/* $XFree86$ */ /* -*- 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 * Leif Delgass * Jose Fonseca */ #include "mach64_context.h" #include "mach64_state.h" #include "mach64_ioctl.h" #include "mach64_vb.h" #include "mach64_tris.h" #include "mach64_tex.h" #include "context.h" #include "macros.h" #include "simple_list.h" #include "texformat.h" #include "imports.h" /* Destroy hardware state associated with texture `t'. */ void mach64DestroyTexObj( mach64ContextPtr mmesa, mach64TexObjPtr t ) { #if ENABLE_PERF_BOXES /* Bump the performace counter */ if (mmesa) mmesa->c_textureSwaps++; #endif if ( !t ) return; #if 0 if ( t->tObj && t->memBlock && mmesa ) { /* not a placeholder, so release from global LRU if necessary */ int heap = t->heap; drmTextureRegion *list = mmesa->sarea->tex_list[heap]; int log2sz = mmesa->mach64Screen->logTexGranularity[heap]; int start = t->memBlock->ofs >> log2sz; int end = (t->memBlock->ofs + t->memBlock->size - 1) >> log2sz; int i; mmesa->lastTexAge[heap] = ++mmesa->sarea->tex_age[heap]; /* Update the global LRU */ for ( i = start ; i <= end ; i++ ) { /* do we own this block? */ if (list[i].in_use == mmesa->hHWContext) { list[i].in_use = 0; list[i].age = mmesa->lastTexAge[heap]; /* remove_from_list(i) */ list[(GLuint)list[i].next].prev = list[i].prev; list[(GLuint)list[i].prev].next = list[i].next; } } } #endif if ( t->memBlock ) { mmFreeMem( t->memBlock ); t->memBlock = NULL; } if ( t->tObj ) { t->tObj->DriverData = NULL; } if ( t->bound && mmesa ) mmesa->CurrentTexObj[t->bound-1] = NULL; remove_from_list( t ); FREE( t ); } /* Keep track of swapped out texture objects. */ void mach64SwapOutTexObj( mach64ContextPtr mmesa, mach64TexObjPtr t ) { #if ENABLE_PERF_BOXES /* Bump the performace counter */ if (mmesa) mmesa->c_textureSwaps++; #endif #if 0 if ( t->tObj && t->memBlock && mmesa ) { /* not a placeholder, so release from global LRU if necessary */ int heap = t->heap; drmTextureRegion *list = mmesa->sarea->tex_list[heap]; int log2sz = mmesa->mach64Screen->logTexGranularity[heap]; int start = t->memBlock->ofs >> log2sz; int end = (t->memBlock->ofs + t->memBlock->size - 1) >> log2sz; int i; mmesa->lastTexAge[heap] = ++mmesa->sarea->tex_age[heap]; /* Update the global LRU */ for ( i = start ; i <= end ; i++ ) { /* do we own this block? */ if (list[i].in_use == mmesa->hHWContext) { list[i].in_use = 0; list[i].age = mmesa->lastTexAge[heap]; /* remove_from_list(i) */ list[(GLuint)list[i].next].prev = list[i].prev; list[(GLuint)list[i].prev].next = list[i].next; } } } #endif if ( t->memBlock ) { mmFreeMem( t->memBlock ); t->memBlock = NULL; } t->dirty = ~0; move_to_tail( &mmesa->SwappedOut, t ); } /* Print out debugging information about texture LRU. */ void mach64PrintLocalLRU( mach64ContextPtr mmesa, int heap ) { mach64TexObjPtr t; int sz = 1 << (mmesa->mach64Screen->logTexGranularity[heap]); fprintf( stderr, "\nLocal LRU, heap %d:\n", heap ); foreach( t, &mmesa->TexObjList[heap] ) { if ( !t->tObj ) { fprintf( stderr, "Placeholder %d at 0x%x sz 0x%x\n", t->memBlock->ofs / sz, t->memBlock->ofs, t->memBlock->size ); } else { fprintf( stderr, "Texture (bound %d) at 0x%x sz 0x%x\n", t->bound, t->memBlock->ofs, t->memBlock->size ); } } fprintf( stderr, "\n" ); } void mach64PrintGlobalLRU( mach64ContextPtr mmesa, int heap ) { drm_tex_region_t *list = mmesa->sarea->tex_list[heap]; int i, j; fprintf( stderr, "\nGlobal LRU, heap %d list %p:\n", heap, list ); for ( i = 0, j = MACH64_NR_TEX_REGIONS ; i < MACH64_NR_TEX_REGIONS ; i++ ) { fprintf( stderr, "list[%d] age %d in_use %d next %d prev %d\n", j, list[j].age, list[j].in_use, list[j].next, list[j].prev ); j = list[j].next; if ( j == MACH64_NR_TEX_REGIONS ) break; } if ( j != MACH64_NR_TEX_REGIONS ) { fprintf( stderr, "Loop detected in global LRU\n" ); for ( i = 0 ; i < MACH64_NR_TEX_REGIONS ; i++ ) { fprintf( stderr, "list[%d] age %d in_use %d next %d prev %d\n", i, list[i].age, list[i].in_use, list[i].next, list[i].prev ); } } fprintf( stderr, "\n" ); } /* Reset the global texture LRU. */ /* NOTE: This function is only called while holding the hardware lock */ static void mach64ResetGlobalLRU( mach64ContextPtr mmesa, int heap ) { drm_tex_region_t *list = mmesa->sarea->tex_list[heap]; int sz = 1 << mmesa->mach64Screen->logTexGranularity[heap]; int i; /* (Re)initialize the global circular LRU list. The last element in * the array (MACH64_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->mach64Screen->texSize[heap] ; i++ ) { list[i].prev = i-1; list[i].next = i+1; list[i].age = 0; list[i].in_use = 0; } i--; list[0].prev = MACH64_NR_TEX_REGIONS; list[i].prev = i-1; list[i].next = MACH64_NR_TEX_REGIONS; list[MACH64_NR_TEX_REGIONS].prev = i; list[MACH64_NR_TEX_REGIONS].next = 0; mmesa->sarea->tex_age[heap] = 0; } /* Update the local and global texture LRUs. */ /* NOTE: This function is only called while holding the hardware lock */ void mach64UpdateTexLRU( mach64ContextPtr mmesa, mach64TexObjPtr t ) { int heap = t->heap; drm_tex_region_t *list = mmesa->sarea->tex_list[heap]; int log2sz = mmesa->mach64Screen->logTexGranularity[heap]; int start = t->memBlock->ofs >> log2sz; int end = (t->memBlock->ofs + t->memBlock->size - 1) >> log2sz; int i; mmesa->lastTexAge[heap] = ++mmesa->sarea->tex_age[heap]; if ( !t->memBlock ) { fprintf( stderr, "no memblock\n\n" ); return; } /* Update our local LRU */ move_to_head( &mmesa->TexObjList[heap], t ); /* Update the global LRU */ for ( i = start ; i <= end ; i++ ) { list[i].in_use = mmesa->hHWContext; list[i].age = mmesa->lastTexAge[heap]; #if 0 /* if this is the last region, it's not in the list */ if ( !(i*(1< mmesa->mach64Screen->texSize[heap] ) ) { #endif /* remove_from_list(i) */ list[(GLuint)list[i].next].prev = list[i].prev; list[(GLuint)list[i].prev].next = list[i].next; #if 0 } #endif /* insert_at_head(list, i) */ list[i].prev = MACH64_NR_TEX_REGIONS; list[i].next = list[MACH64_NR_TEX_REGIONS].next; list[(GLuint)list[MACH64_NR_TEX_REGIONS].next].prev = i; list[MACH64_NR_TEX_REGIONS].next = i; } if ( MACH64_DEBUG & DEBUG_VERBOSE_LRU ) { mach64PrintGlobalLRU( mmesa, t->heap ); mach64PrintLocalLRU( mmesa, t->heap ); } } /* Update our notion of what textures have been changed since we last * held the lock. This pertains to both our local textures and the * textures belonging to other clients. Keep track of other client's * textures by pushing a placeholder texture onto the LRU list -- these * are denoted by (tObj == NULL). */ /* NOTE: This function is only called while holding the hardware lock */ static void mach64TexturesGone( mach64ContextPtr mmesa, int heap, int offset, int size, int in_use ) { mach64TexObjPtr 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 out. Need to hold onto the currently * bound objects, however. */ if ( t->bound ) { mach64SwapOutTexObj( mmesa, t ); } else { mach64DestroyTexObj( mmesa, t ); } } if ( in_use > 0 && in_use != mmesa->hHWContext ) { t = (mach64TexObjPtr) CALLOC( sizeof(*t) ); if (!t) return; 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; } insert_at_head( &mmesa->TexObjList[heap], t ); } } /* Update our client's shared texture state. If another client has * modified a region in which we have textures, then we need to figure * out which of our textures has been removed, and update our global * LRU. */ void mach64AgeTextures( mach64ContextPtr mmesa, int heap ) { drm_mach64_sarea_t *sarea = mmesa->sarea; if ( sarea->tex_age[heap] != mmesa->lastTexAge[heap] ) { int sz = 1 << mmesa->mach64Screen->logTexGranularity[heap]; int nr = 0; int idx; /* 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->tex_list[heap][MACH64_NR_TEX_REGIONS].prev ; idx != MACH64_NR_TEX_REGIONS && nr < MACH64_NR_TEX_REGIONS ; idx = sarea->tex_list[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. */ if ( idx * sz > mmesa->mach64Screen->texSize[heap] ) { nr = MACH64_NR_TEX_REGIONS; break; } if ( sarea->tex_list[heap][idx].age > mmesa->lastTexAge[heap] ) { mach64TexturesGone( mmesa, heap, idx * sz, sz, sarea->tex_list[heap][idx].in_use ); } } /* If switching texturing schemes, then the SAREA might not * have been properly cleared, so we need to reset the * global texture LRU. */ if ( nr == MACH64_NR_TEX_REGIONS ) { mach64TexturesGone( mmesa, heap, 0, mmesa->mach64Screen->texSize[heap], 0 ); mach64ResetGlobalLRU( mmesa, heap ); } if ( 0 ) { mach64PrintGlobalLRU( mmesa, heap ); mach64PrintLocalLRU( mmesa, heap ); } mmesa->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_TEX0IMAGE | MACH64_UPLOAD_TEX1IMAGE); mmesa->lastTexAge[heap] = sarea->tex_age[heap]; } } /* 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; /* Ensure we have a valid texture to upload */ if ( ( level < 0 ) || ( level > mmesa->glCtx->Const.MaxTextureLevels ) ) return; image = t->tObj->Image[0][level]; if ( !image ) return; switch ( image->TexFormat->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->offset, (GLint)width, dwords ); mmDumpMemInfo( mmesa->texHeap[t->heap] ); } assert(image->Data); { CARD32 *dst = (CARD32 *)((char *)mach64Screen->agpTextures.map + t->memBlock->ofs); const GLubyte *src = (const GLubyte *) image->Data + (y * image->Width + x) * image->TexFormat->TexelBytes; const GLuint bytes = width * height * image->TexFormat->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; /* Ensure we have a valid texture to upload */ if ( ( level < 0 ) || ( level > mmesa->glCtx->Const.MaxTextureLevels ) ) return; image = t->tObj->Image[0][level]; if ( !image ) return; switch ( image->TexFormat->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->offset; #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 ); mmDumpMemInfo( mmesa->texHeap[t->heap] ); } /* 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++ ) { drmBufPtr buffer; CARD32 *dst; height = MIN2(remaining, rows); /* Grab the dma buffer for the texture blit */ buffer = mach64GetBufferLocked( mmesa ); dst = (CARD32 *)((char *)buffer->address + MACH64_HOSTDATA_BLIT_OFFSET); assert(image->Data); { const GLubyte *src = (const GLubyte *) image->Data + (y * image->Width + x) * image->TexFormat->TexelBytes; const GLuint bytes = width * height * image->TexFormat->TexelBytes; memcpy(dst, src, bytes); } mach64FireBlitLocked( mmesa, buffer, 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 ) { GLint heap; if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { fprintf( stderr, "%s( %p, %p )\n", __FUNCTION__, mmesa->glCtx, t ); } assert(t); assert(t->tObj); /* Choose the heap appropriately */ heap = MACH64_CARD_HEAP; if ( !mmesa->mach64Screen->IsPCI && t->size > mmesa->mach64Screen->texSize[heap] ) { heap = MACH64_AGP_HEAP; } /* Do we need to eject LRU texture objects? */ if ( !t->memBlock ) { t->heap = heap; /* Allocate a memory block on a 64-byte boundary */ t->memBlock = mmAllocMem( mmesa->texHeap[heap], t->size, 6, 0 ); /* Try AGP before kicking anything out of local mem */ if ( !mmesa->mach64Screen->IsPCI && !t->memBlock && heap == MACH64_CARD_HEAP ) { t->memBlock = mmAllocMem( mmesa->texHeap[MACH64_AGP_HEAP], t->size, 6, 0 ); if ( t->memBlock ) heap = t->heap = MACH64_AGP_HEAP; } /* Kick out textures until the requested texture fits */ while ( !t->memBlock ) { if ( mmesa->TexObjList[heap].prev->bound ) { fprintf( stderr, "mach64UploadTexImages: ran into bound texture\n" ); return; } if ( mmesa->TexObjList[heap].prev == &mmesa->TexObjList[heap] ) { if ( mmesa->mach64Screen->IsPCI ) { fprintf( stderr, "%s: upload texture failure on " "local texture heaps, sz=%d\n", __FUNCTION__, t->size ); return; } else if ( heap == MACH64_CARD_HEAP ) { heap = t->heap = MACH64_AGP_HEAP; continue; } else { int i; fprintf( stderr, "%s: upload texture failure on " "%sAGP texture heaps, sz=%d\n", __FUNCTION__, mmesa->firstTexHeap == MACH64_CARD_HEAP ? "both local and " : "", t->size ); for ( i = mmesa->firstTexHeap ; i < mmesa->lastTexHeap ; i++ ) { mach64PrintLocalLRU( mmesa, i ); mmDumpMemInfo( mmesa->texHeap[i] ); } exit(-1); return; } } mach64SwapOutTexObj( mmesa, mmesa->TexObjList[heap].prev ); t->memBlock = mmAllocMem( mmesa->texHeap[heap], t->size, 6, 0 ); } /* Set the base offset of the texture image */ t->offset = mmesa->mach64Screen->texOffset[heap] + t->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 */ mach64UpdateTexLRU( mmesa, t ); /* Upload any images that are new */ if ( t->dirty ) { if (t->heap == MACH64_AGP_HEAP) { /* Need to make sure any vertex buffers in the queue complete */ mach64WaitForIdleLocked( mmesa ); mach64UploadAGPSubImage( mmesa, t, t->tObj->BaseLevel, 0, 0, t->tObj->Image[0][t->tObj->BaseLevel]->Width, t->tObj->Image[0][t->tObj->BaseLevel]->Height ); } else { mach64UploadLocalSubImage( mmesa, t, t->tObj->BaseLevel, 0, 0, t->tObj->Image[0][t->tObj->BaseLevel]->Width, t->tObj->Image[0][t->tObj->BaseLevel]->Height ); } mmesa->setup.tex_cntl |= MACH64_TEX_CACHE_FLUSH; } mmesa->dirty |= MACH64_UPLOAD_TEXTURE; t->dirty = 0; } /* 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. * FIXME: This needs to be optimized better. */ void mach64UploadMultiTexImages( mach64ContextPtr mmesa, mach64TexObjPtr t0, mach64TexObjPtr t1 ) { GLint heap; if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { fprintf( stderr, "%s( %p, %p %p )\n", __FUNCTION__, mmesa->glCtx, t0, t1 ); } assert(t0 && t1); assert(t0->tObj && t1->tObj); /* Choose the heap appropriately */ heap = MACH64_CARD_HEAP; if ( !mmesa->mach64Screen->IsPCI && ((t0->size + t1->size) > mmesa->mach64Screen->texSize[heap]) ) { heap = MACH64_AGP_HEAP; } /* Do we need to eject LRU texture objects? */ if ( !t0->memBlock || !t1->memBlock || t0->heap != t1->heap ) { /* FIXME: starting from scratch for now to keep it simple */ if ( t0->memBlock ) { mach64SwapOutTexObj( mmesa, t0 ); } if ( t1->memBlock ) { mach64SwapOutTexObj( mmesa, t1 ); } t0->heap = t1->heap = heap; /* Allocate a memory block on a 64-byte boundary */ t0->memBlock = mmAllocMem( mmesa->texHeap[heap], t0->size, 6, 0 ); if ( t0->memBlock ) { t1->memBlock = mmAllocMem( mmesa->texHeap[heap], t1->size, 6, 0 ); if ( !t1->memBlock ) { mmFreeMem( t0->memBlock ); t0->memBlock = NULL; } } /* Try AGP before kicking anything out of local mem */ if ( (!t0->memBlock || !t1->memBlock) && heap == MACH64_CARD_HEAP ) { t0->memBlock = mmAllocMem( mmesa->texHeap[MACH64_AGP_HEAP], t0->size, 6, 0 ); if ( t0->memBlock ) { t1->memBlock = mmAllocMem( mmesa->texHeap[MACH64_AGP_HEAP], t1->size, 6, 0 ); if ( !t1->memBlock ) { mmFreeMem( t0->memBlock ); t0->memBlock = NULL; } } if ( t0->memBlock && t1->memBlock ) heap = t0->heap = t1->heap = MACH64_AGP_HEAP; } /* Kick out textures until the requested texture fits */ while ( !t0->memBlock || !t1->memBlock ) { if ( mmesa->TexObjList[heap].prev->bound ) { fprintf( stderr, "%s: ran into bound texture\n", __FUNCTION__ ); return; } if ( mmesa->TexObjList[heap].prev == &mmesa->TexObjList[heap] ) { if ( mmesa->mach64Screen->IsPCI ) { fprintf( stderr, "%s: upload texture failure on local " "texture heaps, tex0 sz=%d tex1 sz=%d\n", __FUNCTION__, t0->size, t1->size ); return; } else if ( heap == MACH64_CARD_HEAP ) { /* If only one allocation succeeded, start over again in AGP */ if (t0->memBlock) { mmFreeMem( t0->memBlock ); t0->memBlock = NULL; } if (t1->memBlock) { mmFreeMem( t1->memBlock ); t1->memBlock = NULL; } heap = t0->heap = t1->heap = MACH64_AGP_HEAP; continue; } else { int i; fprintf( stderr, "%s: upload texture failure on %s" "AGP texture heaps, tex0 sz=%d tex1 sz=%d\n", __FUNCTION__, mmesa->firstTexHeap == MACH64_CARD_HEAP ? "both local and " : "", t0->size, t1->size ); for ( i = mmesa->firstTexHeap ; i < mmesa->lastTexHeap ; i++ ) { mach64PrintLocalLRU( mmesa, i ); mmDumpMemInfo( mmesa->texHeap[i] ); } exit(-1); return; } } mach64SwapOutTexObj( mmesa, mmesa->TexObjList[heap].prev ); if (!t0->memBlock) t0->memBlock = mmAllocMem( mmesa->texHeap[heap], t0->size, 6, 0 ); if (!t1->memBlock) t1->memBlock = mmAllocMem( mmesa->texHeap[heap], t1->size, 6, 0 ); } /* Set the base offset of the texture image */ t0->offset = mmesa->mach64Screen->texOffset[heap] + t0->memBlock->ofs; t1->offset = mmesa->mach64Screen->texOffset[heap] + t1->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 */ mach64UpdateTexLRU( mmesa, t0 ); mach64UpdateTexLRU( mmesa, t1 ); /* Upload any images that are new */ if ( t0->dirty ) { if (t0->heap == MACH64_AGP_HEAP) { /* Need to make sure any vertex buffers in the queue complete */ mach64WaitForIdleLocked( mmesa ); mach64UploadAGPSubImage( mmesa, t0, t0->tObj->BaseLevel, 0, 0, t0->tObj->Image[0][t0->tObj->BaseLevel]->Width, t0->tObj->Image[0][t0->tObj->BaseLevel]->Height ); } else { mach64UploadLocalSubImage( mmesa, t0, t0->tObj->BaseLevel, 0, 0, t0->tObj->Image[0][t0->tObj->BaseLevel]->Width, t0->tObj->Image[0][t0->tObj->BaseLevel]->Height ); } mmesa->setup.tex_cntl |= MACH64_TEX_CACHE_FLUSH; } if ( t1->dirty ) { if (t1->heap == MACH64_AGP_HEAP) { /* Need to make sure any vertex buffers in the queue complete */ mach64WaitForIdleLocked( mmesa ); mach64UploadAGPSubImage( mmesa, t1, t1->tObj->BaseLevel, 0, 0, t1->tObj->Image[0][t1->tObj->BaseLevel]->Width, t1->tObj->Image[0][t1->tObj->BaseLevel]->Height ); } else { mach64UploadLocalSubImage( mmesa, t1, t1->tObj->BaseLevel, 0, 0, t1->tObj->Image[0][t1->tObj->BaseLevel]->Width, t1->tObj->Image[0][t1->tObj->BaseLevel]->Height ); } mmesa->setup.tex_cntl |= MACH64_TEX_CACHE_FLUSH; } mmesa->dirty |= MACH64_UPLOAD_TEXTURE; t0->dirty = 0; t1->dirty = 0; }