OSDN Git Service

enable cube maps on radeon (#2241 on bugzilla). No vtxfmt code yet (just generates...
[android-x86/external-mesa.git] / src / mesa / drivers / dri / radeon / radeon_texmem.c
1 /* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_texmem.c,v 1.7 2002/12/16 16:18:59 dawes Exp $ */
2 /**************************************************************************
3
4 Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
5                      VA Linux Systems Inc., Fremont, California.
6
7 All Rights Reserved.
8
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation on the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial
19 portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR THEIR
25 SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
26 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
27 IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29
30 **************************************************************************/
31
32 /*
33  * Authors:
34  *   Kevin E. Martin <martin@valinux.com>
35  *   Gareth Hughes <gareth@valinux.com>
36  *
37  */
38 #include <errno.h> 
39
40 #include "glheader.h"
41 #include "imports.h"
42 #include "context.h"
43 #include "macros.h"
44
45 #include "radeon_context.h"
46 #include "radeon_ioctl.h"
47 #include "radeon_tex.h"
48
49 #include <unistd.h>  /* for usleep() */
50
51
52 /**
53  * Destroy any device-dependent state associated with the texture.  This may
54  * include NULLing out hardware state that points to the texture.
55  */
56 void
57 radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t )
58 {
59    if ( RADEON_DEBUG & DEBUG_TEXTURE ) {
60       fprintf( stderr, "%s( %p, %p )\n", __FUNCTION__, (void *)t, (void *)t->base.tObj );
61    }
62
63    if ( rmesa != NULL ) {
64       unsigned   i;
65
66
67       for ( i = 0 ; i < rmesa->glCtx->Const.MaxTextureUnits ; i++ ) {
68          if ( t == rmesa->state.texture.unit[i].texobj ) {
69             rmesa->state.texture.unit[i].texobj = NULL;
70          }
71       }
72    }
73 }
74
75
76 /* ------------------------------------------------------------
77  * Texture image conversions
78  */
79
80
81 static void radeonUploadRectSubImage( radeonContextPtr rmesa,
82                                       radeonTexObjPtr t, 
83                                       struct gl_texture_image *texImage,
84                                       GLint x, GLint y, 
85                                       GLint width, GLint height )
86 {
87    const struct gl_texture_format *texFormat = texImage->TexFormat;
88    int blit_format, dstPitch, done;
89
90    switch ( texFormat->TexelBytes ) {
91    case 1:
92       blit_format = RADEON_GMC_DST_8BPP_CI;
93       break;
94    case 2:
95       blit_format = RADEON_GMC_DST_16BPP;
96       break;
97    case 4:
98       blit_format = RADEON_GMC_DST_32BPP;
99       break;
100    default:
101       fprintf( stderr, "radeonUploadRectSubImage: unknown blit_format (texelbytes=%d)\n", 
102                texFormat->TexelBytes);
103       return;
104    }
105
106    t->image[0][0].data = texImage->Data;
107
108    /* Currently don't need to cope with small pitches.
109     */
110    width = texImage->Width;
111    height = texImage->Height;
112    dstPitch = t->pp_txpitch + 32;
113
114    {    /* FIXME: prefer GART-texturing if possible */
115       /* Data not in GART memory, or bad pitch.
116        */
117       for (done = 0; done < height ; ) {
118          struct radeon_dma_region region;
119          int lines = MIN2( height - done, RADEON_BUFFER_SIZE / dstPitch );
120          int src_pitch;
121          char *tex;
122
123          src_pitch = texImage->RowStride * texFormat->TexelBytes;
124
125          tex = (char *)texImage->Data + done * src_pitch;
126
127          memset(&region, 0, sizeof(region));
128          radeonAllocDmaRegion( rmesa, &region, lines * dstPitch, 1024 );
129
130          /* Copy texdata to dma:
131           */
132          if (0)
133             fprintf(stderr, "%s: src_pitch %d dst_pitch %d\n",
134                     __FUNCTION__, src_pitch, dstPitch);
135
136          if (src_pitch == dstPitch) {
137             memcpy( region.address + region.start, tex, lines * src_pitch );
138          } 
139          else {
140             char *buf = region.address + region.start;
141             int i;
142             for (i = 0 ; i < lines ; i++) {
143                memcpy( buf, tex, src_pitch );
144                buf += dstPitch;
145                tex += src_pitch;
146             }
147          }
148
149          radeonEmitWait( rmesa, RADEON_WAIT_3D );
150
151          
152
153          /* Blit to framebuffer
154           */
155          radeonEmitBlit( rmesa,
156                        blit_format,
157                        dstPitch, GET_START( &region ),
158                        dstPitch, t->bufAddr,
159                        0, 0,
160                        0, done,
161                        width, lines );
162          
163          radeonEmitWait( rmesa, RADEON_WAIT_2D );
164
165          radeonReleaseDmaRegion( rmesa, &region, __FUNCTION__ );
166          done += lines;
167       }
168    }
169 }
170
171
172 /**
173  * Upload the texture image associated with texture \a t at the specified
174  * level at the address relative to \a start.
175  */
176 static void uploadSubImage( radeonContextPtr rmesa, radeonTexObjPtr t, 
177                             GLint hwlevel,
178                             GLint x, GLint y, GLint width, GLint height,
179                             GLuint face )
180 {
181    struct gl_texture_image *texImage = NULL;
182    GLuint offset;
183    GLint imageWidth, imageHeight;
184    GLint ret;
185    drm_radeon_texture_t tex;
186    drm_radeon_tex_image_t tmp;
187    const int level = hwlevel + t->base.firstLevel;
188
189    if ( RADEON_DEBUG & DEBUG_TEXTURE ) {
190       fprintf( stderr, "%s( %p, %p ) level/width/height/face = %d/%d/%d/%u\n", 
191                __FUNCTION__, (void *)t, (void *)t->base.tObj, level, width, height, face );
192    }
193
194    ASSERT(face < 6);
195
196    /* Ensure we have a valid texture to upload */
197    if ( ( hwlevel < 0 ) || ( hwlevel >= RADEON_MAX_TEXTURE_LEVELS ) ) {
198       _mesa_problem(NULL, "bad texture level in %s", __FUNCTION__);
199       return;
200    }
201
202    texImage = t->base.tObj->Image[face][level];
203
204    if ( !texImage ) {
205       if ( RADEON_DEBUG & DEBUG_TEXTURE )
206          fprintf( stderr, "%s: texImage %d is NULL!\n", __FUNCTION__, level );
207       return;
208    }
209    if ( !texImage->Data ) {
210       if ( RADEON_DEBUG & DEBUG_TEXTURE )
211          fprintf( stderr, "%s: image data is NULL!\n", __FUNCTION__ );
212       return;
213    }
214
215
216    if (t->base.tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
217       assert(level == 0);
218       assert(hwlevel == 0);
219       if ( RADEON_DEBUG & DEBUG_TEXTURE )
220          fprintf( stderr, "%s: image data is rectangular\n", __FUNCTION__);
221       radeonUploadRectSubImage( rmesa, t, texImage, x, y, width, height );
222       return;
223    }
224
225    imageWidth = texImage->Width;
226    imageHeight = texImage->Height;
227
228    offset = t->bufAddr + t->base.totalSize * face / 6;
229
230    if ( RADEON_DEBUG & (DEBUG_TEXTURE|DEBUG_IOCTL) ) {
231       GLint imageX = 0;
232       GLint imageY = 0;
233       GLint blitX = t->image[face][hwlevel].x;
234       GLint blitY = t->image[face][hwlevel].y;
235       GLint blitWidth = t->image[face][hwlevel].width;
236       GLint blitHeight = t->image[face][hwlevel].height;
237       fprintf( stderr, "   upload image: %d,%d at %d,%d\n",
238                imageWidth, imageHeight, imageX, imageY );
239       fprintf( stderr, "   upload  blit: %d,%d at %d,%d\n",
240                blitWidth, blitHeight, blitX, blitY );
241       fprintf( stderr, "       blit ofs: 0x%07x level: %d/%d\n",
242                (GLuint)offset, hwlevel, level );
243    }
244
245    t->image[face][hwlevel].data = texImage->Data;
246
247    /* Init the DRM_RADEON_TEXTURE command / drm_radeon_texture_t struct.
248     * NOTE: we're always use a 1KB-wide blit and I8 texture format.
249     * We used to use 1, 2 and 4-byte texels and used to use the texture
250     * width to dictate the blit width - but that won't work for compressed
251     * textures. (Brian)
252     * NOTE: can't do that with texture tiling. (sroland)
253     */
254    tex.offset = offset;
255    tex.image = &tmp;
256    /* copy (x,y,width,height,data) */
257    memcpy( &tmp, &t->image[face][hwlevel], sizeof(drm_radeon_tex_image_t) );
258
259    if (texImage->TexFormat->TexelBytes) {
260       /* use multi-byte upload scheme */
261       tex.height = imageHeight;
262       tex.width = imageWidth;
263       tex.format = t->pp_txformat & RADEON_TXFORMAT_FORMAT_MASK;
264       tex.pitch = MAX2((texImage->Width * texImage->TexFormat->TexelBytes) / 64, 1);
265       tex.offset += tmp.x & ~1023;
266       tmp.x = tmp.x % 1024;
267       if (t->tile_bits & RADEON_TXO_MICRO_TILE_X2) {
268          /* need something like "tiled coordinates" ? */
269          tmp.y = tmp.x / (tex.pitch * 128) * 2;
270          tmp.x = tmp.x % (tex.pitch * 128) / 2 / texImage->TexFormat->TexelBytes;
271          tex.pitch |= RADEON_DST_TILE_MICRO >> 22;
272       }
273       else {
274          tmp.x = tmp.x >> (texImage->TexFormat->TexelBytes >> 1);
275       }
276       if ((t->tile_bits & RADEON_TXO_MACRO_TILE) &&
277          (texImage->Width * texImage->TexFormat->TexelBytes >= 256)) {
278          /* radeon switches off macro tiling for small textures/mipmaps it seems */
279          tex.pitch |= RADEON_DST_TILE_MACRO >> 22;
280       }
281    }
282    else {
283       /* In case of for instance 8x8 texture (2x2 dxt blocks), padding after the first two blocks is
284          needed (only with dxt1 since 2 dxt3/dxt5 blocks already use 32 Byte). */
285       /* set tex.height to 1/4 since 1 "macropixel" (dxt-block) has 4 real pixels. Needed
286          so the kernel module reads the right amount of data. */
287       tex.format = RADEON_TXFORMAT_I8; /* any 1-byte texel format */
288       tex.pitch = (BLIT_WIDTH_BYTES / 64);
289       tex.height = (imageHeight + 3) / 4;
290       tex.width = (imageWidth + 3) / 4;
291       switch (t->pp_txformat & RADEON_TXFORMAT_FORMAT_MASK) {
292       case RADEON_TXFORMAT_DXT1:
293          tex.width *= 8;
294          break;
295       case RADEON_TXFORMAT_DXT23:
296       case RADEON_TXFORMAT_DXT45:
297          tex.width *= 16;
298          break;
299       }
300    }
301
302    LOCK_HARDWARE( rmesa );
303    do {
304       ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_TEXTURE,
305                                  &tex, sizeof(drm_radeon_texture_t) );
306    } while ( ret == -EAGAIN );
307
308    UNLOCK_HARDWARE( rmesa );
309
310    if ( ret ) {
311       fprintf( stderr, "DRM_RADEON_TEXTURE: return = %d\n", ret );
312       fprintf( stderr, "   offset=0x%08x\n",
313                offset );
314       fprintf( stderr, "   image width=%d height=%d\n",
315                imageWidth, imageHeight );
316       fprintf( stderr, "    blit width=%d height=%d data=%p\n",
317                t->image[face][hwlevel].width, t->image[face][hwlevel].height,
318                t->image[face][hwlevel].data );
319       exit( 1 );
320    }
321 }
322
323
324 /**
325  * Upload the texture images associated with texture \a t.  This might
326  * require the allocation of texture memory.
327  * 
328  * \param rmesa Context pointer
329  * \param t Texture to be uploaded
330  * \param face Cube map face to be uploaded.  Zero for non-cube maps.
331  */
332
333 int radeonUploadTexImages( radeonContextPtr rmesa, radeonTexObjPtr t, GLuint face )
334 {
335    const int numLevels = t->base.lastLevel - t->base.firstLevel + 1;
336
337    if ( RADEON_DEBUG & (DEBUG_TEXTURE|DEBUG_IOCTL) ) {
338       fprintf( stderr, "%s( %p, %p ) sz=%d lvls=%d-%d\n", __FUNCTION__,
339                (void *)rmesa->glCtx, (void *)t->base.tObj, t->base.totalSize,
340                t->base.firstLevel, t->base.lastLevel );
341    }
342
343    if ( !t || t->base.totalSize == 0 )
344       return 0;
345
346    if (RADEON_DEBUG & DEBUG_SYNC) {
347       fprintf(stderr, "%s: Syncing\n", __FUNCTION__ );
348       radeonFinish( rmesa->glCtx );
349    }
350
351    LOCK_HARDWARE( rmesa );
352
353    if ( t->base.memBlock == NULL ) {
354       int heap;
355
356       heap = driAllocateTexture( rmesa->texture_heaps, rmesa->nr_heaps,
357                                  (driTextureObject *) t );
358       if ( heap == -1 ) {
359          UNLOCK_HARDWARE( rmesa );
360          return -1;
361       }
362
363       /* Set the base offset of the texture image */
364       t->bufAddr = rmesa->radeonScreen->texOffset[heap] 
365            + t->base.memBlock->ofs;
366       t->pp_txoffset = t->bufAddr;
367
368       if (!(t->base.tObj->Image[0][0]->IsClientData)) {
369          /* hope it's safe to add that here... */
370          t->pp_txoffset |= t->tile_bits;
371       }
372
373       /* Mark this texobj as dirty on all units:
374        */
375       t->dirty_state = TEX_ALL;
376    }
377
378
379    /* Let the world know we've used this memory recently.
380     */
381    driUpdateTextureLRU( (driTextureObject *) t );
382    UNLOCK_HARDWARE( rmesa );
383
384
385    /* Upload any images that are new */
386    if (t->base.dirty_images[face]) {
387       int i;
388       for ( i = 0 ; i < numLevels ; i++ ) {
389          if ( (t->base.dirty_images[face] & (1 << (i+t->base.firstLevel))) != 0 ) {
390             uploadSubImage( rmesa, t, i, 0, 0, t->image[face][i].width,
391                             t->image[face][i].height, face );
392          }
393       }
394       t->base.dirty_images[face] = 0;
395    }
396
397    if (RADEON_DEBUG & DEBUG_SYNC) {
398       fprintf(stderr, "%s: Syncing\n", __FUNCTION__ );
399       radeonFinish( rmesa->glCtx );
400    }
401
402    return 0;
403 }