applied Daryll's patches
authorBrian Paul <brian.paul@tungstengraphics.com>
Fri, 10 Dec 1999 19:11:23 +0000 (19:11 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Fri, 10 Dec 1999 19:11:23 +0000 (19:11 +0000)
src/mesa/drivers/glide/fxglidew.h
src/mesa/drivers/glide/fxsetup.c
src/mesa/drivers/glide/fxtexman.c

index fc41445db191a4ecff7e9336f21afa1525eb53b4..49c28f222cecc036e26bda80ffe15e1286a9aa3c 100644 (file)
@@ -76,7 +76,6 @@
 /*
  * Genral warper functions for Glide2/Glide3:
  */ 
-extern FxI32 grGetInteger(FxU32 pname);
 extern FxI32 FX_grGetInteger(FxU32 pname);
 
 /*
@@ -334,15 +333,7 @@ typedef struct
  */
 #define FX_grDrawTriangle(a,b,c)       \
   do {                                 \
-    /* int big=0; */                           \
     BEGIN_CLIP_LOOP();                 \
-    /* if (((GrVertex*)a)->x>2000 || ((GrVertex*)a)->x<-2000 || \
-        ((GrVertex*)a)->y>2000 || ((GrVertex*)a)->y<-2000 || \
-        ((GrVertex*)a)->z>65000 || ((GrVertex*)a)->z<-65000) { \
-         fprintf(stderr, "Extreme triangle (%f,%f,%f)\n", \
-         ((GrVertex*)a)->x, ((GrVertex*)a)->y, ((GrVertex*)a)->z); \
-        big=1; \
-       } else */ \
     grDrawTriangle(a,b,c);             \
     END_CLIP_LOOP();                   \
   } while (0)
index 8de34ef90c51368b4c29494745108984a0f10b5e..b27d5c98334a6c2dfbbdd40578ce898163a2e371 100644 (file)
@@ -72,11 +72,10 @@ static void fxSetupCull(GLcontext *ctx);
 static void gl_print_fx_state_flags( const char *msg, GLuint flags);
 static GLboolean fxMultipassTexture( struct vertex_buffer *, GLuint );
 
-
 static void fxTexValidate(GLcontext *ctx, struct gl_texture_object *tObj)
 {
-  tfxTexInfo *ti=(tfxTexInfo *)tObj->DriverData;
-  GLint minl,maxl;
+  tfxTexInfo *ti=fxTMGetTexInfo(tObj);
+  GLint minl, maxl;
 
   if (MESA_VERBOSE&VERBOSE_DRIVER) {
      fprintf(stderr,"fxmesa: fxTexValidate(...) Start\n");
@@ -89,15 +88,15 @@ static void fxTexValidate(GLcontext *ctx, struct gl_texture_object *tObj)
     return;
   }
 
+  ti->tObj=tObj;
   minl=ti->minLevel=tObj->BaseLevel;
   maxl=ti->maxLevel=MIN2(tObj->MaxLevel,tObj->Image[0]->MaxLog2);
 
-  fxTexGetInfo(tObj->Image[minl]->Width,tObj->Image[minl]->Height,
-              &(FX_largeLodLog2(ti->info)),&(FX_aspectRatioLog2(ti->info)),
-              &(ti->sScale),&(ti->tScale),
-              &(ti->int_sScale),&(ti->int_tScale),            
-              NULL,NULL);
-
+  fxTexGetInfo(tObj->Image[minl]->Width, tObj->Image[minl]->Height,
+              &(FX_largeLodLog2(ti->info)), &(FX_aspectRatioLog2(ti->info)),
+              &(ti->sScale), &(ti->tScale),
+              &(ti->int_sScale), &(ti->int_tScale),           
+              NULL, NULL);
 
   if((tObj->MinFilter!=GL_NEAREST) && (tObj->MinFilter!=GL_LINEAR))
     fxTexGetInfo(tObj->Image[maxl]->Width,tObj->Image[maxl]->Height,
@@ -110,6 +109,27 @@ static void fxTexValidate(GLcontext *ctx, struct gl_texture_object *tObj)
 
   fxTexGetFormat(tObj->Image[minl]->Format,&(ti->info.format),&(ti->baseLevelInternalFormat));
 
+  switch (tObj->WrapS) {
+  case GL_CLAMP_TO_EDGE:
+    /* What's this really mean compared to GL_CLAMP? */
+  case GL_CLAMP:
+    ti->sClamp=1;
+    break;
+  case GL_REPEAT:
+    ti->sClamp=0;
+    break;
+  }
+  switch (tObj->WrapT) {
+  case GL_CLAMP_TO_EDGE:
+    /* What's this really mean compared to GL_CLAMP? */
+  case GL_CLAMP:
+    ti->tClamp=1;
+    break;
+  case GL_REPEAT:
+    ti->tClamp=0;
+    break;
+  }
+
   ti->validated=GL_TRUE;
 
   ti->info.data=NULL;
@@ -173,7 +193,7 @@ static GLuint fxGetTexSetConfiguration(GLcontext *ctx,
     unitsmode|=FX_UM_COLOR_CONSTANT;
 
   if(tObj0) {
-    tfxTexInfo *ti0=(tfxTexInfo *)tObj0->DriverData;
+    tfxTexInfo *ti0=fxTMGetTexInfo(tObj0);
 
     switch(ti0->baseLevelInternalFormat) {
     case GL_ALPHA:
@@ -219,7 +239,7 @@ static GLuint fxGetTexSetConfiguration(GLcontext *ctx,
   }
 
   if(tObj1) {
-    tfxTexInfo *ti1=(tfxTexInfo *)tObj1->DriverData;
+    tfxTexInfo *ti1=fxTMGetTexInfo(tObj1);
 
     switch(ti1->baseLevelInternalFormat) {
     case GL_ALPHA:
@@ -283,9 +303,9 @@ static GLuint fxGetTexSetConfiguration(GLcontext *ctx,
 
 static void fxSetupSingleTMU_NoLock(fxMesaContext fxMesa, struct gl_texture_object *tObj)
 {
-  tfxTexInfo *ti=(tfxTexInfo *)tObj->DriverData;
+  tfxTexInfo *ti=fxTMGetTexInfo(tObj);
 
-  if (!ti->tmi.isInTM) {
+  if (!ti->isInTM) {
     if (ti->LODblend)
       fxTMMoveInTM_NoLock(fxMesa,tObj,FX_TMU_SPLIT);
     else {
@@ -301,7 +321,7 @@ static void fxSetupSingleTMU_NoLock(fxMesaContext fxMesa, struct gl_texture_obje
     }
   }
 
-  if (ti->LODblend && ti->tmi.whichTMU == FX_TMU_SPLIT) {
+  if (ti->LODblend && ti->whichTMU == FX_TMU_SPLIT) {
     if ((ti->info.format==GR_TEXFMT_P_8) && (!fxMesa->haveGlobalPaletteTexture)) {
        if (MESA_VERBOSE&VERBOSE_DRIVER) {
          fprintf(stderr,"fxmesa: uploading texture palette\n");
@@ -317,16 +337,16 @@ static void fxSetupSingleTMU_NoLock(fxMesaContext fxMesa, struct gl_texture_obje
     FX_grTexMipMapMode_NoLock(GR_TMU0,ti->mmMode,ti->LODblend);
     FX_grTexMipMapMode_NoLock(GR_TMU1,ti->mmMode,ti->LODblend);
 
-    FX_grTexSource_NoLock(GR_TMU0,ti->tmi.tm[FX_TMU0]->startAddress,
+    FX_grTexSource_NoLock(GR_TMU0,ti->tm[FX_TMU0]->startAddr,
                          GR_MIPMAPLEVELMASK_ODD,&(ti->info));
-    FX_grTexSource_NoLock(GR_TMU1,ti->tmi.tm[FX_TMU1]->startAddress,
+    FX_grTexSource_NoLock(GR_TMU1,ti->tm[FX_TMU1]->startAddr,
                          GR_MIPMAPLEVELMASK_EVEN,&(ti->info));
   } else {
     if((ti->info.format==GR_TEXFMT_P_8) && (!fxMesa->haveGlobalPaletteTexture)) {
        if (MESA_VERBOSE&VERBOSE_DRIVER) {
          fprintf(stderr,"fxmesa: uploading texture palette\n");
        }
-      FX_grTexDownloadTable_NoLock(ti->tmi.whichTMU,GR_TEXTABLE_PALETTE,&(ti->palette));
+      FX_grTexDownloadTable_NoLock(ti->whichTMU,GR_TEXTABLE_PALETTE,&(ti->palette));
     }
 
     /* KW: The alternative is to do the download to the other tmu.  If
@@ -336,12 +356,12 @@ static void fxSetupSingleTMU_NoLock(fxMesaContext fxMesa, struct gl_texture_obje
     if (ti->LODblend && (MESA_VERBOSE&VERBOSE_DRIVER))
        fprintf(stderr, "fxmesa: not blending texture - only on one tmu\n");
 
-    FX_grTexClampMode_NoLock(ti->tmi.whichTMU,ti->sClamp,ti->tClamp);
-    FX_grTexFilterMode_NoLock(ti->tmi.whichTMU,ti->minFilt,ti->maxFilt);
-    FX_grTexMipMapMode_NoLock(ti->tmi.whichTMU,ti->mmMode,FXFALSE);
+    FX_grTexClampMode_NoLock(ti->whichTMU,ti->sClamp,ti->tClamp);
+    FX_grTexFilterMode_NoLock(ti->whichTMU,ti->minFilt,ti->maxFilt);
+    FX_grTexMipMapMode_NoLock(ti->whichTMU,ti->mmMode,FXFALSE);
 
-    FX_grTexSource_NoLock(ti->tmi.whichTMU,
-                         ti->tmi.tm[ti->tmi.whichTMU]->startAddress,
+    FX_grTexSource_NoLock(ti->whichTMU,
+                         ti->tm[ti->whichTMU]->startAddr,
                          GR_MIPMAPLEVELMASK_BOTH,&(ti->info));
   }
 }
@@ -411,14 +431,14 @@ static void fxSetupTextureSingleTMU_NoLock(GLcontext *ctx, GLuint textureset)
      fprintf(stderr,"fxmesa: fxSetupTextureSingleTMU(...) Start\n");
   }
 
-  ti=(tfxTexInfo *)tObj->DriverData;
+  ti=fxTMGetTexInfo(tObj);
 
   fxTexValidate(ctx,tObj);
 
   fxSetupSingleTMU_NoLock(fxMesa,tObj);
 
-  if(fxMesa->tmuSrc!=ti->tmi.whichTMU)
-    fxSelectSingleTMUSrc_NoLock(fxMesa,ti->tmi.whichTMU,ti->LODblend);
+  if(fxMesa->tmuSrc!=ti->whichTMU)
+    fxSelectSingleTMUSrc_NoLock(fxMesa,ti->whichTMU,ti->LODblend);
 
   if(textureset==0 || !fxMesa->haveTwoTMUs)
     unitsmode=fxGetTexSetConfiguration(ctx,tObj,NULL);
@@ -547,18 +567,18 @@ static void fxSetupDoubleTMU_NoLock(fxMesaContext fxMesa,
 #define T0_IN_TMU1     0x10
 #define T1_IN_TMU1     0x20
 
-  tfxTexInfo *ti0=(tfxTexInfo *)tObj0->DriverData;
-  tfxTexInfo *ti1=(tfxTexInfo *)tObj1->DriverData;
+  tfxTexInfo *ti0=fxTMGetTexInfo(tObj0);
+  tfxTexInfo *ti1=fxTMGetTexInfo(tObj1);
   GLuint tstate=0;
 
   if (MESA_VERBOSE&VERBOSE_DRIVER) {
      fprintf(stderr,"fxmesa: fxSetupDoubleTMU(...)\n");
   }
 
-  if(ti0->tmi.isInTM) {
-    if(ti0->tmi.whichTMU==FX_TMU0)
+  if(ti0->isInTM) {
+    if(ti0->whichTMU==FX_TMU0)
       tstate|=T0_IN_TMU0;
-    else if(ti0->tmi.whichTMU==FX_TMU1)
+    else if(ti0->whichTMU==FX_TMU1)
       tstate|=T0_IN_TMU1;
     else {
       fxTMMoveOutTM(fxMesa,tObj0);
@@ -567,10 +587,10 @@ static void fxSetupDoubleTMU_NoLock(fxMesaContext fxMesa,
   } else
     tstate|=T0_NOT_IN_TMU;
 
-  if(ti1->tmi.isInTM) {
-    if(ti1->tmi.whichTMU==FX_TMU0)
+  if(ti1->isInTM) {
+    if(ti1->whichTMU==FX_TMU0)
       tstate|=T1_IN_TMU0;
-    else if(ti1->tmi.whichTMU==FX_TMU1)
+    else if(ti1->whichTMU==FX_TMU1)
       tstate|=T1_IN_TMU1;
     else {
       fxTMMoveOutTM(fxMesa,tObj1);
@@ -579,8 +599,8 @@ static void fxSetupDoubleTMU_NoLock(fxMesaContext fxMesa,
   } else
     tstate|=T1_NOT_IN_TMU;
 
-  ti0->tmi.lastTimeUsed=fxMesa->texBindNumber;
-  ti1->tmi.lastTimeUsed=fxMesa->texBindNumber;
+  ti0->lastTimeUsed=fxMesa->texBindNumber;
+  ti1->lastTimeUsed=fxMesa->texBindNumber;
 
   /* Move texture maps in TMUs */ 
 
@@ -638,30 +658,30 @@ static void fxSetupDoubleTMU_NoLock(fxMesaContext fxMesa,
        if (MESA_VERBOSE&VERBOSE_DRIVER) {
          fprintf(stderr,"fxmesa: uploading texture palette TMU0\n");
        }
-       FX_grTexDownloadTable_NoLock(ti0->tmi.whichTMU,GR_TEXTABLE_PALETTE,&(ti0->palette));
+       FX_grTexDownloadTable_NoLock(ti0->whichTMU,GR_TEXTABLE_PALETTE,&(ti0->palette));
     }
 
     if (ti1->info.format==GR_TEXFMT_P_8) {
        if (MESA_VERBOSE&VERBOSE_DRIVER) {
          fprintf(stderr,"fxmesa: uploading texture palette TMU1\n");
        }
-       FX_grTexDownloadTable_NoLock(ti1->tmi.whichTMU, GR_TEXTABLE_PALETTE,&(ti1->palette));
+       FX_grTexDownloadTable_NoLock(ti1->whichTMU, GR_TEXTABLE_PALETTE,&(ti1->palette));
     }
   }
 
-  FX_grTexClampMode_NoLock(ti0->tmi.whichTMU,ti0->sClamp,ti0->tClamp);
-  FX_grTexFilterMode_NoLock(ti0->tmi.whichTMU,ti0->minFilt,ti0->maxFilt);
-  FX_grTexMipMapMode_NoLock(ti0->tmi.whichTMU,ti0->mmMode,FXFALSE);
-  FX_grTexSource_NoLock(ti0->tmi.whichTMU,
-                       ti0->tmi.tm[ti0->tmi.whichTMU]->startAddress,
+  FX_grTexSource_NoLock(ti0->whichTMU,
+                       ti0->tm[ti0->whichTMU]->startAddr,
                        GR_MIPMAPLEVELMASK_BOTH,&(ti0->info));
+  FX_grTexClampMode_NoLock(ti0->whichTMU,ti0->sClamp,ti0->tClamp);
+  FX_grTexFilterMode_NoLock(ti0->whichTMU,ti0->minFilt,ti0->maxFilt);
+  FX_grTexMipMapMode_NoLock(ti0->whichTMU,ti0->mmMode,FXFALSE);
 
-  FX_grTexClampMode_NoLock(ti1->tmi.whichTMU,ti1->sClamp,ti1->tClamp);
-  FX_grTexFilterMode_NoLock(ti1->tmi.whichTMU,ti1->minFilt,ti1->maxFilt);
-  FX_grTexMipMapMode_NoLock(ti1->tmi.whichTMU,ti1->mmMode,FXFALSE);
-  FX_grTexSource_NoLock(ti1->tmi.whichTMU,
-                       ti1->tmi.tm[ti1->tmi.whichTMU]->startAddress,
+  FX_grTexSource_NoLock(ti1->whichTMU,
+                       ti1->tm[ti1->whichTMU]->startAddr,
                        GR_MIPMAPLEVELMASK_BOTH,&(ti1->info));
+  FX_grTexClampMode_NoLock(ti1->whichTMU,ti1->sClamp,ti1->tClamp);
+  FX_grTexFilterMode_NoLock(ti1->whichTMU,ti1->minFilt,ti1->maxFilt);
+  FX_grTexMipMapMode_NoLock(ti1->whichTMU,ti1->mmMode,FXFALSE);
 
 #undef T0_NOT_IN_TMU
 #undef T1_NOT_IN_TMU
@@ -684,10 +704,10 @@ static void fxSetupTextureDoubleTMU_NoLock(GLcontext *ctx)
      fprintf(stderr,"fxmesa: fxSetupTextureDoubleTMU(...) Start\n");
   }
 
-  ti0=(tfxTexInfo *)tObj0->DriverData;
+  ti0=fxTMGetTexInfo(tObj0);
   fxTexValidate(ctx,tObj0);
 
-  ti1=(tfxTexInfo *)tObj1->DriverData;
+  ti1=fxTMGetTexInfo(tObj1);
   fxTexValidate(ctx,tObj1);
 
   fxSetupDoubleTMU_NoLock(fxMesa,tObj0,tObj1);
@@ -729,14 +749,14 @@ static void fxSetupTextureDoubleTMU_NoLock(GLcontext *ctx)
       GLboolean isalpha[FX_NUM_TMU];
 
       if(ti0->baseLevelInternalFormat==GL_ALPHA)
-       isalpha[ti0->tmi.whichTMU]=GL_TRUE;
+       isalpha[ti0->whichTMU]=GL_TRUE;
       else
-       isalpha[ti0->tmi.whichTMU]=GL_FALSE;
+       isalpha[ti0->whichTMU]=GL_FALSE;
 
       if(ti1->baseLevelInternalFormat==GL_ALPHA)
-       isalpha[ti1->tmi.whichTMU]=GL_TRUE;
+       isalpha[ti1->whichTMU]=GL_TRUE;
       else
-       isalpha[ti1->tmi.whichTMU]=GL_FALSE;
+       isalpha[ti1->whichTMU]=GL_FALSE;
        
       if(isalpha[FX_TMU1])
        FX_grTexCombine_NoLock(GR_TMU1,
@@ -782,7 +802,7 @@ static void fxSetupTextureDoubleTMU_NoLock(GLcontext *ctx)
       break;
     }
   case (FX_UM_E0_REPLACE | FX_UM_E1_BLEND): /* Only for GLQuake */
-    if(ti1->tmi.whichTMU==FX_TMU1) {
+    if(ti1->whichTMU==FX_TMU1) {
       FX_grTexCombine_NoLock(GR_TMU1,
                             GR_COMBINE_FUNCTION_LOCAL,
                             GR_COMBINE_FACTOR_NONE,
@@ -825,7 +845,7 @@ static void fxSetupTextureDoubleTMU_NoLock(GLcontext *ctx)
                             FXFALSE);
     break;
   case (FX_UM_E0_REPLACE | FX_UM_E1_MODULATE): /* Quake 2 and 3 */
-    if(ti1->tmi.whichTMU==FX_TMU1) {
+    if(ti1->whichTMU==FX_TMU1) {
       FX_grTexCombine_NoLock(GR_TMU1,
                             GR_COMBINE_FUNCTION_LOCAL,
                             GR_COMBINE_FACTOR_NONE,
@@ -883,14 +903,14 @@ static void fxSetupTextureDoubleTMU_NoLock(GLcontext *ctx)
       GLboolean isalpha[FX_NUM_TMU];
 
       if(ti0->baseLevelInternalFormat==GL_ALPHA)
-       isalpha[ti0->tmi.whichTMU]=GL_TRUE;
+       isalpha[ti0->whichTMU]=GL_TRUE;
       else
-       isalpha[ti0->tmi.whichTMU]=GL_FALSE;
+       isalpha[ti0->whichTMU]=GL_FALSE;
 
       if(ti1->baseLevelInternalFormat==GL_ALPHA)
-       isalpha[ti1->tmi.whichTMU]=GL_TRUE;
+       isalpha[ti1->whichTMU]=GL_TRUE;
       else
-       isalpha[ti1->tmi.whichTMU]=GL_FALSE;
+       isalpha[ti1->whichTMU]=GL_FALSE;
        
       if(isalpha[FX_TMU1])
        FX_grTexCombine_NoLock(GR_TMU1,
index 97577fca26afb87300c7874318fe4480b200e385..770f095ab8cb9edad63e7bb0b6488b4b3022d496 100644 (file)
 
 #include "fxdrv.h"
 
-static tfxTMFreeNode *fxTMNewTMFreeNode(FxU32 start, FxU32 end)
+#define FX_2MB_SPLIT 0x200000
+
+static struct gl_texture_object *fxTMFindOldestObject(fxMesaContext fxMesa,
+                                                     int tmu);
+
+
+#if 0
+static void fubar()
 {
-  tfxTMFreeNode *tmn;
+}
 
-  if(!(tmn=MALLOC(sizeof(tfxTMFreeNode)))) {
-    fprintf(stderr,"fx Driver: out of memory !\n");
-    fxCloseHardware();
-    exit(-1);
+  /* Sanity Check */
+static void sanity(fxMesaContext fxMesa, int tmu)
+{
+  MemRange *tmp, *prev;
+  int i;
+
+  prev=0;
+  tmp = fxMesa->tmFree[tmu];
+  i=0;
+  while (tmp) {
+    fprintf(stderr, "TMU %d Sanity %d %d-%d\n", tmu, i, 
+           tmp->startAddr, tmp->endAddr);
+    i++;
+    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
 
-  tmn->next=NULL;
-  tmn->startAddress=start;
-  tmn->endAddress=end;
+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, "fxDriver: out of memory!\n");
+      fxCloseHardware();
+      exit(-1);
+    }
+  }
+  result->startAddr=start;
+  result->endAddr=end;
+  return result;
+}
 
-  return tmn;
+static void fxTMDeleteRangeNode(fxMesaContext fxMesa, MemRange *range)
+{
+  range->next=fxMesa->tmPool;
+  fxMesa->tmPool=range;
 }
 
-/* Notice this uses grTex{Min,Max}Address directly with FX_ because it
-   is only used during initialization where the lock is already held. */
 static void fxTMUInit(fxMesaContext fxMesa, int tmu)
 {
-  tfxTMFreeNode *tmn,*tmntmp;
+  MemRange *tmn, *last;
   FxU32 start,end,blockstart,blockend;
 
   start=FX_grTexMinAddress(tmu);
   end=FX_grTexMaxAddress(tmu);
+  fxMesa->texStart[tmu]=start;
 
   if(fxMesa->verbose) {
     fprintf(stderr,"%s configuration:",(tmu==FX_TMU0) ? "TMU0" : "TMU1");
@@ -90,169 +139,158 @@ static void fxTMUInit(fxMesaContext fxMesa, int tmu)
 
   fxMesa->freeTexMem[tmu]=end-start;
   fxMesa->tmFree[tmu]=NULL;
-  fxMesa->tmAlloc[tmu]=NULL;
 
+  last=0;
   blockstart=start;
-  while(blockstart<=end) {
-    if(blockstart+0x1fffff>end)
-      blockend=end;
-    else
-      blockend=blockstart+0x1fffff;
+  while (blockstart<end) {
+    if (blockstart+FX_2MB_SPLIT>end) blockend=end;
+    else blockend=blockstart+FX_2MB_SPLIT;
 
     if(fxMesa->verbose)
-      fprintf(stderr,"    %07u-%07u\n",(unsigned int)blockstart,(unsigned int)blockend);
+      fprintf(stderr,"    %07u-%07u\n",
+             (unsigned int)blockstart,(unsigned int)blockend);
 
-    tmn=fxTMNewTMFreeNode(blockstart,blockend);
+    tmn=fxTMNewRangeNode(fxMesa, blockstart, blockend);
+    tmn->next=0;
 
-    if(fxMesa->tmFree[tmu]) {
-      for(tmntmp=fxMesa->tmFree[tmu];tmntmp->next!=NULL;tmntmp=tmntmp->next){};
-      tmntmp->next=tmn;
-    } else
-      fxMesa->tmFree[tmu]=tmn;
+    if (last) last->next=tmn;
+    else fxMesa->tmFree[tmu]=tmn;
+    last=tmn;
 
-    blockstart+=0x1fffff+1;
+    blockstart+=FX_2MB_SPLIT;
   }
 }
 
-void fxTMInit(fxMesaContext fxMesa)
-{
-  fxTMUInit(fxMesa,FX_TMU0);
-
-  if(fxMesa->haveTwoTMUs)
-    fxTMUInit(fxMesa,FX_TMU1);
-
-  fxMesa->texBindNumber=0;
-}
-
-static struct gl_texture_object *fxTMFindOldestTMBlock(fxMesaContext fxMesa,
-                                                      tfxTMAllocNode *tmalloc,
-                                                      GLuint texbindnumber)
+static int fxTMFindStartAddr(fxMesaContext fxMesa, GLint tmu, int size)
 {
-  GLuint age,oldestage,lasttimeused;
-  struct gl_texture_object *oldesttexobj;
-
-  (void)fxMesa;
-  oldesttexobj=tmalloc->tObj;
-  oldestage=0;
-
-  while(tmalloc) {
-    lasttimeused=((tfxTexInfo *)(tmalloc->tObj->DriverData))->tmi.lastTimeUsed;
-
-    if(lasttimeused>texbindnumber)
-      age=texbindnumber+(UINT_MAX-lasttimeused+1); /* TO DO: check */
-    else
-      age=texbindnumber-lasttimeused;
-
-    if(age>=oldestage) {
-      oldestage=age;
-      oldesttexobj=tmalloc->tObj;
+  MemRange *prev, *tmp;
+  int result;
+  struct gl_texture_object *obj;
+
+  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);
+       }
+       return result;
+      }
+      prev=tmp;
+      tmp=tmp->next;
     }
-
-    tmalloc=tmalloc->next;
+    /* No free space. Discard oldest */
+    obj=fxTMFindOldestObject(fxMesa, tmu);
+    if (!obj) {
+      fprintf(stderr, "fx Driver: No space for texture\n");
+      return -1;
+    }
+    fxTMMoveOutTM(fxMesa, obj);
   }
-
-  return oldesttexobj;
-}
-
-static GLboolean fxTMFreeOldTMBlock(fxMesaContext fxMesa, GLint tmu)
-{
-  struct gl_texture_object *oldesttexobj;
-
-  if(!fxMesa->tmAlloc[tmu])
-    return GL_FALSE;
-
-  oldesttexobj=fxTMFindOldestTMBlock(fxMesa,fxMesa->tmAlloc[tmu],fxMesa->texBindNumber);
-
-  fxTMMoveOutTM(fxMesa,oldesttexobj);
-
-  return GL_TRUE;
 }
 
-static tfxTMFreeNode *fxTMExtractTMFreeBlock(tfxTMFreeNode *tmfree, int texmemsize,
-                                            GLboolean *success, FxU32 *startadr)
+static void fxTMRemoveRange(fxMesaContext fxMesa, GLint tmu, MemRange *range)
 {
-  int blocksize;
-
-  /* TO DO: cut recursion */
+  MemRange *tmp, *prev, *next;
 
-  if(!tmfree) {
-    *success=GL_FALSE;
-    return NULL;
+  if (range->startAddr==range->endAddr) {
+    fxTMDeleteRangeNode(fxMesa, range);
+    return;
   }
-
-  blocksize=(int)tmfree->endAddress-(int)tmfree->startAddress+1;
-
-  if(blocksize==texmemsize) {
-    tfxTMFreeNode *nexttmfree;
-
-    *success=GL_TRUE;
-    *startadr=tmfree->startAddress;
-
-    nexttmfree=tmfree->next;
-    FREE(tmfree);
-
-    return nexttmfree;
+  prev=0;
+  tmp=fxMesa->tmFree[tmu];
+  while (tmp) {
+    if (range->startAddr>tmp->startAddr) {
+      prev=tmp;
+      tmp=tmp->next;
+    } else break;
   }
-
-  if(blocksize>texmemsize) {
-    *success=GL_TRUE;
-    *startadr=tmfree->startAddress;
-
-    tmfree->startAddress+=texmemsize;
-
-    return tmfree;
+  /* 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&(FX_2MB_SPLIT-1)) { 
+      /* Combine */
+      tmp->startAddr=range->startAddr;
+      fxTMDeleteRangeNode(fxMesa, range);
+      range=tmp;
+    }
+  }
+  if (prev) {
+    if (prev->endAddr==range->startAddr && range->startAddr&(FX_2MB_SPLIT-1)) { 
+      /* Combine */
+      prev->endAddr=range->endAddr;
+      prev->next=range->next;
+      fxTMDeleteRangeNode(fxMesa, range);
+    } else prev->next=range;
+  } else {
+    fxMesa->tmFree[tmu]=range;
   }
-
-  tmfree->next=fxTMExtractTMFreeBlock(tmfree->next,texmemsize,success,startadr);
-
-  return tmfree;
 }
 
-static tfxTMAllocNode *fxTMGetTMBlock(fxMesaContext fxMesa, struct gl_texture_object *tObj,
-                                     GLint tmu, int texmemsize)
+static struct gl_texture_object *fxTMFindOldestObject(fxMesaContext fxMesa,
+                                                     int tmu)
 {
-  tfxTMFreeNode *newtmfree;
-  tfxTMAllocNode *newtmalloc;
-  GLboolean success;
-  FxU32 startadr;
-
-  for(;;) { /* TO DO: improve performaces */
-    newtmfree=fxTMExtractTMFreeBlock(fxMesa->tmFree[tmu],texmemsize,&success,&startadr);
-
-    if(success) {
-      fxMesa->tmFree[tmu]=newtmfree;
-
-      fxMesa->freeTexMem[tmu]-=texmemsize;
-
-      if(!(newtmalloc=MALLOC(sizeof(tfxTMAllocNode)))) {
-       fprintf(stderr,"fx Driver: out of memory !\n");
-       fxCloseHardware();
-       exit(-1);
+  GLuint age, old, lasttime, bindnumber;
+  tfxTexInfo *info;
+  struct gl_texture_object *obj, *tmp;
+
+  tmp=fxMesa->glCtx->Shared->TexObjectList;
+  if (!tmp) return 0;
+  obj=0;
+  old=0;
+
+  bindnumber=fxMesa->texBindNumber;
+  while (tmp) {
+    info=fxTMGetTexInfo(tmp);
+
+    if (info && info->isInTM &&
+       (info->whichTMU==tmu || info->whichTMU==FX_TMU_BOTH || 
+       info->whichTMU==FX_TMU_SPLIT)) {
+      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;
       }
-      
-      newtmalloc->next=fxMesa->tmAlloc[tmu];
-      newtmalloc->startAddress=startadr;
-      newtmalloc->endAddress=startadr+texmemsize-1;
-      newtmalloc->tObj=tObj;
-
-      fxMesa->tmAlloc[tmu]=newtmalloc;
-
-      return newtmalloc;
-    }
-
-    if(!fxTMFreeOldTMBlock(fxMesa,tmu)) {
-      fprintf(stderr,"fx Driver: internal error in fxTMGetTMBlock()\n");
-      fprintf(stderr,"           TMU: %d Size: %d\n",tmu,texmemsize);
-    
-      fxCloseHardware();
-      exit(-1);
     }
+    tmp=tmp->Next;
   }
+  return obj;
 }
 
+static MemRange *fxTMAddObj(fxMesaContext fxMesa, 
+                           struct gl_texture_object *tObj,
+                           GLint tmu, int texmemsize)
+{
+  FxU32 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=(tfxTexInfo *)tObj->DriverData;
+  tfxTexInfo *ti=fxTMGetTexInfo(tObj);
   int i,l;
   int texmemsize;
 
@@ -262,68 +300,71 @@ void fxTMMoveInTM_NoLock(fxMesaContext fxMesa, struct gl_texture_object *tObj, G
 
   fxMesa->stats.reqTexUpload++;
 
-  if(!ti->validated) {
+  if (!ti->validated) {
     fprintf(stderr,"fx Driver: internal error in fxTMMoveInTM() -> not validated\n");
     fxCloseHardware();
     exit(-1);
   }
 
-  if(ti->tmi.isInTM)
-    return;
+  if (ti->isInTM) return;
 
   if (MESA_VERBOSE&(VERBOSE_DRIVER|VERBOSE_TEXTURE)) {
      fprintf(stderr,"fxmesa: downloading %x (%d) in texture memory in %d\n",(GLuint)tObj,tObj->Name,where);
   }
 
-  ti->tmi.whichTMU=(FxU32)where;
+  ti->whichTMU=(FxU32)where;
 
-  switch(where) {
+  switch (where) {
   case FX_TMU0:
   case FX_TMU1:
     texmemsize=(int)FX_grTexTextureMemRequired_NoLock(GR_MIPMAPLEVELMASK_BOTH,
                                                      &(ti->info));
-    ti->tmi.tm[where]=fxTMGetTMBlock(fxMesa,tObj,where,texmemsize);
+    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++)
+    for (i=FX_largeLodValue(ti->info), l=ti->minLevel;
+        i<=FX_smallLodValue(ti->info);
+        i++,l++)
       FX_grTexDownloadMipMapLevel_NoLock(where,
-                                        ti->tmi.tm[where]->startAddress,
+                                        ti->tm[where]->startAddr,
                                         FX_valueToLod(i),
                                         FX_largeLodLog2(ti->info),
                                         FX_aspectRatioLog2(ti->info),
                                         ti->info.format,
                                         GR_MIPMAPLEVELMASK_BOTH,
-                                        ti->tmi.mipmapLevel[l].data);
+                                        ti->mipmapLevel[l].data);
     break;
   case FX_TMU_SPLIT: /* TO DO: alternate even/odd TMU0/TMU1 */
     texmemsize=(int)FX_grTexTextureMemRequired_NoLock(GR_MIPMAPLEVELMASK_ODD,
                                                      &(ti->info));
-    ti->tmi.tm[FX_TMU0]=fxTMGetTMBlock(fxMesa,tObj,FX_TMU0,texmemsize);
+    ti->tm[FX_TMU0]=fxTMAddObj(fxMesa, tObj, FX_TMU0, texmemsize);
     fxMesa->stats.memTexUpload+=texmemsize;
 
     texmemsize=(int)FX_grTexTextureMemRequired_NoLock(GR_MIPMAPLEVELMASK_EVEN,
                                                      &(ti->info));
-    ti->tmi.tm[FX_TMU1]=fxTMGetTMBlock(fxMesa,tObj,FX_TMU1,texmemsize);
+    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++) {
+    for (i=FX_largeLodValue(ti->info),l=ti->minLevel;
+        i<=FX_smallLodValue(ti->info);
+        i++,l++) {
       FX_grTexDownloadMipMapLevel_NoLock(GR_TMU0,
-                                        ti->tmi.tm[FX_TMU0]->startAddress,
+                                        ti->tm[FX_TMU0]->startAddr,
                                         FX_valueToLod(i),
                                         FX_largeLodLog2(ti->info),
                                         FX_aspectRatioLog2(ti->info),
                                         ti->info.format,
                                         GR_MIPMAPLEVELMASK_ODD,
-                                        ti->tmi.mipmapLevel[l].data);
+                                        ti->mipmapLevel[l].data);
 
       FX_grTexDownloadMipMapLevel_NoLock(GR_TMU1,
-                                        ti->tmi.tm[FX_TMU1]->startAddress,
+                                        ti->tm[FX_TMU1]->startAddr,
                                         FX_valueToLod(i),
                                         FX_largeLodLog2(ti->info),
                                         FX_aspectRatioLog2(ti->info),
                                         ti->info.format,
                                         GR_MIPMAPLEVELMASK_EVEN,
-                                        ti->tmi.mipmapLevel[l].data);
+                                        ti->mipmapLevel[l].data);
     }
     break;
   default:
@@ -334,7 +375,7 @@ void fxTMMoveInTM_NoLock(fxMesaContext fxMesa, struct gl_texture_object *tObj, G
 
   fxMesa->stats.texUpload++;
 
-  ti->tmi.isInTM=GL_TRUE;
+  ti->isInTM=GL_TRUE;
 }
 
 void fxTMMoveInTM(fxMesaContext fxMesa, struct gl_texture_object *tObj, GLint where) {
@@ -345,43 +386,52 @@ void fxTMMoveInTM(fxMesaContext fxMesa, struct gl_texture_object *tObj, GLint wh
 
 void fxTMReloadMipMapLevel(fxMesaContext fxMesa, struct gl_texture_object *tObj, GLint level)
 {
-  tfxTexInfo *ti=(tfxTexInfo *)tObj->DriverData;
+  tfxTexInfo *ti=fxTMGetTexInfo(tObj);
   GrLOD_t lodlevel;
   GLint tmu;
 
-  if(!ti->validated) {
+  if (!ti->validated) {
     fprintf(stderr,"fx Driver: internal error in fxTMReloadMipMapLevel() -> not validated\n");
     fxCloseHardware();
     exit(-1);
   }
 
-  tmu=(int)ti->tmi.whichTMU;
-  fxTMMoveInTM(fxMesa,tObj,tmu);
+  tmu=(int)ti->whichTMU;
+  fxTMMoveInTM(fxMesa, tObj, tmu);
 
-  fxTexGetInfo(ti->tmi.mipmapLevel[0].width,ti->tmi.mipmapLevel[0].height,
-              &lodlevel,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+  fxTexGetInfo(ti->mipmapLevel[0].width,ti->mipmapLevel[0].height,
+              &lodlevel, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
   switch(tmu) {
   case FX_TMU0:
   case FX_TMU1:
     FX_grTexDownloadMipMapLevel(tmu,
-                            ti->tmi.tm[tmu]->startAddress,FX_valueToLod(FX_lodToValue(lodlevel)+level),
-                            FX_largeLodLog2(ti->info),FX_aspectRatioLog2(ti->info),
-                            ti->info.format,GR_MIPMAPLEVELMASK_BOTH,
-                            ti->tmi.mipmapLevel[level].data);
+                               ti->tm[tmu]->startAddr,
+                               FX_valueToLod(FX_lodToValue(lodlevel)+level),
+                               FX_largeLodLog2(ti->info),
+                               FX_aspectRatioLog2(ti->info),
+                               ti->info.format,
+                               GR_MIPMAPLEVELMASK_BOTH,
+                               ti->mipmapLevel[level].data);
     break;
   case FX_TMU_SPLIT: /* TO DO: alternate even/odd TMU0/TMU1 */
     FX_grTexDownloadMipMapLevel(GR_TMU0,
-                            ti->tmi.tm[GR_TMU0]->startAddress,FX_valueToLod(FX_lodToValue(lodlevel)+level),
-                            FX_largeLodLog2(ti->info),FX_aspectRatioLog2(ti->info),
-                            ti->info.format,GR_MIPMAPLEVELMASK_ODD,
-                            ti->tmi.mipmapLevel[level].data);
+                               ti->tm[GR_TMU0]->startAddr,
+                               FX_valueToLod(FX_lodToValue(lodlevel)+level),
+                               FX_largeLodLog2(ti->info),
+                               FX_aspectRatioLog2(ti->info),
+                               ti->info.format,
+                               GR_MIPMAPLEVELMASK_ODD,
+                               ti->mipmapLevel[level].data);
     
     FX_grTexDownloadMipMapLevel(GR_TMU1,
-                            ti->tmi.tm[GR_TMU1]->startAddress,FX_valueToLod(FX_lodToValue(lodlevel)+level),
-                            FX_largeLodLog2(ti->info),FX_aspectRatioLog2(ti->info),
-                            ti->info.format,GR_MIPMAPLEVELMASK_EVEN,
-                            ti->tmi.mipmapLevel[level].data);
+                               ti->tm[GR_TMU1]->startAddr,
+                               FX_valueToLod(FX_lodToValue(lodlevel)+level),
+                               FX_largeLodLog2(ti->info),
+                               FX_aspectRatioLog2(ti->info),
+                               ti->info.format,
+                               GR_MIPMAPLEVELMASK_EVEN,
+                               ti->mipmapLevel[level].data);
     break;
   default:
     fprintf(stderr,"fx Driver: internal error in fxTMReloadMipMapLevel() -> wrong tmu (%d)\n",tmu);
@@ -390,10 +440,11 @@ void fxTMReloadMipMapLevel(fxMesaContext fxMesa, struct gl_texture_object *tObj,
   }
 }
 
-void fxTMReloadSubMipMapLevel(fxMesaContext fxMesa, struct gl_texture_object *tObj,
+void fxTMReloadSubMipMapLevel(fxMesaContext fxMesa, 
+                             struct gl_texture_object *tObj,
                              GLint level, GLint yoffset, GLint height)
 {
-  tfxTexInfo *ti=(tfxTexInfo *)tObj->DriverData;
+  tfxTexInfo *ti=fxTMGetTexInfo(tObj);
   GrLOD_t lodlevel;
   unsigned short *data;
   GLint tmu;
@@ -404,43 +455,52 @@ void fxTMReloadSubMipMapLevel(fxMesaContext fxMesa, struct gl_texture_object *tO
     exit(-1);
   }
 
-  tmu=(int)ti->tmi.whichTMU;
-  fxTMMoveInTM(fxMesa,tObj,tmu);
+  tmu=(int)ti->whichTMU;
+  fxTMMoveInTM(fxMesa, tObj, tmu);
 
-  fxTexGetInfo(ti->tmi.mipmapLevel[0].width,ti->tmi.mipmapLevel[0].height,
-              &lodlevel,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+  fxTexGetInfo(ti->mipmapLevel[0].width, ti->mipmapLevel[0].height,
+              &lodlevel, NULL, NULL, 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=ti->tmi.mipmapLevel[level].data+((yoffset*ti->tmi.mipmapLevel[level].width)>>1);
+    data=ti->mipmapLevel[level].data+((yoffset*ti->mipmapLevel[level].width)>>1);
   else
-    data=ti->tmi.mipmapLevel[level].data+yoffset*ti->tmi.mipmapLevel[level].width;
+    data=ti->mipmapLevel[level].data+yoffset*ti->mipmapLevel[level].width;
 
   switch(tmu) {
   case FX_TMU0:
   case FX_TMU1:
     FX_grTexDownloadMipMapLevelPartial(tmu,
-                                   ti->tmi.tm[tmu]->startAddress,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);
+                                      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: /* TO DO: alternate even/odd TMU0/TMU1 */
     FX_grTexDownloadMipMapLevelPartial(GR_TMU0,
-                                   ti->tmi.tm[FX_TMU0]->startAddress,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);
+                                      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);
 
     FX_grTexDownloadMipMapLevelPartial(GR_TMU1,
-                                   ti->tmi.tm[FX_TMU1]->startAddress,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);
+                                      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;
   default:
     fprintf(stderr,"fx Driver: internal error in fxTMReloadSubMipMapLevel() -> wrong tmu (%d)\n",tmu);
@@ -449,103 +509,24 @@ void fxTMReloadSubMipMapLevel(fxMesaContext fxMesa, struct gl_texture_object *tO
   }
 }
 
-static tfxTMAllocNode *fxTMFreeTMAllocBlock(tfxTMAllocNode *tmalloc,
-                                           tfxTMAllocNode *tmunalloc)
-{
-  if(!tmalloc)
-    return NULL;
-
-  if(tmalloc==tmunalloc) {
-    tfxTMAllocNode *newtmalloc;
-
-    newtmalloc=tmalloc->next;
-    FREE(tmalloc);
-
-    return newtmalloc;
-  }
-
-  tmalloc->next=fxTMFreeTMAllocBlock(tmalloc->next,tmunalloc);
-
-  return tmalloc;
-}
-
-static tfxTMFreeNode *fxTMAddTMFree(tfxTMFreeNode *tmfree, FxU32 startadr, FxU32 endadr)
-{
-  if(!tmfree)
-    return fxTMNewTMFreeNode(startadr,endadr);
-
-  if((endadr+1==tmfree->startAddress) && (tmfree->startAddress & 0x1fffff)) {
-    tmfree->startAddress=startadr;
-
-    return tmfree;
-  }
-
-  if((startadr-1==tmfree->endAddress) && (startadr & 0x1fffff)) {
-    tmfree->endAddress=endadr;
-
-    if((tmfree->next && (endadr+1==tmfree->next->startAddress) &&
-        (tmfree->next->startAddress & 0x1fffff))) {
-      tfxTMFreeNode *nexttmfree;
-
-      tmfree->endAddress=tmfree->next->endAddress;
-
-      nexttmfree=tmfree->next->next;
-      FREE(tmfree->next);
-
-      tmfree->next=nexttmfree;
-    }
-
-
-    return tmfree;
-  }
-
-  if(startadr<tmfree->startAddress) {
-    tfxTMFreeNode *newtmfree;
-
-    newtmfree=fxTMNewTMFreeNode(startadr,endadr);
-    newtmfree->next=tmfree;
-
-    return newtmfree;
-  }
-
-  tmfree->next=fxTMAddTMFree(tmfree->next,startadr,endadr);
-
-  return tmfree;
-}
-
-static void fxTMFreeTMBlock(fxMesaContext fxMesa, GLint tmu, tfxTMAllocNode *tmalloc)
-{
-  FxU32 startadr,endadr;
-
-  startadr=tmalloc->startAddress;
-  endadr=tmalloc->endAddress;
-
-  fxMesa->tmAlloc[tmu]=fxTMFreeTMAllocBlock(fxMesa->tmAlloc[tmu],tmalloc);
-
-  fxMesa->tmFree[tmu]=fxTMAddTMFree(fxMesa->tmFree[tmu],startadr,endadr);
-
-  fxMesa->freeTexMem[tmu]+=endadr-startadr+1;
-}
-
 void fxTMMoveOutTM(fxMesaContext fxMesa, struct gl_texture_object *tObj)
 {
-  tfxTexInfo *ti=(tfxTexInfo *)tObj->DriverData;
+  tfxTexInfo *ti=fxTMGetTexInfo(tObj);
 
   if (MESA_VERBOSE&VERBOSE_DRIVER) {
      fprintf(stderr,"fxmesa: fxTMMoveOutTM(%x (%d))\n",(GLuint)tObj,tObj->Name);
   }
 
-  if(!ti->tmi.isInTM)
-    return;
+  if (!ti->isInTM)  return;
 
-  switch(ti->tmi.whichTMU) {
+  switch(ti->whichTMU) {
   case FX_TMU0:
   case FX_TMU1:
-    fxTMFreeTMBlock(fxMesa,(int)ti->tmi.whichTMU,ti->tmi.tm[ti->tmi.whichTMU]);
+    fxTMRemoveRange(fxMesa, (int)ti->whichTMU, ti->tm[ti->whichTMU]);
     break;
   case FX_TMU_SPLIT:
-    fxTMFreeTMBlock(fxMesa,FX_TMU0,ti->tmi.tm[FX_TMU0]);
-    fxTMFreeTMBlock(fxMesa,FX_TMU1,ti->tmi.tm[FX_TMU1]);
+    fxTMRemoveRange(fxMesa, FX_TMU0, ti->tm[FX_TMU0]);
+    fxTMRemoveRange(fxMesa, FX_TMU1, ti->tm[FX_TMU1]);
     break;
   default:
     fprintf(stderr,"fx Driver: internal error in fxTMMoveOutTM()\n");
@@ -553,65 +534,75 @@ void fxTMMoveOutTM(fxMesaContext fxMesa, struct gl_texture_object *tObj)
     exit(-1);
   }
 
-  ti->tmi.whichTMU=FX_TMU_NONE;
-  ti->tmi.isInTM=GL_FALSE;
+  ti->isInTM=GL_FALSE;
+  ti->whichTMU=FX_TMU_NONE;
 }
 
 void fxTMFreeTexture(fxMesaContext fxMesa, struct gl_texture_object *tObj)
 {
-  tfxTexInfo *ti=(tfxTexInfo *)tObj->DriverData;
+  tfxTexInfo *ti=fxTMGetTexInfo(tObj);
   int i;
 
-  fxTMMoveOutTM(fxMesa,tObj);
+  fxTMMoveOutTM(fxMesa, tObj);
 
-  for(i=0;i<MAX_TEXTURE_LEVELS;i++) {
-    if(ti->tmi.mipmapLevel[i].used &&
-       ti->tmi.mipmapLevel[i].translated)
-      FREE(ti->tmi.mipmapLevel[i].data);
+  for(i=0; i<MAX_TEXTURE_LEVELS; i++) {
+    if (ti->mipmapLevel[i].used &&
+       ti->mipmapLevel[i].translated)
+      FREE(ti->mipmapLevel[i].data);
 
-    (void)ti->tmi.mipmapLevel[i].data;
+    (void)ti->mipmapLevel[i].data;
+  }
+  switch (ti->whichTMU) {
+  case FX_TMU0:
+    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 fxTMFreeAllFreeNode(tfxTMFreeNode *fn)
-{
-  if(!fn)
-    return;
-
-  if(fn->next)
-    fxTMFreeAllFreeNode(fn->next);
-
-  FREE(fn);
-}
-
-void fxTMFreeAllAllocNode(tfxTMAllocNode *an)
+void fxTMInit(fxMesaContext fxMesa)
 {
-  if(!an)
-    return;
+  fxTMUInit(fxMesa,FX_TMU0);
 
-  if(an->next)
-    fxTMFreeAllAllocNode(an->next);
+  if(fxMesa->haveTwoTMUs)
+    fxTMUInit(fxMesa,FX_TMU1);
 
-  FREE(an);
+  fxMesa->texBindNumber=0;
 }
 
 void fxTMClose(fxMesaContext fxMesa)
 {
-  fxTMFreeAllFreeNode(fxMesa->tmFree[FX_TMU0]);
-  fxTMFreeAllAllocNode(fxMesa->tmAlloc[FX_TMU0]);
-  fxMesa->tmFree[FX_TMU0] = NULL;
-  fxMesa->tmAlloc[FX_TMU0] = NULL;
-  if(fxMesa->haveTwoTMUs) {
-    fxTMFreeAllFreeNode(fxMesa->tmFree[FX_TMU1]);
-    fxTMFreeAllAllocNode(fxMesa->tmAlloc[FX_TMU1]);
-    fxMesa->tmFree[FX_TMU1] = NULL;
-    fxMesa->tmAlloc[FX_TMU1] = NULL;
+  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 fxTMRestore_NoLock(fxMesaContext fxMesa, struct gl_texture_object *tObj)
 {
-  tfxTexInfo *ti=(tfxTexInfo *)tObj->DriverData;
+  tfxTexInfo *ti=fxTMGetTexInfo(tObj);
   int i,l, where;
 
   if (MESA_VERBOSE&VERBOSE_DRIVER) {
@@ -624,9 +615,10 @@ void fxTMRestore_NoLock(fxMesaContext fxMesa, struct gl_texture_object *tObj)
     exit(-1);
   }
 
-  where=ti->tmi.whichTMU;
+  where=ti->whichTMU;
   if (MESA_VERBOSE&(VERBOSE_DRIVER|VERBOSE_TEXTURE)) {
-    fprintf(stderr,"fxmesa: reloading %x (%d) in texture memory in %d\n",(GLuint)tObj,tObj->Name,where);
+    fprintf(stderr,"fxmesa: reloading %x (%d) in texture memory in %d\n",
+           (GLuint)tObj, tObj->Name, where);
   }
 
   switch(where) {
@@ -635,38 +627,38 @@ void fxTMRestore_NoLock(fxMesaContext fxMesa, struct gl_texture_object *tObj)
     for (i=FX_largeLodValue_NoLock(ti->info), l=ti->minLevel;
         i<=FX_smallLodValue_NoLock(ti->info);
         i++,l++)
-      if (ti->tmi.mipmapLevel[l].data)
+      if (ti->mipmapLevel[l].data)
        FX_grTexDownloadMipMapLevel_NoLock(where,
-                                          ti->tmi.tm[where]->startAddress,
+                                          ti->tm[where]->startAddr,
                                           FX_valueToLod(i),
                                           FX_largeLodLog2(ti->info),
                                           FX_aspectRatioLog2(ti->info),
                                           ti->info.format,
                                           GR_MIPMAPLEVELMASK_BOTH,
-                                          ti->tmi.mipmapLevel[l].data);
+                                          ti->mipmapLevel[l].data);
     break;
   case FX_TMU_SPLIT: /* TO DO: alternate even/odd TMU0/TMU1 */
     for (i=FX_largeLodValue_NoLock(ti->info),l=ti->minLevel;
         i<=FX_smallLodValue_NoLock(ti->info);
         i++,l++) {
-      if (ti->tmi.mipmapLevel[l].data)
+      if (ti->mipmapLevel[l].data)
        FX_grTexDownloadMipMapLevel_NoLock(GR_TMU0,
-                                          ti->tmi.tm[FX_TMU0]->startAddress,
+                                          ti->tm[FX_TMU0]->startAddr,
                                           FX_valueToLod(i),
                                           FX_largeLodLog2(ti->info),
                                           FX_aspectRatioLog2(ti->info),
                                           ti->info.format,
                                           GR_MIPMAPLEVELMASK_ODD,
-                                          ti->tmi.mipmapLevel[l].data);
-      if (ti->tmi.mipmapLevel[l].data)
+                                          ti->mipmapLevel[l].data);
+      if (ti->mipmapLevel[l].data)
        FX_grTexDownloadMipMapLevel_NoLock(GR_TMU1,
-                                          ti->tmi.tm[FX_TMU1]->startAddress,
+                                          ti->tm[FX_TMU1]->startAddr,
                                           FX_valueToLod(i),
                                           FX_largeLodLog2(ti->info),
                                           FX_aspectRatioLog2(ti->info),
                                           ti->info.format,
                                           GR_MIPMAPLEVELMASK_EVEN,
-                                          ti->tmi.mipmapLevel[l].data);
+                                          ti->mipmapLevel[l].data);
     }
     break;
   default:
@@ -685,8 +677,8 @@ fxTMRestoreTextures(fxMesaContext ctx) {
 
   tObj=ctx->glCtx->Shared->TexObjectList;
   while (tObj) {
-    ti=(tfxTexInfo*)tObj->DriverData;
-    if (ti && ti->tmi.isInTM) {
+    ti=fxTMGetTexInfo(tObj);
+    if (ti && ti->isInTM) {
       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 */
@@ -698,8 +690,6 @@ fxTMRestoreTextures(fxMesaContext ctx) {
     }
     tObj=tObj->Next;
   }
-  ctx->lastUnitsMode=0;
-  fxSetupTexture_NoLock(ctx->glCtx);
 }
 
 #else