diff options
Diffstat (limited to 'src/mesa/drivers/dri/mach64/mach64_texmem.c')
-rw-r--r-- | src/mesa/drivers/dri/mach64/mach64_texmem.c | 511 |
1 files changed, 511 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/mach64/mach64_texmem.c b/src/mesa/drivers/dri/mach64/mach64_texmem.c new file mode 100644 index 0000000000..b09954ce23 --- /dev/null +++ b/src/mesa/drivers/dri/mach64/mach64_texmem.c @@ -0,0 +1,511 @@ +/* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc., + * Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Leif Delgass <ldelgass@retinalburn.net> + * Jose Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#include "main/context.h" +#include "main/macros.h" +#include "main/simple_list.h" +#include "main/imports.h" + +#include "mach64_context.h" +#include "mach64_ioctl.h" +#include "mach64_tex.h" + + +/* Destroy hardware state associated with texture `t'. + */ +void mach64DestroyTexObj( mach64ContextPtr mmesa, mach64TexObjPtr t ) +{ + unsigned i; + + /* See if it was the driver's current object. + */ + if ( mmesa != NULL ) + { + for ( i = 0 ; i < mmesa->glCtx->Const.MaxTextureUnits ; i++ ) + { + if ( t == mmesa->CurrentTexObj[ i ] ) { + assert( t->base.bound & (1 << i) ); + mmesa->CurrentTexObj[ i ] = NULL; + } + } + } +} + +/* Upload the texture image associated with texture `t' at level `level' + * at the address relative to `start'. + */ +static void mach64UploadAGPSubImage( mach64ContextPtr mmesa, + mach64TexObjPtr t, int level, + int x, int y, int width, int height ) +{ + mach64ScreenRec *mach64Screen = mmesa->mach64Screen; + struct gl_texture_image *image; + int texelsPerDword = 0; + int dwords; + GLuint texelBytes; + + /* Ensure we have a valid texture to upload */ + if ( ( level < 0 ) || ( level > mmesa->glCtx->Const.MaxTextureLevels ) ) + return; + + image = t->base.tObj->Image[0][level]; + if ( !image ) + return; + + texelBytes = _mesa_get_format_bytes(image->TexFormat); + + switch ( texelBytes ) { + case 1: texelsPerDword = 4; break; + case 2: texelsPerDword = 2; break; + case 4: texelsPerDword = 1; break; + } + +#if 1 + /* FIXME: The subimage index calcs are wrong... */ + x = 0; + y = 0; + width = image->Width; + height = image->Height; +#endif + + dwords = width * height / texelsPerDword; + +#if ENABLE_PERF_BOXES + /* Bump the performance counter */ + mmesa->c_agpTextureBytes += (dwords << 2); +#endif + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "mach64UploadSubImage: %d,%d of %d,%d at %d,%d\n", + width, height, image->Width, image->Height, x, y ); + fprintf( stderr, " blit ofs: 0x%07x pitch: 0x%x dwords: %d\n", + (GLuint)t->bufAddr, (GLint)width, dwords ); + } + + assert(image->Data); + + { + CARD32 *dst = (CARD32 *)((char *)mach64Screen->agpTextures.map + t->base.memBlock->ofs); + const GLubyte *src = (const GLubyte *) image->Data + + (y * image->Width + x) * texelBytes; + const GLuint bytes = width * height * texelBytes; + memcpy(dst, src, bytes); + } + +} + +/* Upload the texture image associated with texture `t' at level `level' + * at the address relative to `start'. + */ +static void mach64UploadLocalSubImage( mach64ContextPtr mmesa, + mach64TexObjPtr t, int level, + int x, int y, int width, int height ) +{ + struct gl_texture_image *image; + int texelsPerDword = 0; + int imageWidth, imageHeight; + int remaining, rows; + int format, dwords; + const int maxdwords = (MACH64_BUFFER_MAX_DWORDS - (MACH64_HOSTDATA_BLIT_OFFSET / 4)); + CARD32 pitch, offset; + int i; + GLuint texelBytes; + + /* Ensure we have a valid texture to upload */ + if ( ( level < 0 ) || ( level > mmesa->glCtx->Const.MaxTextureLevels ) ) + return; + + image = t->base.tObj->Image[0][level]; + if ( !image ) + return; + + texelBytes = _mesa_get_format_bytes(image->TexFormat); + + switch ( texelBytes ) { + case 1: texelsPerDword = 4; break; + case 2: texelsPerDword = 2; break; + case 4: texelsPerDword = 1; break; + } + +#if 1 + /* FIXME: The subimage index calcs are wrong... */ + x = 0; + y = 0; + width = image->Width; + height = image->Height; +#endif + + imageWidth = image->Width; + imageHeight = image->Height; + + format = t->textureFormat; + + /* The texel upload routines have a minimum width, so force the size + * if needed. + */ + if ( imageWidth < texelsPerDword ) { + int factor; + + factor = texelsPerDword / imageWidth; + imageWidth = texelsPerDword; + imageHeight /= factor; + if ( imageHeight == 0 ) { + /* In this case, the texel converter will actually walk a + * texel or two off the end of the image, but normal malloc + * alignment should prevent it from ever causing a fault. + */ + imageHeight = 1; + } + } + + /* We can't upload to a pitch less than 64 texels so we will need to + * linearly upload all modified rows for textures smaller than this. + * This makes the x/y/width/height different for the blitter and the + * texture walker. + */ + if ( imageWidth >= 64 ) { + /* The texture walker and the blitter look identical */ + pitch = imageWidth >> 3; + } else { + int factor; + int y2; + int start, end; + + start = (y * imageWidth) & ~63; + end = (y + height) * imageWidth; + + if ( end - start < 64 ) { + /* Handle the case where the total number of texels + * uploaded is < 64. + */ + x = 0; + y = start / 64; + width = end - start; + height = 1; + } else { + /* Upload some number of full 64 texel blit rows */ + factor = 64 / imageWidth; + + y2 = y + height - 1; + y /= factor; + y2 /= factor; + + x = 0; + width = 64; + height = y2 - y + 1; + } + + /* Fixed pitch of 64 */ + pitch = 8; + } + + dwords = width * height / texelsPerDword; + offset = t->bufAddr; + +#if ENABLE_PERF_BOXES + /* Bump the performance counter */ + mmesa->c_textureBytes += (dwords << 2); +#endif + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "mach64UploadSubImage: %d,%d of %d,%d at %d,%d\n", + width, height, image->Width, image->Height, x, y ); + fprintf( stderr, " blit ofs: 0x%07x pitch: 0x%x dwords: %d\n", + (GLuint)offset, (GLint)width, dwords ); + } + + /* Subdivide the texture if required (account for the registers added by the drm) */ + if ( dwords <= maxdwords ) { + rows = height; + } else { + rows = (maxdwords * texelsPerDword) / (2 * width); + } + + for ( i = 0, remaining = height ; + remaining > 0 ; + remaining -= rows, y += rows, i++ ) + { + height = MIN2(remaining, rows); + + assert(image->Data); + + { + const GLubyte *src = (const GLubyte *) image->Data + + (y * image->Width + x) * texelBytes; + + mach64FireBlitLocked( mmesa, (void *)src, offset, pitch, format, + x, y, width, height ); + } + + } + + mmesa->new_state |= MACH64_NEW_CONTEXT; + mmesa->dirty |= MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC; +} + + +/* Upload the texture images associated with texture `t'. This might + * require removing our own and/or other client's texture objects to + * make room for these images. + */ +void mach64UploadTexImages( mach64ContextPtr mmesa, mach64TexObjPtr t ) +{ + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p, %p )\n", + __FUNCTION__, mmesa->glCtx, t ); + } + + assert(t); + assert(t->base.tObj); + + if ( !t->base.memBlock ) { + int heap; + + /* NULL heaps are skipped */ + heap = driAllocateTexture( mmesa->texture_heaps, MACH64_NR_TEX_HEAPS, + (driTextureObject *) t ); + + if ( heap == -1 ) { + fprintf( stderr, "%s: upload texture failure, sz=%d\n", __FUNCTION__, + t->base.totalSize ); + exit(-1); + return; + } + + t->heap = heap; + + /* Set the base offset of the texture image */ + assert(t->base.memBlock); + t->bufAddr = mmesa->mach64Screen->texOffset[heap] + t->base.memBlock->ofs; + + /* Force loading the new state into the hardware */ + mmesa->dirty |= (MACH64_UPLOAD_SCALE_3D_CNTL | + MACH64_UPLOAD_TEXTURE); + } + + /* Let the world know we've used this memory recently */ + driUpdateTextureLRU( (driTextureObject *) t ); + + /* Upload any images that are new */ + if ( t->base.dirty_images[0] ) { + const GLint j = t->base.tObj->BaseLevel; + if (t->heap == MACH64_AGP_HEAP) { + /* Need to make sure any vertex buffers in the queue complete */ + mach64WaitForIdleLocked( mmesa ); + mach64UploadAGPSubImage( mmesa, t, j, 0, 0, + t->base.tObj->Image[0][j]->Width, + t->base.tObj->Image[0][j]->Height ); + } else { + mach64UploadLocalSubImage( mmesa, t, j, 0, 0, + t->base.tObj->Image[0][j]->Width, + t->base.tObj->Image[0][j]->Height ); + } + + mmesa->setup.tex_cntl |= MACH64_TEX_CACHE_FLUSH; + t->base.dirty_images[0] = 0; + } + + mmesa->dirty |= MACH64_UPLOAD_TEXTURE; +} + + +/* Allocate memory from the same texture heap `heap' for both textures + * `u0' and `u1'. + */ +static int mach64AllocateMultiTex( mach64ContextPtr mmesa, + mach64TexObjPtr u0, + mach64TexObjPtr u1, + int heap, GLboolean alloc_u0 ) +{ + /* Both objects should be bound */ + assert( u0->base.bound && u1->base.bound ); + + if ( alloc_u0 ) { + /* Evict u0 from its current heap */ + if ( u0->base.memBlock ) { + assert( u0->heap != heap ); + driSwapOutTextureObject( (driTextureObject *) u0 ); + } + + /* Try to allocate u0 in the chosen heap */ + u0->heap = driAllocateTexture( &mmesa->texture_heaps[heap], 1, + (driTextureObject *) u0 ); + + if ( u0->heap == -1 ) { + return -1; + } + } + + /* Evict u1 from its current heap */ + if ( u1->base.memBlock ) { + assert( u1->heap != heap ); + driSwapOutTextureObject( (driTextureObject *) u1 ); + } + + /* Try to allocate u1 in the same heap as u0 */ + u1->heap = driAllocateTexture( &mmesa->texture_heaps[heap], 1, + (driTextureObject *) u1 ); + + if ( u1->heap == -1 ) { + return -1; + } + + /* Bound objects are not evicted */ + assert( u0->base.memBlock && u1->base.memBlock ); + assert( u0->heap == u1->heap ); + + return heap; +} + +/* The mach64 needs to have both primary and secondary textures in either + * local or AGP memory, so we need a "buddy system" to make sure that allocation + * succeeds or fails for both textures. + */ +void mach64UploadMultiTexImages( mach64ContextPtr mmesa, + mach64TexObjPtr t0, + mach64TexObjPtr t1 ) +{ + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p, %p %p )\n", + __FUNCTION__, mmesa->glCtx, t0, t1 ); + } + + assert(t0 && t1); + assert(t0->base.tObj && t1->base.tObj); + + if ( !t0->base.memBlock || !t1->base.memBlock || t0->heap != t1->heap ) { + mach64TexObjPtr u0 = NULL; + mach64TexObjPtr u1 = NULL; + unsigned totalSize = t0->base.totalSize + t1->base.totalSize; + + int heap, ret; + + /* Check if one of the textures is already swapped in a heap and the + * other texture fits in that heap. + */ + if ( t0->base.memBlock && totalSize <= t0->base.heap->size ) { + u0 = t0; + u1 = t1; + } else if ( t1->base.memBlock && totalSize <= t1->base.heap->size ) { + u0 = t1; + u1 = t0; + } + + if ( u0 ) { + heap = u0->heap; + + ret = mach64AllocateMultiTex( mmesa, u0, u1, heap, GL_FALSE ); + } else { + /* Both textures are swapped out or collocation is impossible */ + u0 = t0; + u1 = t1; + + /* Choose the heap appropriately */ + heap = MACH64_CARD_HEAP; + + if ( totalSize > mmesa->texture_heaps[heap]->size ) { + heap = MACH64_AGP_HEAP; + } + + ret = mach64AllocateMultiTex( mmesa, u0, u1, heap, GL_TRUE ); + } + + if ( ret == -1 && heap == MACH64_CARD_HEAP ) { + /* Try AGP if local memory failed */ + heap = MACH64_AGP_HEAP; + + ret = mach64AllocateMultiTex( mmesa, u0, u1, heap, GL_TRUE ); + } + + if ( ret == -1 ) { + /* FIXME: + * Swap out all textures from the AGP heap and re-run allocation, this + * should succeed in all cases. + */ + fprintf( stderr, "%s: upload multi-texture failure, sz0=%d sz1=%d\n", + __FUNCTION__, t0->base.totalSize, t1->base.totalSize ); + exit(-1); + } + + /* Set the base offset of the texture image */ + assert(t0->base.memBlock); + t0->bufAddr = mmesa->mach64Screen->texOffset[heap] + t0->base.memBlock->ofs; + assert(t1->base.memBlock); + t1->bufAddr = mmesa->mach64Screen->texOffset[heap] + t1->base.memBlock->ofs; + + /* Force loading the new state into the hardware */ + mmesa->dirty |= (MACH64_UPLOAD_SCALE_3D_CNTL | + MACH64_UPLOAD_TEXTURE); + } + + /* Let the world know we've used this memory recently */ + driUpdateTextureLRU( (driTextureObject *) t0 ); + driUpdateTextureLRU( (driTextureObject *) t1 ); + + /* Upload any images that are new */ + if ( t0->base.dirty_images[0] ) { + const GLint j0 = t0->base.tObj->BaseLevel; + if (t0->heap == MACH64_AGP_HEAP) { + /* Need to make sure any vertex buffers in the queue complete */ + mach64WaitForIdleLocked( mmesa ); + mach64UploadAGPSubImage( mmesa, t0, j0, 0, 0, + t0->base.tObj->Image[0][j0]->Width, + t0->base.tObj->Image[0][j0]->Height ); + } else { + mach64UploadLocalSubImage( mmesa, t0, j0, 0, 0, + t0->base.tObj->Image[0][j0]->Width, + t0->base.tObj->Image[0][j0]->Height ); + } + mmesa->setup.tex_cntl |= MACH64_TEX_CACHE_FLUSH; + t0->base.dirty_images[0] = 0; + } + if ( t1->base.dirty_images[0] ) { + const GLint j1 = t1->base.tObj->BaseLevel; + if (t1->heap == MACH64_AGP_HEAP) { + /* Need to make sure any vertex buffers in the queue complete */ + mach64WaitForIdleLocked( mmesa ); + mach64UploadAGPSubImage( mmesa, t1, j1, 0, 0, + t1->base.tObj->Image[0][j1]->Width, + t1->base.tObj->Image[0][j1]->Height ); + } else { + mach64UploadLocalSubImage( mmesa, t1, j1, 0, 0, + t1->base.tObj->Image[0][j1]->Width, + t1->base.tObj->Image[0][j1]->Height ); + } + + mmesa->setup.tex_cntl |= MACH64_TEX_CACHE_FLUSH; + t1->base.dirty_images[0] = 0; + } + + mmesa->dirty |= MACH64_UPLOAD_TEXTURE; +} |