1 /**************************************************************************
3 Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
30 * Gareth Hughes <gareth@valinux.com>
31 * Kevin E. Martin <martin@valinux.com>
32 * Brian Paul <brianp@valinux.com>
35 #include "r128_context.h"
36 #include "r128_ioctl.h"
39 #include "main/macros.h"
40 #include "main/simple_list.h"
41 #include "main/imports.h"
47 /* Destroy hardware state associated with texture `t'.
49 void r128DestroyTexObj( r128ContextPtr rmesa, r128TexObjPtr t )
54 /* See if it was the driver's current object.
59 for ( i = 0 ; i < rmesa->glCtx->Const.MaxTextureUnits ; i++ )
61 if ( t == rmesa->CurrentTexObj[ i ] ) {
62 assert( t->base.bound & (1 << i) );
63 rmesa->CurrentTexObj[ i ] = NULL;
71 * Upload the texture image associated with texture \a t at the specified
72 * level at the address relative to \a start.
74 static void uploadSubImage( r128ContextPtr rmesa, r128TexObjPtr t,
76 GLint x, GLint y, GLint width, GLint height )
78 struct gl_texture_image *image;
79 int texelsPerDword = 0;
80 int imageWidth, imageHeight;
83 uint32_t pitch, offset;
86 /* Ensure we have a valid texture to upload */
87 if ( ( level < 0 ) || ( level > R128_MAX_TEXTURE_LEVELS ) )
90 image = t->base.tObj->Image[0][level];
94 switch ( _mesa_get_format_bytes(image->TexFormat) ) {
95 case 1: texelsPerDword = 4; break;
96 case 2: texelsPerDword = 2; break;
97 case 4: texelsPerDword = 1; break;
101 /* FIXME: The subimage index calcs are wrong... */
104 width = image->Width;
105 height = image->Height;
108 imageWidth = image->Width;
109 imageHeight = image->Height;
111 format = t->textureFormat >> 16;
113 /* The texel upload routines have a minimum width, so force the size
116 if ( imageWidth < texelsPerDword ) {
119 factor = texelsPerDword / imageWidth;
120 imageWidth = texelsPerDword;
121 imageHeight /= factor;
122 if ( imageHeight == 0 ) {
123 /* In this case, the texel converter will actually walk a
124 * texel or two off the end of the image, but normal malloc
125 * alignment should prevent it from ever causing a fault.
131 /* We can't upload to a pitch less than 8 texels so we will need to
132 * linearly upload all modified rows for textures smaller than this.
133 * This makes the x/y/width/height different for the blitter and the
136 if ( imageWidth >= 8 ) {
137 /* The texture walker and the blitter look identical */
138 pitch = imageWidth >> 3;
144 start = (y * imageWidth) & ~7;
145 end = (y + height) * imageWidth;
147 if ( end - start < 8 ) {
148 /* Handle the case where the total number of texels
156 /* Upload some number of full 8 texel blit rows */
157 factor = 8 / imageWidth;
168 /* Fixed pitch of 8 */
172 dwords = width * height / texelsPerDword;
173 offset = t->bufAddr + t->image[level - t->base.firstLevel].offset;
175 #if ENABLE_PERF_BOXES
176 /* Bump the performace counter */
177 rmesa->c_textureBytes += (dwords << 2);
180 if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
181 fprintf( stderr, "r128UploadSubImage: %d,%d of %d,%d at %d,%d\n",
182 width, height, image->Width, image->Height, x, y );
183 fprintf( stderr, " blit ofs: 0x%07x pitch: 0x%x dwords: %d "
184 "level: %d format: %x\n",
185 (GLuint)offset, (GLuint)pitch, dwords, level, format );
188 /* Subdivide the texture if required */
189 if ( dwords <= R128_BUFFER_MAX_DWORDS / 2 ) {
192 rows = (R128_BUFFER_MAX_DWORDS * texelsPerDword) / (2 * width);
195 for ( i = 0, remaining = height ;
197 remaining -= rows, y += rows, i++ )
204 height = MIN2(remaining, rows);
206 /* Grab the indirect buffer for the texture blit */
207 LOCK_HARDWARE( rmesa );
208 buffer = r128GetBufferLocked( rmesa );
210 dst = (uint32_t *)((char *)buffer->address + R128_HOSTDATA_BLIT_OFFSET);
212 /* Copy the next chunck of the texture image into the blit buffer */
214 const GLuint texelBytes =
215 _mesa_get_format_bytes(image->TexFormat);
216 const GLubyte *src = (const GLubyte *) image->Data +
217 (y * image->Width + x) * texelBytes;
218 const GLuint bytes = width * height * texelBytes;
219 memcpy(dst, src, bytes);
222 r128FireBlitLocked( rmesa, buffer,
223 offset, pitch, format,
224 x, y, width, height );
225 UNLOCK_HARDWARE( rmesa );
228 rmesa->new_state |= R128_NEW_CONTEXT;
229 rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS;
233 /* Upload the texture images associated with texture `t'. This might
234 * require removing our own and/or other client's texture objects to
235 * make room for these images.
237 void r128UploadTexImages( r128ContextPtr rmesa, r128TexObjPtr t )
239 const GLint numLevels = t->base.lastLevel - t->base.firstLevel + 1;
242 if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
243 fprintf( stderr, "%s( %p, %p )\n",
244 __FUNCTION__, (void *) rmesa->glCtx, (void *) t );
249 LOCK_HARDWARE( rmesa );
251 if ( !t->base.memBlock ) {
255 heap = driAllocateTexture( rmesa->texture_heaps, rmesa->nr_heaps,
256 (driTextureObject *) t );
258 UNLOCK_HARDWARE( rmesa );
262 /* Set the base offset of the texture image */
263 assert(t->base.memBlock);
264 t->bufAddr = rmesa->r128Screen->texOffset[heap]
265 + t->base.memBlock->ofs;
267 /* Set texture offsets for each mipmap level */
268 if ( t->setup.tex_cntl & R128_MIP_MAP_DISABLE ) {
269 for ( i = 0 ; i < R128_MAX_TEXTURE_LEVELS ; i++ ) {
270 t->setup.tex_offset[i] = t->bufAddr;
273 for ( i = 0; i < numLevels; i++ ) {
274 const int j = numLevels - i - 1;
275 t->setup.tex_offset[j] = t->bufAddr + t->image[i].offset;
280 /* Let the world know we've used this memory recently.
282 driUpdateTextureLRU( (driTextureObject *) t );
283 UNLOCK_HARDWARE( rmesa );
285 /* Upload any images that are new */
286 if ( t->base.dirty_images[0] ) {
287 for ( i = 0 ; i < numLevels; i++ ) {
288 const GLint j = t->base.firstLevel + i; /* the texObj's level */
289 if ( t->base.dirty_images[0] & (1 << j) ) {
290 uploadSubImage( rmesa, t, j, 0, 0,
291 t->image[i].width, t->image[i].height );
295 rmesa->setup.tex_cntl_c |= R128_TEX_CACHE_FLUSH;
296 rmesa->dirty |= R128_UPLOAD_CONTEXT;
297 t->base.dirty_images[0] = 0;