OSDN Git Service

bring over build fixes from stable branch
[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 #include "simple_list.h"
45
46 #include "radeon_context.h"
47 #include "radeon_ioctl.h"
48 #include "radeon_tex.h"
49
50
51 /**
52  * Destroy any device-dependent state associated with the texture.  This may
53  * include NULLing out hardware state that points to the texture.
54  */
55 void
56 radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t )
57 {
58    if ( RADEON_DEBUG & DEBUG_TEXTURE ) {
59       fprintf( stderr, "%s( %p, %p )\n", __FUNCTION__, (void *)t, (void *)t->base.tObj );
60    }
61
62    if ( rmesa != NULL ) {
63       unsigned   i;
64
65
66       for ( i = 0 ; i < rmesa->glCtx->Const.MaxTextureUnits ; i++ ) {
67          if ( t == rmesa->state.texture.unit[i].texobj ) {
68             rmesa->state.texture.unit[i].texobj = NULL;
69             remove_from_list( &rmesa->hw.tex[i] );
70             make_empty_list( &rmesa->hw.tex[i] );
71          }
72       }
73    }
74 }
75
76
77 /* ------------------------------------------------------------
78  * Texture image conversions
79  */
80
81
82 static void radeonUploadRectSubImage( radeonContextPtr rmesa,
83                                       radeonTexObjPtr t, 
84                                       struct gl_texture_image *texImage,
85                                       GLint x, GLint y, 
86                                       GLint width, GLint height )
87 {
88    const struct gl_texture_format *texFormat = texImage->TexFormat;
89    int blit_format, dstPitch, done;
90
91    switch ( texFormat->TexelBytes ) {
92    case 1:
93       blit_format = RADEON_GMC_DST_8BPP_CI;
94       break;
95    case 2:
96       blit_format = RADEON_GMC_DST_16BPP;
97       break;
98    case 4:
99       blit_format = RADEON_GMC_DST_32BPP;
100       break;
101    default:
102       fprintf( stderr, "radeonUploadRectSubImage: unknown blit_format (texelbytes=%d)\n", 
103                texFormat->TexelBytes);
104       return;
105    }
106
107    t->image[0][0].data = texImage->Data;
108
109    /* Currently don't need to cope with small pitches.
110     */
111    width = texImage->Width;
112    height = texImage->Height;
113    dstPitch = t->pp_txpitch + 32;
114
115    {    /* FIXME: prefer GART-texturing if possible */
116       /* Data not in GART memory, or bad pitch.
117        */
118       for (done = 0; done < height ; ) {
119          struct radeon_dma_region region;
120          int lines = MIN2( height - done, RADEON_BUFFER_SIZE / dstPitch );
121          int src_pitch;
122          char *tex;
123
124          src_pitch = texImage->RowStride * texFormat->TexelBytes;
125
126          tex = (char *)texImage->Data + done * src_pitch;
127
128          memset(&region, 0, sizeof(region));
129          radeonAllocDmaRegion( rmesa, &region, lines * dstPitch, 1024 );
130
131          /* Copy texdata to dma:
132           */
133          if (0)
134             fprintf(stderr, "%s: src_pitch %d dst_pitch %d\n",
135                     __FUNCTION__, src_pitch, dstPitch);
136
137          if (src_pitch == dstPitch) {
138             memcpy( region.address + region.start, tex, lines * src_pitch );
139          } 
140          else {
141             char *buf = region.address + region.start;
142             int i;
143             for (i = 0 ; i < lines ; i++) {
144                memcpy( buf, tex, src_pitch );
145                buf += dstPitch;
146                tex += src_pitch;
147             }
148          }
149
150          radeonEmitWait( rmesa, RADEON_WAIT_3D );
151
152          
153
154          /* Blit to framebuffer
155           */
156          radeonEmitBlit( rmesa, 
157                        blit_format, 
158                        dstPitch, GET_START( &region ),    
159                        dstPitch, t->bufAddr, 
160                        0, 0, 
161                        0, done, 
162                        width, lines );
163          
164          radeonEmitWait( rmesa, RADEON_WAIT_2D );
165
166          radeonReleaseDmaRegion( rmesa, &region, __FUNCTION__ );
167          done += lines;
168       }
169    }
170 }
171
172
173 /**
174  * Upload the texture image associated with texture \a t at the specified
175  * level at the address relative to \a start.
176  */
177 static void uploadSubImage( radeonContextPtr rmesa, radeonTexObjPtr t, 
178                             GLint hwlevel,
179                             GLint x, GLint y, GLint width, GLint height,
180                             GLuint face )
181 {
182    struct gl_texture_image *texImage = NULL;
183    GLuint offset;
184    GLint imageWidth, imageHeight;
185    GLint ret;
186    drm_radeon_texture_t tex;
187    drm_radeon_tex_image_t tmp;
188    const int level = hwlevel + t->base.firstLevel;
189
190    if ( RADEON_DEBUG & DEBUG_TEXTURE ) {
191       fprintf( stderr, "%s( %p, %p ) level/width/height/face = %d/%d/%d/%u\n", 
192                __FUNCTION__, (void *)t, (void *)t->base.tObj, level, width, height, face );
193    }
194
195    ASSERT(face < 6);
196
197    /* Ensure we have a valid texture to upload */
198    if ( ( hwlevel < 0 ) || ( hwlevel >= RADEON_MAX_TEXTURE_LEVELS ) ) {
199       _mesa_problem(NULL, "bad texture level in %s", __FUNCTION__);
200       return;
201    }
202
203    texImage = t->base.tObj->Image[face][level];
204
205    if ( !texImage ) {
206       if ( RADEON_DEBUG & DEBUG_TEXTURE )
207          fprintf( stderr, "%s: texImage %d is NULL!\n", __FUNCTION__, level );
208       return;
209    }
210    if ( !texImage->Data ) {
211       if ( RADEON_DEBUG & DEBUG_TEXTURE )
212          fprintf( stderr, "%s: image data is NULL!\n", __FUNCTION__ );
213       return;
214    }
215
216
217    if (t->base.tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
218       assert(level == 0);
219       assert(hwlevel == 0);
220       if ( RADEON_DEBUG & DEBUG_TEXTURE )
221          fprintf( stderr, "%s: image data is rectangular\n", __FUNCTION__);
222       radeonUploadRectSubImage( rmesa, t, texImage, x, y, width, height );
223       return;
224    }
225
226    imageWidth = texImage->Width;
227    imageHeight = texImage->Height;
228
229    offset = t->bufAddr;
230
231    if ( RADEON_DEBUG & (DEBUG_TEXTURE|DEBUG_IOCTL) ) {
232       GLint imageX = 0;
233       GLint imageY = 0;
234       GLint blitX = t->image[face][hwlevel].x;
235       GLint blitY = t->image[face][hwlevel].y;
236       GLint blitWidth = t->image[face][hwlevel].width;
237       GLint blitHeight = t->image[face][hwlevel].height;
238       fprintf( stderr, "   upload image: %d,%d at %d,%d\n",
239                imageWidth, imageHeight, imageX, imageY );
240       fprintf( stderr, "   upload  blit: %d,%d at %d,%d\n",
241                blitWidth, blitHeight, blitX, blitY );
242       fprintf( stderr, "       blit ofs: 0x%07x level: %d/%d\n",
243                (GLuint)offset, hwlevel, level );
244    }
245
246    t->image[face][hwlevel].data = texImage->Data;
247
248    /* Init the DRM_RADEON_TEXTURE command / drm_radeon_texture_t struct.
249     * NOTE: we're always use a 1KB-wide blit and I8 texture format.
250     * We used to use 1, 2 and 4-byte texels and used to use the texture
251     * width to dictate the blit width - but that won't work for compressed
252     * textures. (Brian)
253     */
254    tex.offset = offset;
255    tex.pitch = BLIT_WIDTH_BYTES / 64;
256    tex.format = RADEON_TXFORMAT_I8; /* any 1-byte texel format */
257    if (texImage->TexFormat->TexelBytes) {
258       tex.width = imageWidth * texImage->TexFormat->TexelBytes; /* in bytes */
259       tex.height = imageHeight;
260    }
261    else {
262       tex.width = imageWidth; /* compressed */
263       tex.height = imageHeight;
264       if (tex.height < 4)
265          tex.height = 4;
266    }
267    tex.image = &tmp;
268
269    /* copy (x,y,width,height,data) */
270    memcpy( &tmp, &t->image[face][hwlevel], sizeof(drm_radeon_tex_image_t) );
271
272    LOCK_HARDWARE( rmesa );
273    do {
274       ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_TEXTURE,
275                                  &tex, sizeof(drm_radeon_texture_t) );
276    } while ( ret && errno == EAGAIN );
277
278    UNLOCK_HARDWARE( rmesa );
279
280    if ( ret ) {
281       fprintf( stderr, "DRM_RADEON_TEXTURE: return = %d\n", ret );
282       fprintf( stderr, "   offset=0x%08x\n",
283                offset );
284       fprintf( stderr, "   image width=%d height=%d\n",
285                imageWidth, imageHeight );
286       fprintf( stderr, "    blit width=%d height=%d data=%p\n",
287                t->image[face][hwlevel].width, t->image[face][hwlevel].height,
288                t->image[face][hwlevel].data );
289       exit( 1 );
290    }
291 }
292
293
294 /**
295  * Upload the texture images associated with texture \a t.  This might
296  * require the allocation of texture memory.
297  * 
298  * \param rmesa Context pointer
299  * \param t Texture to be uploaded
300  * \param face Cube map face to be uploaded.  Zero for non-cube maps.
301  */
302
303 int radeonUploadTexImages( radeonContextPtr rmesa, radeonTexObjPtr t, GLuint face )
304 {
305    const int numLevels = t->base.lastLevel - t->base.firstLevel + 1;
306
307    if ( RADEON_DEBUG & (DEBUG_TEXTURE|DEBUG_IOCTL) ) {
308       fprintf( stderr, "%s( %p, %p ) sz=%d lvls=%d-%d\n", __FUNCTION__,
309                (void *)rmesa->glCtx, (void *)t->base.tObj, t->base.totalSize,
310                t->base.firstLevel, t->base.lastLevel );
311    }
312
313    if ( !t || t->base.totalSize == 0 )
314       return 0;
315
316    LOCK_HARDWARE( rmesa );
317
318    if ( t->base.memBlock == NULL ) {
319       int heap;
320
321       heap = driAllocateTexture( rmesa->texture_heaps, rmesa->nr_heaps,
322                                  (driTextureObject *) t );
323       if ( heap == -1 ) {
324          UNLOCK_HARDWARE( rmesa );
325          return -1;
326       }
327
328       /* Set the base offset of the texture image */
329       t->bufAddr = rmesa->radeonScreen->texOffset[heap] 
330            + t->base.memBlock->ofs;
331       t->pp_txoffset = t->bufAddr;
332
333
334       /* Mark this texobj as dirty on all units:
335        */
336       t->dirty_state = TEX_ALL;
337    }
338
339
340    /* Let the world know we've used this memory recently.
341     */
342    driUpdateTextureLRU( (driTextureObject *) t );
343    UNLOCK_HARDWARE( rmesa );
344
345
346    /* Upload any images that are new */
347    if (t->base.dirty_images[face]) {
348       int i;
349       for ( i = 0 ; i < numLevels ; i++ ) {
350          if ( (t->base.dirty_images[face] & (1 << (i+t->base.firstLevel))) != 0 ) {
351             uploadSubImage( rmesa, t, i, 0, 0, t->image[face][i].width,
352                             t->image[face][i].height, face );
353          }
354       }
355       t->base.dirty_images[face] = 0;
356    }
357
358    return 0;
359 }