blob: 940c8fd0b97d92c9d065b6b8753ae2a61a0193aa [file] [log] [blame]
/*
* 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 0x200000
static struct gl_texture_object *fxTMFindOldestObject(fxMesaContext fxMesa,
int tmu);
#ifdef TEXSANITY
static void
fubar()
{
}
/* Sanity Check */
static void
sanity(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;
}
}
#endif
static 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);
#else
static void
fxTMDeleteRangeNode(fxMesaContext fxMesa, MemRange * range)
{
range->next = fxMesa->tmPool;
fxMesa->tmPool = range;
}
#endif
static void
fxTMUInit(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 int
fxTMFindStartAddr(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 void
fxTMRemoveRange(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 */
void
fxTMMoveInTM_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));
ti->tm[where] = fxTMAddObj(fxMesa, tObj, where, texmemsize);
fxMesa->stats.memTexUpload += texmemsize;
for (i = FX_largeLodValue(ti->info), l = ti->minLevel;
i <= FX_smallLodValue(ti->info); i++, l++) {
struct gl_texture_image *texImage = tObj->Image[0][l];
grTexDownloadMipMapLevel(where,
ti->tm[where]->startAddr,
FX_valueToLod(i),
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_BOTH,
texImage->Data);
}
break;
case FX_TMU_SPLIT:
texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD, &(ti->info));
ti->tm[FX_TMU0] = fxTMAddObj(fxMesa, tObj, FX_TMU0, texmemsize);
fxMesa->stats.memTexUpload += texmemsize;
texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN, &(ti->info));
ti->tm[FX_TMU1] = fxTMAddObj(fxMesa, tObj, FX_TMU1, texmemsize);
fxMesa->stats.memTexUpload += texmemsize;
for (i = FX_largeLodValue(ti->info), l = ti->minLevel;
i <= FX_smallLodValue(ti->info); i++, l++) {
struct gl_texture_image *texImage = tObj->Image[0][l];
grTexDownloadMipMapLevel(GR_TMU0,
ti->tm[FX_TMU0]->startAddr,
FX_valueToLod(i),
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_ODD,
texImage->Data);
grTexDownloadMipMapLevel(GR_TMU1,
ti->tm[FX_TMU1]->startAddr,
FX_valueToLod(i),
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_EVEN,
texImage->Data);
}
break;
case FX_TMU_BOTH:
texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
ti->tm[FX_TMU0] = fxTMAddObj(fxMesa, tObj, FX_TMU0, texmemsize);
fxMesa->stats.memTexUpload += texmemsize;
/*texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));*/
ti->tm[FX_TMU1] = fxTMAddObj(fxMesa, tObj, FX_TMU1, texmemsize);
fxMesa->stats.memTexUpload += texmemsize;
for (i = FX_largeLodValue(ti->info), l = ti->minLevel;
i <= FX_smallLodValue(ti->info); i++, l++) {
struct gl_texture_image *texImage = tObj->Image[0][l];
grTexDownloadMipMapLevel(GR_TMU0,
ti->tm[FX_TMU0]->startAddr,
FX_valueToLod(i),
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_BOTH,
texImage->Data);
grTexDownloadMipMapLevel(GR_TMU1,
ti->tm[FX_TMU1]->startAddr,
FX_valueToLod(i),
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_BOTH,
texImage->Data);
}
break;
default:
fprintf(stderr, "fxTMMoveInTM_NoLock: INTERNAL ERROR: wrong tmu (%d)\n", where);
fxCloseHardware();
exit(-1);
}
fxMesa->stats.texUpload++;
ti->isInTM = GL_TRUE;
}
void
fxTMMoveInTM(fxMesaContext fxMesa, struct gl_texture_object *tObj,
GLint where)
{
BEGIN_BOARD_LOCK();
fxTMMoveInTM_NoLock(fxMesa, tObj, where);
END_BOARD_LOCK();
}
void
fxTMReloadMipMapLevel(fxMesaContext fxMesa, struct gl_texture_object *tObj,
GLint level)
{
tfxTexInfo *ti = fxTMGetTexInfo(tObj);
GrLOD_t lodlevel;
GLint tmu;
struct gl_texture_image *texImage = tObj->Image[0][level];
tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
if (TDFX_DEBUG & VERBOSE_TEXTURE) {
fprintf(stderr, "fxTMReloadMipMapLevel(%p (%d), %d)\n", (void *)tObj, tObj->Name, level);
}
assert(mml);
assert(mml->width > 0);
assert(mml->height > 0);
assert(mml->glideFormat > 0);
assert(ti->isInTM);
if (!ti->validated) {
fprintf(stderr, "fxTMReloadMipMapLevel: INTERNAL ERROR: not validated\n");
fxCloseHardware();
exit(-1);
}
tmu = (int) ti->whichTMU;
fxMesa->stats.reqTexUpload++;
fxMesa->stats.texUpload++;
lodlevel = ti->info.largeLodLog2 - (level - ti->minLevel);
switch (tmu) {
case FX_TMU0:
case FX_TMU1:
grTexDownloadMipMapLevel(tmu,
ti->tm[tmu]->startAddr,
lodlevel,
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
break;
case FX_TMU_SPLIT:
grTexDownloadMipMapLevel(GR_TMU0,
ti->tm[GR_TMU0]->startAddr,
lodlevel,
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_ODD, texImage->Data);
grTexDownloadMipMapLevel(GR_TMU1,
ti->tm[GR_TMU1]->startAddr,
lodlevel,
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_EVEN, texImage->Data);
break;
case FX_TMU_BOTH:
grTexDownloadMipMapLevel(GR_TMU0,
ti->tm[GR_TMU0]->startAddr,
lodlevel,
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
grTexDownloadMipMapLevel(GR_TMU1,
ti->tm[GR_TMU1]->startAddr,
lodlevel,
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
break;
default:
fprintf(stderr, "fxTMReloadMipMapLevel: INTERNAL ERROR: wrong tmu (%d)\n", tmu);
fxCloseHardware();
exit(-1);
}
}
void
fxTMReloadSubMipMapLevel(fxMesaContext fxMesa,
struct gl_texture_object *tObj,
GLint level, GLint yoffset, GLint height)
{
tfxTexInfo *ti = fxTMGetTexInfo(tObj);
GrLOD_t lodlevel;
unsigned short *data;
GLint tmu;
struct gl_texture_image *texImage = tObj->Image[0][level];
tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
assert(mml);
if (!ti->validated) {
fprintf(stderr, "fxTMReloadSubMipMapLevel: INTERNAL ERROR: not validated\n");
fxCloseHardware();
exit(-1);
}
tmu = (int) ti->whichTMU;
fxTMMoveInTM(fxMesa, tObj, tmu);
fxTexGetInfo(mml->width, mml->height,
&lodlevel, NULL, NULL, NULL, NULL, NULL);
if ((ti->info.format == GR_TEXFMT_INTENSITY_8) ||
(ti->info.format == GR_TEXFMT_P_8) ||
(ti->info.format == GR_TEXFMT_ALPHA_8))
data = (GLushort *) texImage->Data + ((yoffset * mml->width) >> 1);
else
data = (GLushort *) texImage->Data + yoffset * mml->width;
switch (tmu) {
case FX_TMU0:
case FX_TMU1:
grTexDownloadMipMapLevelPartial(tmu,
ti->tm[tmu]->startAddr,
FX_valueToLod(FX_lodToValue(lodlevel)
+ level),
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_BOTH, data,
yoffset, yoffset + height - 1);
break;
case FX_TMU_SPLIT:
grTexDownloadMipMapLevelPartial(GR_TMU0,
ti->tm[FX_TMU0]->startAddr,
FX_valueToLod(FX_lodToValue(lodlevel)
+ level),
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_ODD, data,
yoffset, yoffset + height - 1);
grTexDownloadMipMapLevelPartial(GR_TMU1,
ti->tm[FX_TMU1]->startAddr,
FX_valueToLod(FX_lodToValue(lodlevel)
+ level),
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_EVEN, data,
yoffset, yoffset + height - 1);
break;
case FX_TMU_BOTH:
grTexDownloadMipMapLevelPartial(GR_TMU0,
ti->tm[FX_TMU0]->startAddr,
FX_valueToLod(FX_lodToValue(lodlevel)
+ level),
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_BOTH, data,
yoffset, yoffset + height - 1);
grTexDownloadMipMapLevelPartial(GR_TMU1,
ti->tm[FX_TMU1]->startAddr,
FX_valueToLod(FX_lodToValue(lodlevel)
+ level),
FX_largeLodLog2(ti->info),
FX_aspectRatioLog2(ti->info),
ti->info.format,
GR_MIPMAPLEVELMASK_BOTH, data,
yoffset, yoffset + height - 1);
break;
default:
fprintf(stderr, "fxTMReloadSubMipMapLevel: INTERNAL ERROR: wrong tmu (%d)\n", tmu);
fxCloseHardware();
exit(-1);
}
}
void
fxTMMoveOutTM(fxMesaContext fxMesa, struct gl_texture_object *tObj)
{
tfxTexInfo *ti = fxTMGetTexInfo(tObj);
if (TDFX_DEBUG & VERBOSE_DRIVER) {
fprintf(stderr, "fxTMMoveOutTM(%p (%d))\n", (void *)tObj, tObj->Name);
}
if (!ti->isInTM)
return;
switch (ti->whichTMU) {
case FX_TMU0:
case FX_TMU1:
fxTMRemoveRange(fxMesa, (int) ti->whichTMU, ti->tm[ti->whichTMU]);
break;
case FX_TMU_SPLIT:
case FX_TMU_BOTH:
fxTMRemoveRange(fxMesa, FX_TMU0, ti->tm[FX_TMU0]);
fxTMRemoveRange(fxMesa, FX_TMU1, ti->tm[FX_TMU1]);
break;
default:
fprintf(stderr, "fxTMMoveOutTM: INTERNAL ERROR: bad TMU (%ld)\n", ti->whichTMU);
fxCloseHardware();
exit(-1);
}
ti->isInTM = GL_FALSE;
ti->whichTMU = FX_TMU_NONE;
}
void
fxTMFreeTexture(fxMesaContext fxMesa, struct gl_texture_object *tObj)
{
tfxTexInfo *ti = fxTMGetTexInfo(tObj);
int i;
if (TDFX_DEBUG & VERBOSE_TEXTURE) {
fprintf(stderr, "fxTMFreeTexture(%p (%d))\n", (void *)tObj, tObj->Name);
}
fxTMMoveOutTM(fxMesa, tObj);
for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
struct gl_texture_image *texImage = tObj->Image[0][i];
if (texImage) {
if (texImage->DriverData) {
FREE(texImage->DriverData);
texImage->DriverData = NULL;
}
}
}
switch (ti->whichTMU) {
case FX_TMU0:
case FX_TMU1:
fxTMDeleteRangeNode(fxMesa, ti->tm[ti->whichTMU]);
break;
case FX_TMU_SPLIT:
case FX_TMU_BOTH:
fxTMDeleteRangeNode(fxMesa, ti->tm[FX_TMU0]);
fxTMDeleteRangeNode(fxMesa, ti->tm[FX_TMU1]);
break;
}
}
void
fxTMInit(fxMesaContext fxMesa)
{
fxMesa->texBindNumber = 0;
fxMesa->tmPool = 0;
if (fxMesa->HaveTexUma) {
grEnable(GR_TEXTURE_UMA_EXT);
}
fxTMUInit(fxMesa, FX_TMU0);
if (!fxMesa->HaveTexUma && fxMesa->haveTwoTMUs)
fxTMUInit(fxMesa, FX_TMU1);
texBoundMask = (fxMesa->type >= GR_SSTTYPE_Banshee) ? -1 : (FX_2MB_SPLIT - 1);
}
void
fxTMClose(fxMesaContext fxMesa)
{
MemRange *tmp, *next;
tmp = fxMesa->tmPool;
while (tmp) {
next = tmp->next;
FREE(tmp);
tmp = next;
}
tmp = fxMesa->tmFree[FX_TMU0];
while (tmp) {
next = tmp->next;
FREE(tmp);
tmp = next;
}
if (fxMesa->haveTwoTMUs) {
tmp = fxMesa->tmFree[FX_TMU1];
while (tmp) {
next = tmp->next;
FREE(tmp);
tmp = next;
}
}
}
void
fxTMRestoreTextures_NoLock(fxMesaContext ctx)
{
struct _mesa_HashTable *textures = ctx->glCtx->Shared->TexObjects;
GLuint id;
for (id = _mesa_HashFirstEntry(textures);
id;
id = _mesa_HashNextEntry(textures, id)) {
struct gl_texture_object *tObj
= (struct gl_texture_object *) _mesa_HashLookup(textures, id);
tfxTexInfo *ti = fxTMGetTexInfo(tObj);
if (ti && ti->isInTM) {
int i;
for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
if (ctx->glCtx->Texture.Unit[i]._Current == tObj) {
/* Force the texture onto the board, as it could be in use */
int where = ti->whichTMU;
fxTMMoveOutTM_NoLock(ctx, tObj);
fxTMMoveInTM_NoLock(ctx, tObj, where);
break;
}
}
if (i == MAX_TEXTURE_UNITS) /* Mark the texture as off the board */
fxTMMoveOutTM_NoLock(ctx, tObj);
}
}
}
#else
/*
* Need this to provide at least one external definition.
*/
extern int gl_fx_dummy_function_texman(void);
int
gl_fx_dummy_function_texman(void)
{
return 0;
}
#endif /* FX */