From 5df82c82bd53db90eb72c5aad4dd20cf6f1116b1 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Fri, 22 Aug 2003 20:11:43 +0000 Subject: patch to import Jon Smirl's work from Bitkeeper --- src/mesa/drivers/dri/mga/mgatexmem.c | 616 ++++++++++------------------------- 1 file changed, 167 insertions(+), 449 deletions(-) (limited to 'src/mesa/drivers/dri/mga/mgatexmem.c') diff --git a/src/mesa/drivers/dri/mga/mgatexmem.c b/src/mesa/drivers/dri/mga/mgatexmem.c index 7dbdbc582f..4e7fd6b24b 100644 --- a/src/mesa/drivers/dri/mga/mgatexmem.c +++ b/src/mesa/drivers/dri/mga/mgatexmem.c @@ -26,539 +26,257 @@ */ /* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgatexmem.c,v 1.7 2002/10/30 12:51:36 alanh Exp $ */ -#include -#include -#include +#include "glheader.h" #include "mm.h" #include "mgacontext.h" #include "mgatex.h" #include "mgaregs.h" #include "mgaioctl.h" +#include "mga_xmesa.h" -/*#include "mem.h" */ +#include "imports.h" #include "simple_list.h" -static void -mgaSwapOutTexObj(mgaContextPtr mmesa, mgaTextureObjectPtr t) -{ - if (t->MemBlock) { - mmFreeMem(t->MemBlock); - t->MemBlock = 0; - - if (t->age > mmesa->dirtyAge) - mmesa->dirtyAge = t->age; - } - - t->dirty_images = ~0; - move_to_tail(&(mmesa->SwappedOut), t); -} - -static void -mgaPrintLocalLRU( mgaContextPtr mmesa, int heap ) -{ - mgaTextureObjectPtr t; - int sz = 1 << (mmesa->mgaScreen->logTextureGranularity[heap]); - - fprintf(stderr, "\nLocal LRU, heap %d:\n", heap); - - foreach( t, &(mmesa->TexObjList[heap]) ) { - if (!t->tObj) - fprintf(stderr, "Placeholder %d at %x sz %x\n", - t->MemBlock->ofs / sz, - t->MemBlock->ofs, - t->MemBlock->size); - else - fprintf(stderr, "Texture (bound %d) at %x sz %x\n", - t->bound, - t->MemBlock->ofs, - t->MemBlock->size); - } - - fprintf(stderr, "\n\n"); -} - -static void -mgaPrintGlobalLRU( mgaContextPtr mmesa, int heap ) +/** + * Destroy any device-dependent state associated with the texture. This may + * include NULLing out hardware state that points to the texture. + */ +void +mgaDestroyTexObj( mgaContextPtr mmesa, mgaTextureObjectPtr t ) { - int i, j; - drmTextureRegion *list = mmesa->sarea->texList[heap]; + unsigned i; - fprintf(stderr, "\nGlobal LRU, heap %d list %p:\n", heap, list); - for (i = 0, j = MGA_NR_TEX_REGIONS ; i < MGA_NR_TEX_REGIONS ; i++) { - fprintf(stderr, "list[%d] age %d next %d prev %d\n", - j, list[j].age, list[j].next, list[j].prev); - j = list[j].next; - if (j == MGA_NR_TEX_REGIONS) break; - } + /* See if it was the driver's current object. + */ - if (j != MGA_NR_TEX_REGIONS) { - fprintf(stderr, "Loop detected in global LRU\n\n\n"); - for (i = 0 ; i < MGA_NR_TEX_REGIONS ; i++) { - fprintf(stderr, "list[%d] age %d next %d prev %d\n", - i, list[i].age, list[i].next, list[i].prev); - } - } + if ( mmesa != NULL ) + { + if ( t->age > mmesa->dirtyAge ) + mmesa->dirtyAge = t->age; - fprintf(stderr, "\n\n"); + for ( i = 0 ; i < mmesa->glCtx->Const.MaxTextureUnits ; i++ ) + { + if ( t == mmesa->CurrentTexObj[ i ] ) { + mmesa->CurrentTexObj[ i ] = NULL; + } + } + } } -static void mgaResetGlobalLRU( mgaContextPtr mmesa, GLuint heap ) +/** + * Upload a texture image from system memory to either on-card or AGP + * memory. Uploads to on-card memory are performed using an ILOAD operation. + * This is used for both initial loading of the entire image, and texSubImage + * updates. + * + * Performed with the hardware lock held. + * + * Even though this function is named "upload subimage," the entire image + * is uploaded. + * + * \param mmesa Driver context. + * \param t Texture to be uploaded. + * \param hwlevel Mipmap level of the texture to be uploaded. + * + * \bug As mentioned above, this fuction actually copies the entier mipmap + * level. There should be a version of this function that performs + * sub-rectangle uploads. This will perform quite a bit better if only + * a small portion of a larger texture has been updated. Care would + * need to be take with such an implementation once glCopyTexImage has + * been hardware accelerated. + */ +static void mgaUploadSubImage( mgaContextPtr mmesa, + mgaTextureObjectPtr t, GLint hwlevel ) { - drmTextureRegion *list = mmesa->sarea->texList[heap]; - int sz = 1 << mmesa->mgaScreen->logTextureGranularity[heap]; - int i; - - mmesa->texAge[heap] = ++mmesa->sarea->texAge[heap]; + struct gl_texture_image * texImage; + unsigned offset; + unsigned texelBytes; + unsigned length; + const int level = hwlevel + t->base.firstLevel; - if (0) fprintf(stderr, "mgaResetGlobalLRU %d\n", (int)heap); - /* (Re)initialize the global circular LRU list. The last element - * in the array (MGA_NR_TEX_REGIONS) is the sentinal. Keeping it - * at the end of the array allows it to be addressed rationally - * when looking up objects at a particular location in texture - * memory. - */ - for (i = 0 ; (i+1) * sz <= mmesa->mgaScreen->textureSize[heap] ; i++) { - list[i].prev = i-1; - list[i].next = i+1; - list[i].age = mmesa->sarea->texAge[heap]; + if ( (hwlevel < 0) + || (hwlevel >= (MGA_IS_G200(mmesa) + ? G200_TEX_MAXLEVELS : G400_TEX_MAXLEVELS)) ) { + fprintf( stderr, "[%s:%d] level = %d\n", __FILE__, __LINE__, level ); + return; } - i--; - list[0].prev = MGA_NR_TEX_REGIONS; - list[i].prev = i-1; - list[i].next = MGA_NR_TEX_REGIONS; - list[MGA_NR_TEX_REGIONS].prev = i; - list[MGA_NR_TEX_REGIONS].next = 0; - -} - - -static void mgaUpdateTexLRU( mgaContextPtr mmesa, mgaTextureObjectPtr t ) -{ - int i; - int heap = t->heap; - int logsz = mmesa->mgaScreen->logTextureGranularity[heap]; - int start = t->MemBlock->ofs >> logsz; - int end = (t->MemBlock->ofs + t->MemBlock->size - 1) >> logsz; - drmTextureRegion *list = mmesa->sarea->texList[heap]; - - mmesa->texAge[heap] = ++mmesa->sarea->texAge[heap]; - - if (!t->MemBlock) { - fprintf(stderr, "no memblock\n\n"); + texImage = t->base.tObj->Image[level]; + if ( texImage == NULL ) { + fprintf( stderr, "[%s:%d] Image[%d] = NULL\n", __FILE__, __LINE__, + level ); return; } - /* Update our local LRU - */ - move_to_head( &(mmesa->TexObjList[heap]), t ); - - - if (0) - fprintf(stderr, "mgaUpdateTexLRU heap %d list %p\n", heap, list); - - /* Update the global LRU - */ - for (i = start ; i <= end ; i++) { - - list[i].in_use = 1; - list[i].age = mmesa->texAge[heap]; - - /* remove_from_list(i) - */ - list[(unsigned)list[i].next].prev = list[i].prev; - list[(unsigned)list[i].prev].next = list[i].next; - - /* insert_at_head(list, i) - */ - list[i].prev = MGA_NR_TEX_REGIONS; - list[i].next = list[MGA_NR_TEX_REGIONS].next; - list[(unsigned)list[MGA_NR_TEX_REGIONS].next].prev = i; - list[MGA_NR_TEX_REGIONS].next = i; - } - - if (0) { - mgaPrintGlobalLRU(mmesa, t->heap); - mgaPrintLocalLRU(mmesa, t->heap); + if (texImage->Data == NULL) { + fprintf(stderr, "null texture image data tObj %p level %d\n", + t->base.tObj, level); + return; } -} - -/* Called for every shared texture region which has increased in age - * since we last held the lock. - * - * Figures out which of our textures have been ejected by other clients, - * and pushes a placeholder texture onto the LRU list to represent - * the other client's textures. - */ -static void mgaTexturesGone( mgaContextPtr mmesa, - GLuint heap, - GLuint offset, - GLuint size, - GLuint in_use ) -{ - mgaTextureObjectPtr t, tmp; - - - foreach_s ( t, tmp, &(mmesa->TexObjList[heap]) ) { - if (t->MemBlock->ofs >= offset + size || - t->MemBlock->ofs + t->MemBlock->size <= offset) - continue; - - - - - /* It overlaps - kick it off. Need to hold onto the currently bound - * objects, however. - */ - if (t->bound) - mgaSwapOutTexObj( mmesa, t ); - else - mgaDestroyTexObj( mmesa, t ); + /* find the proper destination offset for this level */ + if ( MGA_IS_G200(mmesa) ) { + offset = (t->base.memBlock->ofs + t->offsets[hwlevel]); } + else { + unsigned i; - - if (in_use) { - t = (mgaTextureObjectPtr) calloc(1, sizeof(*t)); - if (!t) return; - - t->heap = heap; - t->MemBlock = mmAllocMem( mmesa->texHeap[heap], size, 0, offset); - if (!t->MemBlock) { - fprintf(stderr, "Couldn't alloc placeholder sz %x ofs %x\n", - (int)size, (int)offset); - mmDumpMemInfo( mmesa->texHeap[heap]); - return; + offset = t->base.memBlock->ofs; + for ( i = 0 ; i < hwlevel ; i++ ) { + offset += (t->offsets[1] >> (i * 2)); } - insert_at_head( &(mmesa->TexObjList[heap]), t ); - } -} - - -void mgaAgeTextures( mgaContextPtr mmesa, int heap ) -{ - MGASAREAPrivPtr sarea = mmesa->sarea; - int sz = 1 << (mmesa->mgaScreen->logTextureGranularity[heap]); - int idx, nr = 0; - /* Have to go right round from the back to ensure stuff ends up - * LRU in our local list... Fix with a cursor pointer. - */ - for (idx = sarea->texList[heap][MGA_NR_TEX_REGIONS].prev ; - idx != MGA_NR_TEX_REGIONS && nr < MGA_NR_TEX_REGIONS ; - idx = sarea->texList[heap][idx].prev, nr++) - { - /* If switching texturing schemes, then the SAREA might not - * have been properly cleared, so we need to reset the - * global texture LRU. + /* Each mipmap must be DWORD aligned. */ - if ( idx * sz > mmesa->mgaScreen->textureSize[heap] ) { - nr = MGA_NR_TEX_REGIONS; - break; - } - - if (sarea->texList[heap][idx].age > mmesa->texAge[heap]) { - mgaTexturesGone(mmesa, heap, idx * sz, sz, - sarea->texList[heap][idx].in_use); - } - } - - if (nr == MGA_NR_TEX_REGIONS) { - mgaTexturesGone(mmesa, heap, 0, - mmesa->mgaScreen->textureSize[heap], 0); - mgaResetGlobalLRU( mmesa, heap ); + offset &= ~0x03; } - if (0) { - mgaPrintGlobalLRU( mmesa, heap ); - mgaPrintLocalLRU( mmesa, heap ); - } - - mmesa->texAge[heap] = sarea->texAge[heap]; - mmesa->dirty |= MGA_UPLOAD_TEX0IMAGE | MGA_UPLOAD_TEX1IMAGE; -} - -/* - * mgaUploadSubImageLocked - * - * Perform an iload based update of a resident buffer. This is used for - * both initial loading of the entire image, and texSubImage updates. - * - * Performed with the hardware lock held. - */ -void mgaUploadSubImageLocked( mgaContextPtr mmesa, - mgaTextureObjectPtr t, - int level, - int x, int y, int width, int height ) -{ - int x2; - int dwords; - int offset; - struct gl_texture_image *image; - int texelBytes, texelsPerDword, texelMaccess, length; - - if ( level < 0 || level >= MGA_TEX_MAXLEVELS ) - return; + /* Copy the texture from system memory to a memory space that can be + * directly used by the hardware for texturing. + */ - image = t->tObj->Image[level]; - if ( !image ) return; + texelBytes = texImage->TexFormat->TexelBytes; + length = texImage->Width * texImage->Height * texelBytes; + if ( t->base.heap->heapId == MGA_CARD_HEAP ) { + unsigned tex_offset = 0; + unsigned to_copy; - if (image->Data == 0) { - fprintf(stderr, "null texture image data tObj %p level %d\n", - t->tObj, level); - return; - } + /* We may not be able to upload the entire texture in one batch due to + * register limits or dma buffer limits. Split the copy up into maximum + * sized chunks. + */ + offset += mmesa->mgaScreen->textureOffset[ t->base.heap->heapId ]; + while ( length != 0 ) { + mgaGetILoadBufferLocked( mmesa ); - /* find the proper destination offset for this level */ - offset = (t->MemBlock->ofs + - t->offsets[level]); - - - texelBytes = t->texelBytes; - switch( texelBytes ) { - case 1: - texelsPerDword = 4; - texelMaccess = 0; - break; - case 2: - texelsPerDword = 2; - texelMaccess = 1; - break; - case 4: - texelsPerDword = 1; - texelMaccess = 2; - break; - default: - return; - } + /* The kernel ILOAD ioctl requires that the lenght be an even multiple + * of MGA_ILOAD_ALIGN. + */ + length = ((length) + MGA_ILOAD_MASK) & ~MGA_ILOAD_MASK; + to_copy = MIN2( length, MGA_BUFFER_SIZE ); + (void) memcpy( mmesa->iload_buffer->address, + (GLubyte *) texImage->Data + tex_offset, to_copy ); - /* We can't do a subimage update if pitch is < 32 texels due - * to hardware XY addressing limits, so we will need to - * linearly upload all modified rows. - */ - if ( image->Width < 32 ) { - x = 0; - width = image->Width * height; - height = 1; - - /* Assume that 1x1 textures aren't going to cause a - * bus error if we read up to four texels from that - * location: - */ -/* if ( width < texelsPerDword ) { */ -/* width = texelsPerDword; */ -/* } */ - } else { - /* pad the size out to dwords. The image is a pointer - to the entire image, so we can safely reference - outside the x,y,width,height bounds if we need to */ - x2 = x + width; - x2 = (x2 + (texelsPerDword-1)) & ~(texelsPerDword-1); - x = (x + (texelsPerDword-1)) & ~(texelsPerDword-1); - width = x2 - x; - } + if ( MGA_DEBUG & DEBUG_VERBOSE_TEXTURE ) + fprintf(stderr, "[%s:%d] address/size = 0x%08lx/%d\n", + __FILE__, __LINE__, + (long) (offset + tex_offset), + to_copy ); - /* we may not be able to upload the entire texture in one - batch due to register limits or dma buffer limits. - Recursively split it up. */ - while ( 1 ) { - dwords = height * width / texelsPerDword; - if ( dwords * 4 <= MGA_BUFFER_SIZE ) { - break; + mgaFireILoadLocked( mmesa, offset + tex_offset, to_copy ); + tex_offset += to_copy; + length -= to_copy; } - - mgaUploadSubImageLocked( mmesa, t, level, x, y, - width, height >> 1 ); - y += ( height >> 1 ); - height -= ( height >> 1 ); - } - - length = dwords * 4; - - /* Fill in the secondary buffer with properly converted texels - * from the mesa buffer. */ - /* FIXME: the sync for direct copy reduces speed.. */ - if(t->heap == MGA_CARD_HEAP ) { - mgaGetILoadBufferLocked( mmesa ); - mgaConvertTexture( (GLuint *)mmesa->iload_buffer->address, - texelBytes, image, x, y, width, height ); - if(length < 64) length = 64; - - if (0) - fprintf(stderr, "TexelBytes : %d, offset: %d, length : %d\n", - texelBytes, - mmesa->mgaScreen->textureOffset[t->heap] + - offset + - y * width * 4/texelsPerDword, - length); - - mgaFireILoadLocked( mmesa, - mmesa->mgaScreen->textureOffset[t->heap] + - offset + - y * width * 4/texelsPerDword, - length); } else { + /* FIXME: the sync for direct copy reduces speed.. */ /* This works, is slower for uploads to card space and needs * additional synchronization with the dma stream. */ UPDATE_LOCK(mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT); - mgaConvertTexture( (GLuint *) - (mmesa->mgaScreen->texVirtual[t->heap] + - offset + - y * width * 4/texelsPerDword), - texelBytes, image, x, y, width, height ); - } -} - - -static void mgaUploadTexLevel( mgaContextPtr mmesa, - mgaTextureObjectPtr t, - int l ) -{ - mgaUploadSubImageLocked( mmesa, - t, - l, - 0, 0, - t->tObj->Image[l]->Width, - t->tObj->Image[l]->Height); -} - - - - -#if 0 -static void mgaMigrateTexture( mgaContextPtr mmesa, mgaTextureObjectPtr t ) -{ - /* NOT DONE */ -} -#endif - - -static int mgaChooseTexHeap( mgaContextPtr mmesa, mgaTextureObjectPtr t ) -{ - int freeagp, freecard; - int fitincard, fitinagp; - int totalcard, totalagp; - TMemBlock *b; - - totalcard = totalagp = fitincard = fitinagp = freeagp = freecard = 0; - - b = mmesa->texHeap[0]; - while(b) - { - totalcard += b->size; - if(b->free) if(t->totalSize <= b->size)fitincard = 1; - b = b->next; - } - - b = mmesa->texHeap[1]; - while(b) - { - totalagp += b->size; - if(b->free) if(t->totalSize <= b->size)fitinagp = 1; - b = b->next; - } - if(fitincard)return 0; - if(fitinagp)return 1; + memcpy( mmesa->mgaScreen->texVirtual[t->base.heap->heapId] + offset, + texImage->Data, length ); - if(totalcard && totalagp) - { - int ages; - int ratio = (totalcard > totalagp) ? totalcard / totalagp : totalagp / totalcard; - ages = mmesa->sarea->texAge[0] + mmesa->sarea->texAge[1]; - if( (ages % ratio) == 0)return totalcard > totalagp ? 1 : 0; - else return totalcard > totalagp ? 0 : 1; + if ( MGA_DEBUG & DEBUG_VERBOSE_TEXTURE ) + fprintf(stderr, "[%s:%d] address/size = 0x%08lx/%d\n", + __FILE__, __LINE__, + (long) (mmesa->mgaScreen->texVirtual[t->base.heap->heapId] + + offset), + length); } - - if(totalagp) return 1; - return 0; } +/** + * Upload the texture images associated with texture \a t. This might + * require the allocation of texture memory. + * + * \param mmesa Context pointer + * \param t Texture to be uploaded + */ + int mgaUploadTexImages( mgaContextPtr mmesa, mgaTextureObjectPtr t ) { - int heap; int i; int ofs; - heap = t->heap = mgaChooseTexHeap( mmesa, t ); - /* Do we need to eject LRU texture objects? - */ - if (!t->MemBlock) { - while (1) - { - mgaTextureObjectPtr tmp = mmesa->TexObjList[heap].prev; - - t->MemBlock = mmAllocMem( mmesa->texHeap[heap], - t->totalSize, - 6, 0 ); - if (t->MemBlock) - break; - - if (mmesa->TexObjList[heap].prev->bound) { - fprintf(stderr, "Hit bound texture in upload\n"); - return -1; - } + if ( (t == NULL) || (t->base.totalSize == 0) ) + return 0; - if (mmesa->TexObjList[heap].prev == - &(mmesa->TexObjList[heap])) - { - fprintf(stderr, "Failed to upload texture, sz %d\n", t->totalSize); - mmDumpMemInfo( mmesa->texHeap[heap] ); - return -1; - } + LOCK_HARDWARE( mmesa ); - mgaDestroyTexObj( mmesa, tmp ); + if (t->base.memBlock == NULL ) { + int heap; + + heap = driAllocateTexture( mmesa->texture_heaps, mmesa->nr_heaps, + (driTextureObject *) t ); + if ( heap == -1 ) { + UNLOCK_HARDWARE( mmesa ); + return -1; } - ofs = t->MemBlock->ofs - + mmesa->mgaScreen->textureOffset[heap] - ; + ofs = mmesa->mgaScreen->textureOffset[ heap ] + + t->base.memBlock->ofs; - t->setup.texorg = ofs; - t->setup.texorg1 = ofs + t->offsets[1]; - t->setup.texorg2 = ofs + t->offsets[2]; - t->setup.texorg3 = ofs + t->offsets[3]; - t->setup.texorg4 = ofs + t->offsets[4]; + if ( MGA_IS_G200(mmesa) ) { + t->setup.texorg = ofs; + t->setup.texorg1 = ofs + t->offsets[1]; + t->setup.texorg2 = ofs + t->offsets[2]; + t->setup.texorg3 = ofs + t->offsets[3]; + t->setup.texorg4 = ofs + t->offsets[4]; + } + else { + t->setup.texorg = ofs | TO_texorgoffsetsel; + t->setup.texorg1 = t->offsets[1]; + t->setup.texorg2 = 0; + t->setup.texorg3 = 0; + t->setup.texorg4 = 0; + } mmesa->dirty |= MGA_UPLOAD_CONTEXT; } /* Let the world know we've used this memory recently. */ - mgaUpdateTexLRU( mmesa, t ); - + driUpdateTextureLRU( (driTextureObject *) t ); - if (MGA_DEBUG&DEBUG_VERBOSE_LRU) - fprintf(stderr, "dispatch age: %d age freed memory: %d\n", + if (MGA_DEBUG&DEBUG_VERBOSE_TEXTURE) + fprintf(stderr, "[%s:%d] dispatch age: %d age freed memory: %d\n", + __FILE__, __LINE__, GET_DISPATCH_AGE(mmesa), mmesa->dirtyAge); if (mmesa->dirtyAge >= GET_DISPATCH_AGE(mmesa)) mgaWaitAgeLocked( mmesa, mmesa->dirtyAge ); - if (t->dirty_images) { - if (MGA_DEBUG&DEBUG_VERBOSE_LRU) - fprintf(stderr, "*"); + if (t->base.dirty_images[0]) { + const int numLevels = t->base.lastLevel - t->base.firstLevel + 1; - for (i = 0 ; i <= t->lastLevel ; i++) - if (t->dirty_images & (1<base.dirty_images[0] ); + + for (i = 0 ; i < numLevels ; i++) { + if ( (t->base.dirty_images[0] & (1U << i)) != 0 ) { + mgaUploadSubImage( mmesa, t, i ); + } + } + t->base.dirty_images[0] = 0; } - t->dirty_images = 0; + UNLOCK_HARDWARE( mmesa ); + return 0; } -- cgit v1.2.3