📄 fxtexman.c
字号:
/* * Mesa 3-D graphics library * Version: 4.0 * * Copyright (C) 1999-2001 Brian Paul 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 * the rights to use, copy, modify, merge, publish, distribute, sublicense, * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL 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: * David Bucciarelli * Brian Paul * Daryll Strauss * Keith Whitwell * Daniel Borca * Hiroshi Morii *//* fxtexman.c - 3Dfx VooDoo texture memory functions */#ifdef HAVE_CONFIG_H#include "conf.h"#endif#if defined(FX)#include "hash.h"#include "fxdrv.h"int texSwaps = 0;static FxU32 texBoundMask;#define FX_2MB_SPLIT 0x200000static struct gl_texture_object *fxTMFindOldestObject(fxMesaContext fxMesa, int tmu);#ifdef TEXSANITYstatic voidfubar(){} /* Sanity Check */static voidsanity(fxMesaContext fxMesa){ MemRange *tmp, *prev, *pos; prev = 0; tmp = fxMesa->tmFree[0]; while (tmp) { if (!tmp->startAddr && !tmp->endAddr) { fprintf(stderr, "Textures fubar\n"); fubar(); } if (tmp->startAddr >= tmp->endAddr) { fprintf(stderr, "Node fubar\n"); fubar(); } if (prev && (prev->startAddr >= tmp->startAddr || prev->endAddr > tmp->startAddr)) { fprintf(stderr, "Sorting fubar\n"); fubar(); } prev = tmp; tmp = tmp->next; } prev = 0; tmp = fxMesa->tmFree[1]; while (tmp) { if (!tmp->startAddr && !tmp->endAddr) { fprintf(stderr, "Textures fubar\n"); fubar(); } if (tmp->startAddr >= tmp->endAddr) { fprintf(stderr, "Node fubar\n"); fubar(); } if (prev && (prev->startAddr >= tmp->startAddr || prev->endAddr > tmp->startAddr)) { fprintf(stderr, "Sorting fubar\n"); fubar(); } prev = tmp; tmp = tmp->next; }}#endifstatic MemRange *fxTMNewRangeNode(fxMesaContext fxMesa, FxU32 start, FxU32 end){ MemRange *result = 0; if (fxMesa->tmPool) { result = fxMesa->tmPool; fxMesa->tmPool = fxMesa->tmPool->next; } else { if (!(result = MALLOC(sizeof(MemRange)))) { fprintf(stderr, "fxTMNewRangeNode: ERROR: out of memory!\n"); fxCloseHardware(); exit(-1); } } result->startAddr = start; result->endAddr = end; return result;}#if 1#define fxTMDeleteRangeNode(fxMesa, range) \ do { \ range->next = fxMesa->tmPool; \ fxMesa->tmPool = range; \ } while (0);#elsestatic voidfxTMDeleteRangeNode(fxMesaContext fxMesa, MemRange * range){ range->next = fxMesa->tmPool; fxMesa->tmPool = range;}#endifstatic voidfxTMUInit(fxMesaContext fxMesa, int tmu){ MemRange *tmn, *last; FxU32 start, end, blockstart, blockend, chunk; start = grTexMinAddress(tmu); end = grTexMaxAddress(tmu); chunk = (fxMesa->type >= GR_SSTTYPE_Banshee) ? (end - start) : FX_2MB_SPLIT; if (fxMesa->verbose) { fprintf(stderr, "Voodoo TMU%d configuration:\n", tmu); } fxMesa->freeTexMem[tmu] = end - start; fxMesa->tmFree[tmu] = NULL; last = 0; blockstart = start; while (blockstart < end) { if (blockstart + chunk > end) blockend = end; else blockend = blockstart + chunk; if (fxMesa->verbose) fprintf(stderr, "Voodoo %08u-%08u\n", (unsigned int) blockstart, (unsigned int) blockend); tmn = fxTMNewRangeNode(fxMesa, blockstart, blockend); tmn->next = NULL; if (last) last->next = tmn; else fxMesa->tmFree[tmu] = tmn; last = tmn; blockstart += chunk; }}static intfxTMFindStartAddr(fxMesaContext fxMesa, GLint tmu, int size){ MemRange *prev, *tmp; int result; struct gl_texture_object *obj; if (fxMesa->HaveTexUma) { tmu = FX_TMU0; } while (1) { prev = 0; tmp = fxMesa->tmFree[tmu]; while (tmp) { if (tmp->endAddr - tmp->startAddr >= size) { /* Fits here */ result = tmp->startAddr; tmp->startAddr += size; if (tmp->startAddr == tmp->endAddr) { /* Empty */ if (prev) { prev->next = tmp->next; } else { fxMesa->tmFree[tmu] = tmp->next; } fxTMDeleteRangeNode(fxMesa, tmp); } fxMesa->freeTexMem[tmu] -= size; return result; } prev = tmp; tmp = tmp->next; } /* No free space. Discard oldest */ if (TDFX_DEBUG & VERBOSE_TEXTURE) { fprintf(stderr, "fxTMFindStartAddr: No free space. Discard oldest\n"); } obj = fxTMFindOldestObject(fxMesa, tmu); if (!obj) { fprintf(stderr, "fxTMFindStartAddr: ERROR: No space for texture\n"); return -1; } fxTMMoveOutTM(fxMesa, obj); texSwaps++; }}int fxTMCheckStartAddr (fxMesaContext fxMesa, GLint tmu, tfxTexInfo *ti){ MemRange *tmp; int size; if (fxMesa->HaveTexUma) { return FXTRUE; } size = grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info)); tmp = fxMesa->tmFree[tmu]; while (tmp) { if (tmp->endAddr - tmp->startAddr >= size) { /* Fits here */ return FXTRUE; } tmp = tmp->next; } return FXFALSE;}static voidfxTMRemoveRange(fxMesaContext fxMesa, GLint tmu, MemRange * range){ MemRange *tmp, *prev; if (fxMesa->HaveTexUma) { tmu = FX_TMU0; } if (range->startAddr == range->endAddr) { fxTMDeleteRangeNode(fxMesa, range); return; } fxMesa->freeTexMem[tmu] += range->endAddr - range->startAddr; prev = 0; tmp = fxMesa->tmFree[tmu]; while (tmp) { if (range->startAddr > tmp->startAddr) { prev = tmp; tmp = tmp->next; } else break; } /* When we create the regions, we make a split at the 2MB boundary. Now we have to make sure we don't join those 2MB boundary regions back together again. */ range->next = tmp; if (tmp) { if (range->endAddr == tmp->startAddr && tmp->startAddr & texBoundMask) { /* Combine */ tmp->startAddr = range->startAddr; fxTMDeleteRangeNode(fxMesa, range); range = tmp; } } if (prev) { if (prev->endAddr == range->startAddr && range->startAddr & texBoundMask) { /* Combine */ prev->endAddr = range->endAddr; prev->next = range->next; fxTMDeleteRangeNode(fxMesa, range); } else prev->next = range; } else { fxMesa->tmFree[tmu] = range; }}static struct gl_texture_object *fxTMFindOldestObject(fxMesaContext fxMesa, int tmu){ GLuint age, old, lasttime, bindnumber; GLfloat lowestPriority; struct gl_texture_object *obj, *lowestPriorityObj; struct _mesa_HashTable *textures = fxMesa->glCtx->Shared->TexObjects; GLuint id; if (!_mesa_HashFirstEntry(textures)) return 0; obj = NULL; old = 0; lowestPriorityObj = NULL; lowestPriority = 1.0F; bindnumber = fxMesa->texBindNumber; for (id = _mesa_HashFirstEntry(textures); id; id = _mesa_HashNextEntry(textures, id)) { struct gl_texture_object *tmp = (struct gl_texture_object *) _mesa_HashLookup(textures, id); tfxTexInfo *info = fxTMGetTexInfo(tmp); if (info && info->isInTM && ((info->whichTMU == tmu) || (info->whichTMU == FX_TMU_BOTH) || (info->whichTMU == FX_TMU_SPLIT) || fxMesa->HaveTexUma ) ) { lasttime = info->lastTimeUsed; if (lasttime > bindnumber) age = bindnumber + (UINT_MAX - lasttime + 1); /* TO DO: check wrap around */ else age = bindnumber - lasttime; if (age >= old) { old = age; obj = tmp; } /* examine priority */ if (tmp->Priority < lowestPriority) { lowestPriority = tmp->Priority; lowestPriorityObj = tmp; } } } if (lowestPriorityObj != NULL) { if (TDFX_DEBUG & VERBOSE_TEXTURE) { fprintf(stderr, "fxTMFindOldestObject: %d pri=%f\n", lowestPriorityObj->Name, lowestPriority); } return lowestPriorityObj; } else { if (TDFX_DEBUG & VERBOSE_TEXTURE) { if (obj != NULL) { fprintf(stderr, "fxTMFindOldestObject: %d age=%d\n", obj->Name, old); } } return obj; }}static MemRange *fxTMAddObj(fxMesaContext fxMesa, struct gl_texture_object *tObj, GLint tmu, int texmemsize){ FxI32 startAddr; MemRange *range; startAddr = fxTMFindStartAddr(fxMesa, tmu, texmemsize); if (startAddr < 0) return 0; range = fxTMNewRangeNode(fxMesa, startAddr, startAddr + texmemsize); return range;}/* External Functions */voidfxTMMoveInTM_NoLock(fxMesaContext fxMesa, struct gl_texture_object *tObj, GLint where){ tfxTexInfo *ti = fxTMGetTexInfo(tObj); int i, l; int texmemsize; if (TDFX_DEBUG & VERBOSE_DRIVER) { fprintf(stderr, "fxTMMoveInTM_NoLock(%d)\n", tObj->Name); } fxMesa->stats.reqTexUpload++; if (!ti->validated) { fprintf(stderr, "fxTMMoveInTM_NoLock: INTERNAL ERROR: not validated\n"); fxCloseHardware(); exit(-1); } if (ti->isInTM) { if (ti->whichTMU == where) return; if (where == FX_TMU_SPLIT || ti->whichTMU == FX_TMU_SPLIT) fxTMMoveOutTM_NoLock(fxMesa, tObj); else { if (ti->whichTMU == FX_TMU_BOTH) return; where = FX_TMU_BOTH; } } if (TDFX_DEBUG & (VERBOSE_DRIVER | VERBOSE_TEXTURE)) { fprintf(stderr, "fxTMMoveInTM_NoLock: downloading %p (%d) in texture memory in %d\n", (void *)tObj, tObj->Name, where); } ti->whichTMU = (FxU32) where; switch (where) { case FX_TMU0: case FX_TMU1: texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -