📄 tdfx_texman.c
字号:
const int numTMUs = fxMesa->haveTwoTMUs ? 2 : 1; int tmu; tdfxMemRange *tmp, *next; /* Deallocate the pool of free tdfxMemRange nodes */ tmp = shared->tmPool; while (tmp) { next = tmp->next; FREE(tmp); tmp = next; } /* Delete the texture memory block tdfxMemRange nodes */ for (tmu = 0; tmu < numTMUs; tmu++) { tmp = shared->tmFree[tmu]; while (tmp) { next = tmp->next; FREE(tmp); tmp = next; } } FREE(shared); fxMesa->glCtx->Shared->DriverData = NULL; }}/* * Delete a tdfxMemRange struct. * We keep a linked list of free/available tdfxMemRange structs to * avoid extra malloc/free calls. */#if 0static voidDeleteRangeNode_NoLock(struct TdfxSharedState *shared, tdfxMemRange *range){ /* insert at head of list */ range->next = shared->tmPool; shared->tmPool = range;}#endif#define DELETE_RANGE_NODE(shared, range) \ (range)->next = (shared)->tmPool; \ (shared)->tmPool = (range)/* * When we've run out of texture memory we have to throw out an * existing texture to make room for the new one. This function * determins the texture to throw out. */static struct gl_texture_object *FindOldestObject(tdfxContextPtr fxMesa, FxU32 tmu){ const GLuint bindnumber = fxMesa->texBindNumber; struct gl_texture_object *oldestObj, *lowestPriorityObj; GLfloat lowestPriority; GLuint oldestAge; GLuint id; struct _mesa_HashTable *textures = fxMesa->glCtx->Shared->TexObjects; oldestObj = NULL; oldestAge = 0; lowestPriority = 1.0F; lowestPriorityObj = NULL; for (id = _mesa_HashFirstEntry(textures); id; id = _mesa_HashNextEntry(textures, id)) { struct gl_texture_object *obj = _mesa_lookup_texture(fxMesa->glCtx, id); tdfxTexInfo *info = TDFX_TEXTURE_DATA(obj); if (info && info->isInTM && ((info->whichTMU == tmu) || (info->whichTMU == TDFX_TMU_BOTH) || (info->whichTMU == TDFX_TMU_SPLIT))) { GLuint age, lasttime; assert(info->tm[0]); lasttime = info->lastTimeUsed; if (lasttime > bindnumber) age = bindnumber + (UINT_MAX - lasttime + 1); /* TO DO: check wrap around */ else age = bindnumber - lasttime; if (age >= oldestAge) { oldestAge = age; oldestObj = obj; } /* examine priority */ if (obj->Priority < lowestPriority) { lowestPriority = obj->Priority; lowestPriorityObj = obj; } } } if (lowestPriority < 1.0) { ASSERT(lowestPriorityObj); /* printf("discard %d pri=%f\n", lowestPriorityObj->Name, lowestPriority); */ return lowestPriorityObj; } else { /* printf("discard %d age=%d\n", oldestObj->Name, oldestAge); */ return oldestObj; }}#if 0static voidFlushTexMemory(tdfxContextPtr fxMesa){ struct _mesa_HashTable *textures = fxMesa->glCtx->Shared->TexObjects; GLuint id; for (id = _mesa_HashFirstEntry(textures); id; id = _mesa_HashNextEntry(textures, id)) { struct gl_texture_object *obj = _mesa_lookup_texture(fxMesa->glCtx, id); if (obj->RefCount < 2) { /* don't flush currently bound textures */ tdfxTMMoveOutTM_NoLock(fxMesa, obj); } }}#endif/* * Find the address (offset?) at which we can store a new texture. * <tmu> is the texture unit. * <size> is the texture size in bytes. */static FxU32FindStartAddr(tdfxContextPtr fxMesa, FxU32 tmu, FxU32 size){ struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared; struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData; tdfxMemRange *prev, *block; FxU32 result;#if 0 int discardedCount = 0;#define MAX_DISCARDS 10#endif if (shared->umaTexMemory) { assert(tmu == TDFX_TMU0); } _glthread_LOCK_MUTEX(mesaShared->Mutex); while (1) { prev = NULL; block = shared->tmFree[tmu]; while (block) { if (block->endAddr - block->startAddr >= size) { /* The texture will fit here */ result = block->startAddr; block->startAddr += size; if (block->startAddr == block->endAddr) { /* Remove this node since it's empty */ if (prev) { prev->next = block->next; } else { shared->tmFree[tmu] = block->next; } DELETE_RANGE_NODE(shared, block); } shared->freeTexMem[tmu] -= size; _glthread_UNLOCK_MUTEX(mesaShared->Mutex); return result; } prev = block; block = block->next; } /* We failed to find a block large enough to accomodate <size> bytes. * Find the oldest texObject and free it. */#if 0 discardedCount++; if (discardedCount > MAX_DISCARDS + 1) { _mesa_problem(NULL, "%s: extreme texmem fragmentation", __FUNCTION__); _glthread_UNLOCK_MUTEX(mesaShared->Mutex); return BAD_ADDRESS; } else if (discardedCount > MAX_DISCARDS) { /* texture memory is probably really fragmented, flush it */ FlushTexMemory(fxMesa); } else#endif { struct gl_texture_object *obj = FindOldestObject(fxMesa, tmu); if (obj) { tdfxTMMoveOutTM_NoLock(fxMesa, obj); fxMesa->stats.texSwaps++; } else { _mesa_problem(NULL, "%s: extreme texmem fragmentation", __FUNCTION__); _glthread_UNLOCK_MUTEX(mesaShared->Mutex); return BAD_ADDRESS; } } } /* never get here, but play it safe */ _glthread_UNLOCK_MUTEX(mesaShared->Mutex); return BAD_ADDRESS;}/* * Remove the given tdfxMemRange node from hardware texture memory. */static voidRemoveRange_NoLock(tdfxContextPtr fxMesa, FxU32 tmu, tdfxMemRange *range){ struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared; struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData; tdfxMemRange *block, *prev; if (shared->umaTexMemory) { assert(tmu == TDFX_TMU0); } if (!range) return; if (range->startAddr == range->endAddr) { DELETE_RANGE_NODE(shared, range); return; } shared->freeTexMem[tmu] += range->endAddr - range->startAddr; /* find position in linked list to insert this tdfxMemRange node */ prev = NULL; block = shared->tmFree[tmu]; while (block) { assert(range->startAddr != block->startAddr); if (range->startAddr > block->startAddr) { prev = block; block = block->next; } else { break; } } /* Insert the free block, combine with adjacent blocks when possible */ range->next = block; if (block) { if (range->endAddr == block->startAddr) { /* Combine */ block->startAddr = range->startAddr; DELETE_RANGE_NODE(shared, range); range = block; } } if (prev) { if (prev->endAddr == range->startAddr) { /* Combine */ prev->endAddr = range->endAddr; prev->next = range->next; DELETE_RANGE_NODE(shared, range); } else { prev->next = range; } } else { shared->tmFree[tmu] = range; }}#if 0 /* NOT USED */static voidRemoveRange(tdfxContextPtr fxMesa, FxU32 tmu, tdfxMemRange *range){ struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared; _glthread_LOCK_MUTEX(mesaShared->Mutex); RemoveRange_NoLock(fxMesa, tmu, range); _glthread_UNLOCK_MUTEX(mesaShared->Mutex);}#endif/* * Allocate space for a texture image. * <tmu> is the texture unit * <texmemsize> is the number of bytes to allocate */static tdfxMemRange *AllocTexMem(tdfxContextPtr fxMesa, FxU32 tmu, FxU32 texmemsize){ FxU32 startAddr; startAddr = FindStartAddr(fxMesa, tmu, texmemsize); if (startAddr == BAD_ADDRESS) { _mesa_problem(fxMesa->glCtx, "%s returned NULL! tmu=%d texmemsize=%d", __FUNCTION__, (int) tmu, (int) texmemsize); return NULL; } else { tdfxMemRange *range; range = NewRangeNode(fxMesa, startAddr, startAddr + texmemsize); return range; }}/* * Download (copy) the given texture data (all mipmap levels) into the * Voodoo's texture memory. * The texture memory must have already been allocated. */voidtdfxTMDownloadTexture(tdfxContextPtr fxMesa, struct gl_texture_object *tObj){ tdfxTexInfo *ti;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -