stencil wrap works, either HW or SW (Ian Romanick)
[mesa.git] / src / mesa / drivers / glide / fxsetup.c
index 6ebd037fd5760af2df50ba095c844bfbc9ac0337..71b66fcc1d7b15a4081eb7348a8070116145004a 100644 (file)
@@ -1,10 +1,8 @@
-/* -*- mode: C; tab-width:8; c-basic-offset:2 -*- */
-
 /*
  * Mesa 3-D graphics library
- * Version:  3.3
+ * Version:  4.0
  *
- * Copyright (C) 1999-2000  Brian Paul   All Rights Reserved.
+ * 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"),
  * 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.
- *
- *
- * Original Mesa / 3Dfx device driver (C) 1999 David Bucciarelli, by the
- * terms stated above.
- *
- * Thank you for your contribution, David!
- *
- * Please make note of the above copyright/license statement.  If you
- * contributed code or bug fixes to this code under the previous (GNU
- * Library) license and object to the new license, your code will be
- * removed at your request.  Please see the Mesa docs/COPYRIGHT file
- * for more information.
- *
- * Additional Mesa/3Dfx driver developers:
- *   Daryll Strauss <daryll@precisioninsight.com>
- *   Keith Whitwell <keith@precisioninsight.com>
- *
- * See fxapi.h for more revision/author details.
  */
 
+/* Authors:
+ *    David Bucciarelli
+ *    Brian Paul
+ *    Daryll Strauss
+ *    Keith Whitwell
+ *    Daniel Borca
+ *    Hiroshi Morii
+ */
 
 /* fxsetup.c - 3Dfx VooDoo rendering mode setup functions */
 
 
 #include "fxdrv.h"
 #include "enums.h"
+#include "tnl.h"
+#include "tnl/t_context.h"
+#include "swrast.h"
+
+static void
+fxTexValidate(GLcontext * ctx, struct gl_texture_object *tObj)
+{
+   tfxTexInfo *ti = fxTMGetTexInfo(tObj);
+   GLint minl, maxl;
+
+   if (ti->validated) {
+      if (TDFX_DEBUG & VERBOSE_DRIVER) {
+        fprintf(stderr, "fxTexValidate(NOP)\n");
+      }
+      return;
+   }
+
+   if (TDFX_DEBUG & VERBOSE_DRIVER) {
+      fprintf(stderr, "fxTexValidate(%p (%d))\n", (void *)tObj, tObj->Name);
+   }
+
+   ti->tObj = tObj;
+   minl = ti->minLevel = tObj->BaseLevel;
+   maxl = ti->maxLevel = MIN2(tObj->MaxLevel, tObj->Image[0][0]->MaxLog2);
 
-static GLuint fxGetTexSetConfiguration(GLcontext *ctx,
-                               struct gl_texture_object *tObj0,
-                               struct gl_texture_object *tObj1);
-static void fxSetupTextureSingleTMU_NoLock(GLcontext *ctx, GLuint textureset);
-static void fxSetupDoubleTMU_NoLock(fxMesaContext fxMesa, 
-                            struct gl_texture_object *tObj0,
-                            struct gl_texture_object *tObj1);
-static void fxSetupTexture_NoLock(GLcontext *ctx);
-static void fxSetupTexture(GLcontext *ctx);
-static void fxSetupBlend(GLcontext *ctx);
-static void fxSetupDepthTest(GLcontext *ctx);
-static void fxFogTableGenerate(GLcontext *ctx);
-static void fxSetupFog(GLcontext *ctx, GLboolean forceTableRebuild);
-static void fxSetupScissor(GLcontext *ctx);
-static void fxSetupCull(GLcontext *ctx);
-static void gl_print_fx_state_flags( const char *msg, GLuint flags);
-static GLboolean fxMultipassBlend(struct vertex_buffer *, GLuint);
-static GLboolean fxMultipassTexture( struct vertex_buffer *, GLuint );
-
-static void fxTexValidate(GLcontext *ctx, struct gl_texture_object *tObj)
+#if FX_RESCALE_BIG_TEXURES_HACK
 {
-  tfxTexInfo *ti=fxTMGetTexInfo(tObj);
-  GLint minl, maxl;
-
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
-     fprintf(stderr,"fxmesa: fxTexValidate(...) Start\n");
-  }
-
-  if(ti->validated) {
-     if (MESA_VERBOSE&VERBOSE_DRIVER) {
-       fprintf(stderr,"fxmesa: fxTexValidate(...) End (validated=GL_TRUE)\n");
-     }
-    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);
-
-  if((tObj->MinFilter!=GL_NEAREST) && (tObj->MinFilter!=GL_LINEAR))
-    fxTexGetInfo(tObj->Image[maxl]->Width,tObj->Image[maxl]->Height,
-                &(FX_smallLodLog2(ti->info)),NULL,
-                NULL,NULL,
-                NULL,NULL,
-                NULL,NULL);
-  else
-    FX_smallLodLog2(ti->info)=FX_largeLodLog2(ti->info);
-
-  fxTexGetFormat(tObj->Image[minl]->IntFormat,&(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;
-  default:
-    ;  /* silence compiler warning */
-  }
-  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;
-  default:
-    ;  /* silence compiler warning */
-  }
-
-  ti->validated=GL_TRUE;
-
-  ti->info.data=NULL;
-
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
-     fprintf(stderr,"fxmesa: fxTexValidate(...) End\n");
-  }
+   extern void _mesa_rescale_teximage2d( GLuint bytesPerPixel,
+                                         GLuint dstRowStride,
+                                         GLint srcWidth, GLint srcHeight,
+                                         GLint dstWidth, GLint dstHeight,
+                                         const GLvoid *srcImage, GLvoid *dstImage );
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   /* [dBorca]
+    * Fake textures larger than HW supports:
+    * 1) we have mipmaps. Then we just push up to the first supported
+    *    LOD. A possible drawback is that Mesa will ignore the skipped
+    *    LODs on further texture handling.
+    *    Will this interfere with GL_TEXTURE_[MIN|BASE]_LEVEL? How?
+    * 2) we don't have mipmaps. We need to rescale the big LOD in place.
+    *    The above approach is somehow dumb! we might have rescaled
+    *    once in TexImage2D to accomodate aspect ratio, and now we
+    *    are rescaling again. The thing is, in TexImage2D we don't
+    *    know whether we'll hit 1) or 2) by the time of validation.
+    */
+   if ((tObj->MinFilter == GL_NEAREST) || (tObj->MinFilter == GL_LINEAR)) {
+      /* no mipmaps! */
+      struct gl_texture_image *texImage = tObj->Image[0][minl];
+      tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
+      GLint _w, _h, maxSize = 1 << fxMesa->textureMaxLod;
+      if ((mml->width > maxSize) || (mml->height > maxSize)) {
+         /* need to rescale */
+         GLint texelBytes = texImage->TexFormat->TexelBytes;
+         GLvoid *texImage_Data = texImage->Data;
+         _w = MIN2(texImage->Width, maxSize);
+         _h = MIN2(texImage->Height, maxSize);
+         if (TDFX_DEBUG & VERBOSE_TEXTURE) {
+            fprintf(stderr, "fxTexValidate: rescaling %d x %d -> %d x %d\n",
+                            texImage->Width, texImage->Height, _w, _h);
+         }
+         /* we should leave these as is and... (!) */
+         texImage->Width = _w;
+         texImage->Height = _h;
+         fxTexGetInfo(_w, _h, NULL, NULL, NULL, NULL,
+                      &(mml->wScale), &(mml->hScale));
+         _w *= mml->wScale;
+         _h *= mml->hScale;
+         texImage->Data = MESA_PBUFFER_ALLOC(_w * _h * texelBytes);
+         _mesa_rescale_teximage2d(texelBytes,
+                                  _w * texelBytes, /* dst stride */
+                                  mml->width, mml->height, /* src */
+                                  _w, _h, /* dst */
+                                  texImage_Data /*src*/, texImage->Data /*dst*/ );
+         MESA_PBUFFER_FREE(texImage_Data);
+         mml->width = _w;
+         mml->height = _h;
+         /* (!) ... and set mml->wScale = _w / texImage->Width */
+      }
+   } else {
+      /* mipmapping */
+      if (maxl - minl > fxMesa->textureMaxLod) {
+         /* skip a certain number of LODs */
+         minl += maxl - fxMesa->textureMaxLod;
+         if (TDFX_DEBUG & VERBOSE_TEXTURE) {
+            fprintf(stderr, "fxTexValidate: skipping %d LODs\n", minl - ti->minLevel);
+         }
+         ti->minLevel = tObj->BaseLevel = minl;
+      }
+   }
+}
+#endif
+
+   fxTexGetInfo(tObj->Image[0][minl]->Width, tObj->Image[0][minl]->Height,
+               &(FX_largeLodLog2(ti->info)), &(FX_aspectRatioLog2(ti->info)),
+               &(ti->sScale), &(ti->tScale),
+               NULL, NULL);
+
+   if ((tObj->MinFilter != GL_NEAREST) && (tObj->MinFilter != GL_LINEAR))
+      fxTexGetInfo(tObj->Image[0][maxl]->Width, tObj->Image[0][maxl]->Height,
+                  &(FX_smallLodLog2(ti->info)), NULL,
+                  NULL, NULL, NULL, NULL);
+   else
+      FX_smallLodLog2(ti->info) = FX_largeLodLog2(ti->info);
+
+   /* [dBorca] this is necessary because of fxDDCompressedTexImage2D */
+   if (ti->padded) {
+      struct gl_texture_image *texImage = tObj->Image[0][minl];
+      tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
+      if (mml->wScale != 1 || mml->hScale != 1) {
+         ti->sScale /= mml->wScale;
+         ti->tScale /= mml->hScale;
+      }
+   }
+
+   ti->baseLevelInternalFormat = tObj->Image[0][minl]->Format;
+
+   ti->validated = GL_TRUE;
+
+   ti->info.data = NULL;
 }
 
-static void fxPrintUnitsMode( const char *msg, GLuint mode )
+static void
+fxPrintUnitsMode(const char *msg, GLuint mode)
 {
-   fprintf(stderr, 
+   fprintf(stderr,
           "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
           msg,
           mode,
-          (mode & FX_UM_E0_REPLACE)         ? "E0_REPLACE, " : "",
-          (mode & FX_UM_E0_MODULATE)        ? "E0_MODULATE, " : "",
-          (mode & FX_UM_E0_DECAL)           ? "E0_DECAL, " : "",
-          (mode & FX_UM_E0_BLEND)           ? "E0_BLEND, " : "",
-          (mode & FX_UM_E1_REPLACE)         ? "E1_REPLACE, " : "",
-          (mode & FX_UM_E1_MODULATE)        ? "E1_MODULATE, " : "",
-          (mode & FX_UM_E1_DECAL)           ? "E1_DECAL, " : "",
-          (mode & FX_UM_E1_BLEND)           ? "E1_BLEND, " : "",
-          (mode & FX_UM_E0_ALPHA)           ? "E0_ALPHA, " : "",
-          (mode & FX_UM_E0_LUMINANCE)       ? "E0_LUMINANCE, " : "",
+          (mode & FX_UM_E0_REPLACE) ? "E0_REPLACE, " : "",
+          (mode & FX_UM_E0_MODULATE) ? "E0_MODULATE, " : "",
+          (mode & FX_UM_E0_DECAL) ? "E0_DECAL, " : "",
+          (mode & FX_UM_E0_BLEND) ? "E0_BLEND, " : "",
+          (mode & FX_UM_E1_REPLACE) ? "E1_REPLACE, " : "",
+          (mode & FX_UM_E1_MODULATE) ? "E1_MODULATE, " : "",
+          (mode & FX_UM_E1_DECAL) ? "E1_DECAL, " : "",
+          (mode & FX_UM_E1_BLEND) ? "E1_BLEND, " : "",
+          (mode & FX_UM_E0_ALPHA) ? "E0_ALPHA, " : "",
+          (mode & FX_UM_E0_LUMINANCE) ? "E0_LUMINANCE, " : "",
           (mode & FX_UM_E0_LUMINANCE_ALPHA) ? "E0_LUMINANCE_ALPHA, " : "",
-          (mode & FX_UM_E0_INTENSITY)       ? "E0_INTENSITY, " : "",
-          (mode & FX_UM_E0_RGB)             ? "E0_RGB, " : "",
-          (mode & FX_UM_E0_RGBA)            ? "E0_RGBA, " : "",
-          (mode & FX_UM_E1_ALPHA)           ? "E1_ALPHA, " : "",
-          (mode & FX_UM_E1_LUMINANCE)       ? "E1_LUMINANCE, " : "",
+          (mode & FX_UM_E0_INTENSITY) ? "E0_INTENSITY, " : "",
+          (mode & FX_UM_E0_RGB) ? "E0_RGB, " : "",
+          (mode & FX_UM_E0_RGBA) ? "E0_RGBA, " : "",
+          (mode & FX_UM_E1_ALPHA) ? "E1_ALPHA, " : "",
+          (mode & FX_UM_E1_LUMINANCE) ? "E1_LUMINANCE, " : "",
           (mode & FX_UM_E1_LUMINANCE_ALPHA) ? "E1_LUMINANCE_ALPHA, " : "",
-          (mode & FX_UM_E1_INTENSITY)       ? "E1_INTENSITY, " : "",
-          (mode & FX_UM_E1_RGB)             ? "E1_RGB, " : "",
-          (mode & FX_UM_E1_RGBA)            ? "E1_RGBA, " : "",
-          (mode & FX_UM_COLOR_ITERATED)     ? "COLOR_ITERATED, " : "",
-          (mode & FX_UM_COLOR_CONSTANT)     ? "COLOR_CONSTANT, " : "",
-          (mode & FX_UM_ALPHA_ITERATED)     ? "ALPHA_ITERATED, " : "",
-          (mode & FX_UM_ALPHA_CONSTANT)     ? "ALPHA_CONSTANT, " : "");
+          (mode & FX_UM_E1_INTENSITY) ? "E1_INTENSITY, " : "",
+          (mode & FX_UM_E1_RGB) ? "E1_RGB, " : "",
+          (mode & FX_UM_E1_RGBA) ? "E1_RGBA, " : "",
+          (mode & FX_UM_COLOR_ITERATED) ? "COLOR_ITERATED, " : "",
+          (mode & FX_UM_COLOR_CONSTANT) ? "COLOR_CONSTANT, " : "",
+          (mode & FX_UM_ALPHA_ITERATED) ? "ALPHA_ITERATED, " : "",
+          (mode & FX_UM_ALPHA_CONSTANT) ? "ALPHA_CONSTANT, " : "");
 }
 
-static GLuint fxGetTexSetConfiguration(GLcontext *ctx,
-                                      struct gl_texture_object *tObj0,
-                                      struct gl_texture_object *tObj1)
+static GLuint
+fxGetTexSetConfiguration(GLcontext * ctx,
+                        struct gl_texture_object *tObj0,
+                        struct gl_texture_object *tObj1)
 {
-  GLuint unitsmode=0;
-  GLuint envmode=0;
-  GLuint ifmt=0;
-
-  if((ctx->Light.ShadeModel==GL_SMOOTH) ||
-     (ctx->Point.SmoothFlag) ||
-     (ctx->Line.SmoothFlag) ||
-     (ctx->Polygon.SmoothFlag))
-    unitsmode|=FX_UM_ALPHA_ITERATED;
-  else
-    unitsmode|=FX_UM_ALPHA_CONSTANT;
-
-  if(ctx->Light.ShadeModel==GL_SMOOTH)
-    unitsmode|=FX_UM_COLOR_ITERATED;
-  else
-    unitsmode|=FX_UM_COLOR_CONSTANT;
-
-  /* 
-     OpenGL Feeds Texture 0 into Texture 1
-     Glide Feeds Texture 1 into Texture 0
-  */
-  if(tObj0) {
-    tfxTexInfo *ti0=fxTMGetTexInfo(tObj0);
-
-    switch(ti0->baseLevelInternalFormat) {
-    case GL_ALPHA:
-      ifmt|=FX_UM_E0_ALPHA;
-      break;
-    case GL_LUMINANCE:
-      ifmt|=FX_UM_E0_LUMINANCE;
-      break;
-    case GL_LUMINANCE_ALPHA:
-      ifmt|=FX_UM_E0_LUMINANCE_ALPHA;
-      break;
-    case GL_INTENSITY:
-      ifmt|=FX_UM_E0_INTENSITY;
-      break;
-    case GL_RGB:
-      ifmt|=FX_UM_E0_RGB;
-      break;
-    case GL_RGBA:
-      ifmt|=FX_UM_E0_RGBA;
-      break;
-    }
-
-    switch(ctx->Texture.Unit[0].EnvMode) {
-    case GL_DECAL:
-      envmode|=FX_UM_E0_DECAL;
-      break;
-    case GL_MODULATE:
-      envmode|=FX_UM_E0_MODULATE;
-      break;
-    case GL_REPLACE:
-      envmode|=FX_UM_E0_REPLACE;
-      break;
-    case GL_BLEND:
-      envmode|=FX_UM_E0_BLEND;
-      break;
-    case GL_ADD:
-      envmode|=FX_UM_E0_ADD;
-      break;
-    default:
-      /* do nothing */
-      break;
-    }
-  }
+   GLuint unitsmode = 0;
+   GLuint envmode = 0;
+   GLuint ifmt = 0;
+
+   if ((ctx->Light.ShadeModel == GL_SMOOTH) || 1 ||
+       (ctx->Point.SmoothFlag) ||
+       (ctx->Line.SmoothFlag) ||
+       (ctx->Polygon.SmoothFlag)) unitsmode |= FX_UM_ALPHA_ITERATED;
+   else
+      unitsmode |= FX_UM_ALPHA_CONSTANT;
+
+   if (ctx->Light.ShadeModel == GL_SMOOTH || 1)
+      unitsmode |= FX_UM_COLOR_ITERATED;
+   else
+      unitsmode |= FX_UM_COLOR_CONSTANT;
+
+
+
+   /* 
+      OpenGL Feeds Texture 0 into Texture 1
+      Glide Feeds Texture 1 into Texture 0
+    */
+   if (tObj0) {
+      tfxTexInfo *ti0 = fxTMGetTexInfo(tObj0);
+
+      switch (ti0->baseLevelInternalFormat) {
+      case GL_ALPHA:
+        ifmt |= FX_UM_E0_ALPHA;
+        break;
+      case GL_LUMINANCE:
+        ifmt |= FX_UM_E0_LUMINANCE;
+        break;
+      case GL_LUMINANCE_ALPHA:
+        ifmt |= FX_UM_E0_LUMINANCE_ALPHA;
+        break;
+      case GL_INTENSITY:
+        ifmt |= FX_UM_E0_INTENSITY;
+        break;
+      case GL_RGB:
+        ifmt |= FX_UM_E0_RGB;
+        break;
+      case GL_RGBA:
+        ifmt |= FX_UM_E0_RGBA;
+        break;
+      }
 
-  if(tObj1) {
-    tfxTexInfo *ti1=fxTMGetTexInfo(tObj1);
+      switch (ctx->Texture.Unit[0].EnvMode) {
+      case GL_DECAL:
+        envmode |= FX_UM_E0_DECAL;
+        break;
+      case GL_MODULATE:
+        envmode |= FX_UM_E0_MODULATE;
+        break;
+      case GL_REPLACE:
+        envmode |= FX_UM_E0_REPLACE;
+        break;
+      case GL_BLEND:
+        envmode |= FX_UM_E0_BLEND;
+        break;
+      case GL_ADD:
+        envmode |= FX_UM_E0_ADD;
+        break;
+      default:
+        /* do nothing */
+        break;
+      }
+   }
 
-    switch(ti1->baseLevelInternalFormat) {
-    case GL_ALPHA:
-      ifmt|=FX_UM_E1_ALPHA;
-      break;
-    case GL_LUMINANCE:
-      ifmt|=FX_UM_E1_LUMINANCE;
-      break;
-    case GL_LUMINANCE_ALPHA:
-      ifmt|=FX_UM_E1_LUMINANCE_ALPHA;
-      break;
-    case GL_INTENSITY:
-      ifmt|=FX_UM_E1_INTENSITY;
-      break;
-    case GL_RGB:
-      ifmt|=FX_UM_E1_RGB;
-      break;
-    case GL_RGBA:
-      ifmt|=FX_UM_E1_RGBA;
-      break;
-    default:
-      /* do nothing */
-      break;
-    }
+   if (tObj1) {
+      tfxTexInfo *ti1 = fxTMGetTexInfo(tObj1);
+
+      switch (ti1->baseLevelInternalFormat) {
+      case GL_ALPHA:
+        ifmt |= FX_UM_E1_ALPHA;
+        break;
+      case GL_LUMINANCE:
+        ifmt |= FX_UM_E1_LUMINANCE;
+        break;
+      case GL_LUMINANCE_ALPHA:
+        ifmt |= FX_UM_E1_LUMINANCE_ALPHA;
+        break;
+      case GL_INTENSITY:
+        ifmt |= FX_UM_E1_INTENSITY;
+        break;
+      case GL_RGB:
+        ifmt |= FX_UM_E1_RGB;
+        break;
+      case GL_RGBA:
+        ifmt |= FX_UM_E1_RGBA;
+        break;
+      default:
+        /* do nothing */
+        break;
+      }
 
-    switch(ctx->Texture.Unit[1].EnvMode) {
-    case GL_DECAL:
-      envmode|=FX_UM_E1_DECAL;
-      break;
-    case GL_MODULATE:
-      envmode|=FX_UM_E1_MODULATE;
-      break;
-    case GL_REPLACE:
-      envmode|=FX_UM_E1_REPLACE;
-      break;
-    case GL_BLEND:
-      envmode|=FX_UM_E1_BLEND;
-      break;
-    case GL_ADD:
-      envmode|=FX_UM_E1_ADD;
-      break;
-    default:
-      /* do nothing */
-      break;
-    }
-  }
+      switch (ctx->Texture.Unit[1].EnvMode) {
+      case GL_DECAL:
+        envmode |= FX_UM_E1_DECAL;
+        break;
+      case GL_MODULATE:
+        envmode |= FX_UM_E1_MODULATE;
+        break;
+      case GL_REPLACE:
+        envmode |= FX_UM_E1_REPLACE;
+        break;
+      case GL_BLEND:
+        envmode |= FX_UM_E1_BLEND;
+        break;
+      case GL_ADD:
+        envmode |= FX_UM_E1_ADD;
+        break;
+      default:
+        /* do nothing */
+        break;
+      }
+   }
 
-  unitsmode|=(ifmt | envmode);
+   unitsmode |= (ifmt | envmode);
 
-  if (MESA_VERBOSE & (VERBOSE_DRIVER|VERBOSE_TEXTURE)) 
-     fxPrintUnitsMode("unitsmode", unitsmode);
+   if (TDFX_DEBUG & (VERBOSE_DRIVER | VERBOSE_TEXTURE))
+      fxPrintUnitsMode("fxGetTexSetConfiguration", unitsmode);
 
-  return unitsmode;
+   return unitsmode;
 }
 
 /************************************************************************/
@@ -311,307 +332,428 @@ static GLuint fxGetTexSetConfiguration(GLcontext *ctx,
 
 /************************* Single Texture Set ***************************/
 
-static void fxSetupSingleTMU_NoLock(fxMesaContext fxMesa, struct gl_texture_object *tObj)
+static void
+fxSetupSingleTMU_NoLock(fxMesaContext fxMesa, struct gl_texture_object *tObj)
 {
-  tfxTexInfo *ti=fxTMGetTexInfo(tObj);
-  int tmu;
-
-  /* Make sure we're not loaded incorrectly */
-  if (ti->isInTM) {
-    if (ti->LODblend) {
-      if (ti->whichTMU!=FX_TMU_SPLIT)
-       fxTMMoveOutTM(fxMesa, tObj);
-    } else {
-      if (ti->whichTMU==FX_TMU_SPLIT)
-       fxTMMoveOutTM(fxMesa, tObj);
-    }
-  }
-
-  /* Make sure we're loaded correctly */
-  if (!ti->isInTM) {
-    if (ti->LODblend)
-      fxTMMoveInTM_NoLock(fxMesa,tObj,FX_TMU_SPLIT);
-    else {
-      if (fxMesa->haveTwoTMUs) {
-       if (fxMesa->freeTexMem[FX_TMU0] >
-           FX_grTexTextureMemRequired_NoLock(GR_MIPMAPLEVELMASK_BOTH,
-                                             &(ti->info))) {
-         fxTMMoveInTM_NoLock(fxMesa,tObj, FX_TMU0);
-       } else {
-         fxTMMoveInTM_NoLock(fxMesa,tObj, FX_TMU1);
-       }
-      } else
-       fxTMMoveInTM_NoLock(fxMesa,tObj,FX_TMU0);
-    }
-  }
-
-  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");
-       }
-      FX_grTexDownloadTable_NoLock(GR_TMU0,GR_TEXTABLE_PALETTE,&(ti->palette));
-      FX_grTexDownloadTable_NoLock(GR_TMU1,GR_TEXTABLE_PALETTE,&(ti->palette));
-    }
+   tfxTexInfo *ti = fxTMGetTexInfo(tObj);
+   int tmu;
 
-    FX_grTexClampMode_NoLock(GR_TMU0,ti->sClamp,ti->tClamp);
-    FX_grTexClampMode_NoLock(GR_TMU1,ti->sClamp,ti->tClamp);
-    FX_grTexFilterMode_NoLock(GR_TMU0,ti->minFilt,ti->maxFilt);
-    FX_grTexFilterMode_NoLock(GR_TMU1,ti->minFilt,ti->maxFilt);
-    FX_grTexMipMapMode_NoLock(GR_TMU0,ti->mmMode,ti->LODblend);
-    FX_grTexMipMapMode_NoLock(GR_TMU1,ti->mmMode,ti->LODblend);
-
-    FX_grTexSource_NoLock(GR_TMU0,ti->tm[FX_TMU0]->startAddr,
-                         GR_MIPMAPLEVELMASK_ODD,&(ti->info));
-    FX_grTexSource_NoLock(GR_TMU1,ti->tm[FX_TMU1]->startAddr,
-                         GR_MIPMAPLEVELMASK_EVEN,&(ti->info));
-  } else {
-    if (ti->whichTMU==FX_TMU_BOTH) tmu=FX_TMU0;
-    else tmu=ti->whichTMU;
-
-    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(tmu, GR_TEXTABLE_PALETTE, &(ti->palette));
-    }
+   if (TDFX_DEBUG & VERBOSE_DRIVER) {
+      fprintf(stderr, "fxSetupSingleTMU_NoLock(%p (%d))\n", (void *)tObj, tObj->Name);
+   }
+
+   ti->lastTimeUsed = fxMesa->texBindNumber;
+
+   /* Make sure we're not loaded incorrectly */
+   if (ti->isInTM) {
+      if (ti->LODblend) {
+        if (ti->whichTMU != FX_TMU_SPLIT)
+           fxTMMoveOutTM(fxMesa, tObj);
+      }
+      else {
+        if (ti->whichTMU == FX_TMU_SPLIT)
+           fxTMMoveOutTM(fxMesa, tObj);
+      }
+   }
+
+   /* Make sure we're loaded correctly */
+   if (!ti->isInTM) {
+      if (ti->LODblend)
+        fxTMMoveInTM_NoLock(fxMesa, tObj, FX_TMU_SPLIT);
+      else {
+        if (fxMesa->haveTwoTMUs) {
+            if (fxTMCheckStartAddr(fxMesa, FX_TMU0, ti)) {
+              fxTMMoveInTM_NoLock(fxMesa, tObj, FX_TMU0);
+           }
+           else {
+              fxTMMoveInTM_NoLock(fxMesa, tObj, FX_TMU1);
+           }
+        }
+        else
+           fxTMMoveInTM_NoLock(fxMesa, tObj, FX_TMU0);
+      }
+   }
+
+   if (ti->LODblend && ti->whichTMU == FX_TMU_SPLIT) {
+      /* broadcast */
+      if ((ti->info.format == GR_TEXFMT_P_8)
+         && (!fxMesa->haveGlobalPaletteTexture)) {
+        if (TDFX_DEBUG & VERBOSE_DRIVER) {
+           fprintf(stderr, "fxSetupSingleTMU_NoLock: uploading texture palette\n");
+        }
+        grTexDownloadTable(ti->paltype, &(ti->palette));
+      }
+#if FX_TC_NCC
+      if ((ti->info.format == GR_TEXFMT_AYIQ_8422) ||
+          (ti->info.format == GR_TEXFMT_YIQ_422)) {
+        if (TDFX_DEBUG & VERBOSE_DRIVER) {
+           fprintf(stderr, "fxSetupSingleTMU_NoLock: uploading NCC table\n");
+        }
+        grTexDownloadTable(GR_TEXTABLE_NCC0, &(ti->palette));
+      }
+#endif
+
+      grTexClampMode(GR_TMU0, ti->sClamp, ti->tClamp);
+      grTexClampMode(GR_TMU1, ti->sClamp, ti->tClamp);
+      grTexFilterMode(GR_TMU0, ti->minFilt, ti->maxFilt);
+      grTexFilterMode(GR_TMU1, ti->minFilt, ti->maxFilt);
+      grTexMipMapMode(GR_TMU0, ti->mmMode, ti->LODblend);
+      grTexMipMapMode(GR_TMU1, ti->mmMode, ti->LODblend);
+
+      grTexSource(GR_TMU0, ti->tm[FX_TMU0]->startAddr,
+                           GR_MIPMAPLEVELMASK_ODD, &(ti->info));
+      grTexSource(GR_TMU1, ti->tm[FX_TMU1]->startAddr,
+                           GR_MIPMAPLEVELMASK_EVEN, &(ti->info));
+   }
+   else {
+      if (ti->whichTMU == FX_TMU_BOTH)
+        tmu = FX_TMU0;
+      else
+        tmu = ti->whichTMU;
 
-    /* KW: The alternative is to do the download to the other tmu.  If
-     * we get to this point, I think it means we are thrashing the
-     * texture memory, so perhaps it's not a good idea.  
-     */
-    if (ti->LODblend && (MESA_VERBOSE&VERBOSE_DRIVER))
-       fprintf(stderr, "fxmesa: not blending texture - only on one tmu\n");
+      /* pointcast */
+      if ((ti->info.format == GR_TEXFMT_P_8)
+         && (!fxMesa->haveGlobalPaletteTexture)) {
+        if (TDFX_DEBUG & VERBOSE_DRIVER) {
+           fprintf(stderr, "fxSetupSingleTMU_NoLock: uploading texture palette\n");
+        }
+        fxMesa->Glide.grTexDownloadTableExt(tmu, ti->paltype, &(ti->palette));
+      }
+#if FX_TC_NCC
+      if ((ti->info.format == GR_TEXFMT_AYIQ_8422) ||
+          (ti->info.format == GR_TEXFMT_YIQ_422)) {
+        if (TDFX_DEBUG & VERBOSE_DRIVER) {
+           fprintf(stderr, "fxSetupSingleTMU_NoLock: uploading NCC table\n");
+        }
+        fxMesa->Glide.grTexDownloadTableExt(tmu, GR_TEXTABLE_NCC0, &(ti->palette));
+      }
+#endif
+
+      /* KW: The alternative is to do the download to the other tmu.  If
+       * we get to this point, I think it means we are thrashing the
+       * texture memory, so perhaps it's not a good idea.  
+       */
+      if (ti->LODblend && (TDFX_DEBUG & VERBOSE_DRIVER)) {
+        fprintf(stderr, "fxSetupSingleTMU_NoLock: not blending texture - only one tmu\n");
+      }
 
-    FX_grTexClampMode_NoLock(tmu, ti->sClamp, ti->tClamp);
-    FX_grTexFilterMode_NoLock(tmu, ti->minFilt, ti->maxFilt);
-    FX_grTexMipMapMode_NoLock(tmu, ti->mmMode, FXFALSE);
+      grTexClampMode(tmu, ti->sClamp, ti->tClamp);
+      grTexFilterMode(tmu, ti->minFilt, ti->maxFilt);
+      grTexMipMapMode(tmu, ti->mmMode, FXFALSE);
 
-    FX_grTexSource_NoLock(tmu, ti->tm[tmu]->startAddr,
-                         GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
-  }
+      grTexSource(tmu, ti->tm[tmu]->startAddr, GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
+   }
 }
 
-static void fxSelectSingleTMUSrc_NoLock(fxMesaContext fxMesa, GLint tmu, 
-                                       FxBool LODblend)
+static void
+fxSelectSingleTMUSrc_NoLock(fxMesaContext fxMesa, GLint tmu, FxBool LODblend)
 {
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
-    fprintf(stderr,"fxmesa: fxSelectSingleTMUSrc(%d,%d)\n",tmu,LODblend);
-  }
-
-  if (LODblend) {
-    FX_grTexCombine_NoLock(GR_TMU0,
-                          GR_COMBINE_FUNCTION_BLEND,
-                          GR_COMBINE_FACTOR_ONE_MINUS_LOD_FRACTION,
-                          GR_COMBINE_FUNCTION_BLEND,
-                          GR_COMBINE_FACTOR_ONE_MINUS_LOD_FRACTION,
-                          FXFALSE,FXFALSE);
-
-    if (fxMesa->haveTwoTMUs)
-      FX_grTexCombine_NoLock(GR_TMU1,
-                            GR_COMBINE_FUNCTION_LOCAL,GR_COMBINE_FACTOR_NONE,
-                            GR_COMBINE_FUNCTION_LOCAL,GR_COMBINE_FACTOR_NONE,
-                            FXFALSE,FXFALSE);
-    fxMesa->tmuSrc=FX_TMU_SPLIT;
-  }
-  else {
-    if (tmu!=FX_TMU1) {
-      FX_grTexCombine_NoLock(GR_TMU0,
-                            GR_COMBINE_FUNCTION_LOCAL,GR_COMBINE_FACTOR_NONE,
-                            GR_COMBINE_FUNCTION_LOCAL,GR_COMBINE_FACTOR_NONE,
-                            FXFALSE,FXFALSE);
-      if (fxMesa->haveTwoTMUs) {
-        FX_grTexCombine_NoLock(GR_TMU1,
-                               GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_NONE,
-                               GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_NONE,
-                               FXFALSE,FXFALSE);
-      }
-      fxMesa->tmuSrc=FX_TMU0;
-    }
-    else {
-      FX_grTexCombine_NoLock(GR_TMU1,
-                            GR_COMBINE_FUNCTION_LOCAL,GR_COMBINE_FACTOR_NONE,
-                            GR_COMBINE_FUNCTION_LOCAL,GR_COMBINE_FACTOR_NONE,
-                            FXFALSE,FXFALSE);
-
-      /* GR_COMBINE_FUNCTION_SCALE_OTHER doesn't work ?!? */
-
-      FX_grTexCombine_NoLock(GR_TMU0,
-                            GR_COMBINE_FUNCTION_BLEND,
-                            GR_COMBINE_FACTOR_ONE,
-                            GR_COMBINE_FUNCTION_BLEND,
-                            GR_COMBINE_FACTOR_ONE,
-                            FXFALSE,FXFALSE);
-
-      fxMesa->tmuSrc=FX_TMU1;
-    }
-  }
+   struct tdfx_texcombine tex0, tex1;
+
+   if (TDFX_DEBUG & VERBOSE_DRIVER) {
+      fprintf(stderr, "fxSelectSingleTMUSrc_NoLock(%d, %d)\n", tmu, LODblend);
+   }
+
+   tex0.InvertRGB     = FXFALSE;
+   tex0.InvertAlpha   = FXFALSE;
+   tex1.InvertRGB     = FXFALSE;
+   tex1.InvertAlpha   = FXFALSE;
+
+   if (LODblend) {
+      tex0.FunctionRGB   = GR_COMBINE_FUNCTION_BLEND;
+      tex0.FactorRGB     = GR_COMBINE_FACTOR_ONE_MINUS_LOD_FRACTION;
+      tex0.FunctionAlpha = GR_COMBINE_FUNCTION_BLEND;
+      tex0.FactorAlpha   = GR_COMBINE_FACTOR_ONE_MINUS_LOD_FRACTION;
+
+      tex1.FunctionRGB   = GR_COMBINE_FUNCTION_LOCAL;
+      tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+      tex1.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+      tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+
+      fxMesa->tmuSrc = FX_TMU_SPLIT;
+   }
+   else {
+      if (tmu != FX_TMU1) {
+         tex0.FunctionRGB   = GR_COMBINE_FUNCTION_LOCAL;
+         tex0.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+         tex0.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         tex0.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+
+         tex1.FunctionRGB   = GR_COMBINE_FUNCTION_ZERO;
+         tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+         tex1.FunctionAlpha = GR_COMBINE_FUNCTION_ZERO;
+         tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+
+        fxMesa->tmuSrc = FX_TMU0;
+      }
+      else {
+         tex1.FunctionRGB   = GR_COMBINE_FUNCTION_LOCAL;
+         tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+         tex1.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+
+        /* correct values to set TMU0 in passthrough mode */
+         tex0.FunctionRGB   = GR_COMBINE_FUNCTION_BLEND;
+         tex0.FactorRGB     = GR_COMBINE_FACTOR_ONE;
+         tex0.FunctionAlpha = GR_COMBINE_FUNCTION_BLEND;
+         tex0.FactorAlpha   = GR_COMBINE_FACTOR_ONE;
+
+        fxMesa->tmuSrc = FX_TMU1;
+      }
+   }
+
+   grTexCombine(GR_TMU0,
+                tex0.FunctionRGB,
+                tex0.FactorRGB,
+                tex0.FunctionAlpha,
+                tex0.FactorAlpha,
+                tex0.InvertRGB,
+                tex0.InvertAlpha);
+   if (fxMesa->haveTwoTMUs) {
+      grTexCombine(GR_TMU1,
+                   tex1.FunctionRGB,
+                   tex1.FactorRGB,
+                   tex1.FunctionAlpha,
+                   tex1.FactorAlpha,
+                   tex1.InvertRGB,
+                   tex1.InvertAlpha);
+   }
 }
 
-static void fxSetupTextureSingleTMU_NoLock(GLcontext *ctx, GLuint textureset)
+static void
+fxSetupTextureSingleTMU_NoLock(GLcontext * ctx, GLuint textureset)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  GrCombineLocal_t localc,locala;
-  GLuint unitsmode;
-  GLint ifmt;
-  tfxTexInfo *ti;
-  struct gl_texture_object *tObj=ctx->Texture.Unit[textureset].CurrentD[2];
-  int tmu;
-
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
-     fprintf(stderr,"fxmesa: fxSetupTextureSingleTMU(...) Start\n");
-  }
-
-  ti=fxTMGetTexInfo(tObj);
-
-  fxTexValidate(ctx,tObj);
-
-  fxSetupSingleTMU_NoLock(fxMesa,tObj);
-
-  if (ti->whichTMU==FX_TMU_BOTH) tmu=FX_TMU0;
-  else tmu=ti->whichTMU;
-  if (fxMesa->tmuSrc!=tmu)
-    fxSelectSingleTMUSrc_NoLock(fxMesa, tmu, ti->LODblend);
-
-  if(textureset==0 || !fxMesa->haveTwoTMUs)
-    unitsmode=fxGetTexSetConfiguration(ctx,tObj,NULL);
-  else
-    unitsmode=fxGetTexSetConfiguration(ctx,NULL,tObj);
-
-  if(fxMesa->lastUnitsMode==unitsmode)
-    return;
-
-  fxMesa->lastUnitsMode=unitsmode;
-
-  fxMesa->stw_hint_state = 0;
-  FX_grHints_NoLock(GR_HINT_STWHINT,0);
-
-  ifmt=ti->baseLevelInternalFormat;
-
-  if(unitsmode & FX_UM_ALPHA_ITERATED)
-    locala=GR_COMBINE_LOCAL_ITERATED;
-  else
-    locala=GR_COMBINE_LOCAL_CONSTANT;
-
-  if(unitsmode & FX_UM_COLOR_ITERATED)
-    localc=GR_COMBINE_LOCAL_ITERATED;
-  else
-    localc=GR_COMBINE_LOCAL_CONSTANT;
-
-  if (MESA_VERBOSE & (VERBOSE_DRIVER|VERBOSE_TEXTURE))
-     fprintf(stderr, "fxMesa: fxSetupTextureSingleTMU, envmode is %s\n",
-            gl_lookup_enum_by_nr(ctx->Texture.Unit[textureset].EnvMode));
-
-  switch(ctx->Texture.Unit[textureset].EnvMode) {
-  case GL_DECAL:
-    FX_grAlphaCombine_NoLock(GR_COMBINE_FUNCTION_LOCAL,
-                            GR_COMBINE_FACTOR_NONE,
-                            locala,
-                            GR_COMBINE_OTHER_NONE,
-                            FXFALSE);
-
-    FX_grColorCombine_NoLock(GR_COMBINE_FUNCTION_BLEND,
-                            GR_COMBINE_FACTOR_TEXTURE_ALPHA,
-                            localc,
-                            GR_COMBINE_OTHER_TEXTURE,
-                            FXFALSE);
-    break;
-  case GL_MODULATE:
-    FX_grAlphaCombine_NoLock(GR_COMBINE_FUNCTION_SCALE_OTHER,
-                            GR_COMBINE_FACTOR_LOCAL,
-                            locala,
-                            GR_COMBINE_OTHER_TEXTURE,
-                            FXFALSE);
-
-    if(ifmt==GL_ALPHA)
-      FX_grColorCombine_NoLock(GR_COMBINE_FUNCTION_LOCAL,
-                              GR_COMBINE_FACTOR_NONE,
-                              localc,
-                              GR_COMBINE_OTHER_NONE,
-                              FXFALSE);
-    else
-      FX_grColorCombine_NoLock(GR_COMBINE_FUNCTION_SCALE_OTHER,
-                              GR_COMBINE_FACTOR_LOCAL,
-                              localc,
-                              GR_COMBINE_OTHER_TEXTURE,
-                              FXFALSE);
-    break;
-  case GL_BLEND:
-#if 0
-    FX_grAlphaCombine_NoLock(GR_COMBINE_FUNCTION_SCALE_OTHER,
-                            GR_COMBINE_FACTOR_LOCAL,
-                            locala,
-                            GR_COMBINE_OTHER_TEXTURE,
-                            FXFALSE);
-    if (ifmt==GL_ALPHA)
-      FX_grColorCombine_NoLock(GR_COMBINE_FUNCTION_LOCAL,
-                              GR_COMBINE_FACTOR_NONE,
-                              localc,
-                              GR_COMBINE_OTHER_NONE,
-                              FXFALSE);
-    else
-      FX_grColorCombine_NoLock(GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL,
-                              GR_COMBINE_FACTOR_LOCAL,
-                              localc,
-                              GR_COMBINE_OTHER_TEXTURE,
-                              FXTRUE);
-    ctx->Driver.MultipassFunc = fxMultipassBlend;
-#else
-#ifndef FX_SILENT
-    fprintf(stderr,"fx Driver: GL_BLEND not yet supported\n");
-#endif
-#endif    
-    break;
-  case GL_REPLACE:
-    if((ifmt==GL_RGB) || (ifmt==GL_LUMINANCE))
-      FX_grAlphaCombine_NoLock(GR_COMBINE_FUNCTION_LOCAL,
-                              GR_COMBINE_FACTOR_NONE,
-                              locala,
-                              GR_COMBINE_OTHER_NONE,
-                              FXFALSE);
-    else
-      FX_grAlphaCombine_NoLock(GR_COMBINE_FUNCTION_SCALE_OTHER,
-                              GR_COMBINE_FACTOR_ONE,
-                              locala,
-                              GR_COMBINE_OTHER_TEXTURE,
-                              FXFALSE);
-    
-    if(ifmt==GL_ALPHA)
-      FX_grColorCombine_NoLock(GR_COMBINE_FUNCTION_LOCAL,
-                              GR_COMBINE_FACTOR_NONE,
-                              localc,
-                              GR_COMBINE_OTHER_NONE,
-                              FXFALSE);
-    else
-      FX_grColorCombine_NoLock(GR_COMBINE_FUNCTION_SCALE_OTHER,
-                              GR_COMBINE_FACTOR_ONE,
-                              localc,
-                              GR_COMBINE_OTHER_TEXTURE,
-                              FXFALSE);
-    break;
-  default:
-#ifndef FX_SILENT
-    fprintf(stderr,"fx Driver: %x Texture.EnvMode not yet supported\n",ctx->Texture.Unit[textureset].EnvMode);
-#endif
-    break;
-  }
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   struct tdfx_combine alphaComb, colorComb;
+   GrCombineLocal_t localc, locala;
+   GLuint unitsmode;
+   GLint ifmt;
+   tfxTexInfo *ti;
+   struct gl_texture_object *tObj = ctx->Texture.Unit[textureset]._Current;
+   int tmu;
+
+   if (TDFX_DEBUG & VERBOSE_DRIVER) {
+      fprintf(stderr, "fxSetupTextureSingleTMU_NoLock(%d)\n", textureset);
+   }
+
+   ti = fxTMGetTexInfo(tObj);
+
+   fxTexValidate(ctx, tObj);
+
+   fxSetupSingleTMU_NoLock(fxMesa, tObj);
+
+   if (ti->whichTMU == FX_TMU_BOTH)
+      tmu = FX_TMU0;
+   else
+      tmu = ti->whichTMU;
+   if (fxMesa->tmuSrc != tmu)
+      fxSelectSingleTMUSrc_NoLock(fxMesa, tmu, ti->LODblend);
+
+   if (textureset == 0 || !fxMesa->haveTwoTMUs)
+      unitsmode = fxGetTexSetConfiguration(ctx, tObj, NULL);
+   else
+      unitsmode = fxGetTexSetConfiguration(ctx, NULL, tObj);
+
+/*    if(fxMesa->lastUnitsMode==unitsmode) */
+/*      return; */
+
+   fxMesa->lastUnitsMode = unitsmode;
+
+   fxMesa->stw_hint_state = 0;
+   FX_grHints_NoLock(GR_HINT_STWHINT, 0);
+
+   ifmt = ti->baseLevelInternalFormat;
+
+   if (unitsmode & FX_UM_ALPHA_ITERATED)
+      locala = GR_COMBINE_LOCAL_ITERATED;
+   else
+      locala = GR_COMBINE_LOCAL_CONSTANT;
+
+   if (unitsmode & FX_UM_COLOR_ITERATED)
+      localc = GR_COMBINE_LOCAL_ITERATED;
+   else
+      localc = GR_COMBINE_LOCAL_CONSTANT;
+
+   if (TDFX_DEBUG & (VERBOSE_DRIVER | VERBOSE_TEXTURE))
+      fprintf(stderr, "fxSetupTextureSingleTMU_NoLock: envmode is %s\n",
+             _mesa_lookup_enum_by_nr(ctx->Texture.Unit[textureset].EnvMode));
+
+   alphaComb.Local    = locala;
+   alphaComb.Invert   = FXFALSE;
+   colorComb.Local    = localc;
+   colorComb.Invert   = FXFALSE;
+
+   switch (ctx->Texture.Unit[textureset].EnvMode) {
+   case GL_DECAL:
+      alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+      alphaComb.Factor   = GR_COMBINE_FACTOR_NONE;
+      alphaComb.Other    = GR_COMBINE_OTHER_NONE;
+
+      colorComb.Function = GR_COMBINE_FUNCTION_BLEND;
+      colorComb.Factor   = GR_COMBINE_FACTOR_TEXTURE_ALPHA;
+      colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+      break;
+   case GL_MODULATE:
+      alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+      alphaComb.Factor   = GR_COMBINE_FACTOR_LOCAL;
+      alphaComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+
+      if (ifmt == GL_ALPHA) {
+         colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         colorComb.Factor   = GR_COMBINE_FACTOR_NONE;
+         colorComb.Other    = GR_COMBINE_OTHER_NONE;
+      } else {
+         colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         colorComb.Factor   = GR_COMBINE_FACTOR_LOCAL;
+         colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+      }
+      break;
+   case GL_BLEND:
+      if (ifmt == GL_LUMINANCE || ifmt == GL_RGB) {
+         /* Av = Af */
+         alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         alphaComb.Factor   = GR_COMBINE_FACTOR_NONE;
+         alphaComb.Other    = GR_COMBINE_OTHER_NONE;
+      }
+      else if (ifmt == GL_INTENSITY) {
+         /* Av = Af * (1 - It) + Ac * It */
+         alphaComb.Function = GR_COMBINE_FUNCTION_BLEND;
+         alphaComb.Factor   = GR_COMBINE_FACTOR_TEXTURE_ALPHA;
+         alphaComb.Other    = GR_COMBINE_OTHER_CONSTANT;
+      }
+      else {
+         /* Av = Af * At */
+         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         alphaComb.Factor   = GR_COMBINE_FACTOR_LOCAL;
+         alphaComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+      }
 
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
-     fprintf(stderr,"fxmesa: fxSetupTextureSingleTMU(...) End\n");
-  }
+      if (ifmt == GL_ALPHA) {
+         colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         colorComb.Factor   = GR_COMBINE_FACTOR_NONE;
+         colorComb.Other    = GR_COMBINE_OTHER_NONE;
+      } else {
+         if (fxMesa->type >= GR_SSTTYPE_Voodoo2) {
+            colorComb.Function = GR_COMBINE_FUNCTION_BLEND;
+            colorComb.Factor   = GR_COMBINE_FACTOR_TEXTURE_RGB;
+            colorComb.Other    = GR_COMBINE_OTHER_CONSTANT;
+         } else if (ifmt == GL_INTENSITY) {
+            /* just a hack: RGB == ALPHA */
+            colorComb.Function = GR_COMBINE_FUNCTION_BLEND;
+            colorComb.Factor   = GR_COMBINE_FACTOR_TEXTURE_ALPHA;
+            colorComb.Other    = GR_COMBINE_OTHER_CONSTANT;
+         } else {
+            /* Only Voodoo^2 can GL_BLEND (GR_COMBINE_FACTOR_TEXTURE_RGB)
+             * These settings assume that the TexEnv color is black and
+             * incoming fragment color is white.
+             */
+            colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+            colorComb.Factor   = GR_COMBINE_FACTOR_ONE;
+            colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+            colorComb.Invert   = FXTRUE;
+            _mesa_problem(NULL, "can't GL_BLEND with SST1");
+         }
+      }
+
+      grConstantColorValue(
+         (((GLuint)(ctx->Texture.Unit[textureset].EnvColor[0] * 255.0f))      ) |
+         (((GLuint)(ctx->Texture.Unit[textureset].EnvColor[1] * 255.0f)) <<  8) |
+         (((GLuint)(ctx->Texture.Unit[textureset].EnvColor[2] * 255.0f)) << 16) |
+         (((GLuint)(ctx->Texture.Unit[textureset].EnvColor[3] * 255.0f)) << 24));
+      break;
+   case GL_REPLACE:
+      if ((ifmt == GL_RGB) || (ifmt == GL_LUMINANCE)) {
+         alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         alphaComb.Factor   = GR_COMBINE_FACTOR_NONE;
+         alphaComb.Other    = GR_COMBINE_OTHER_NONE;
+      } else {
+         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         alphaComb.Factor   = GR_COMBINE_FACTOR_ONE;
+         alphaComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+      }
+
+      if (ifmt == GL_ALPHA) {
+         colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         colorComb.Factor   = GR_COMBINE_FACTOR_NONE;
+         colorComb.Other    = GR_COMBINE_OTHER_NONE;
+      } else {
+         colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         colorComb.Factor   = GR_COMBINE_FACTOR_ONE;
+         colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+      }
+      break;
+   case GL_ADD:
+      if (ifmt == GL_ALPHA ||
+          ifmt == GL_LUMINANCE_ALPHA ||
+          ifmt == GL_RGBA) {
+         /* product of texel and fragment alpha */
+         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         alphaComb.Factor   = GR_COMBINE_FACTOR_LOCAL;
+         alphaComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+      }
+      else if (ifmt == GL_LUMINANCE || ifmt == GL_RGB) {
+         /* fragment alpha is unchanged */
+         alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         alphaComb.Factor   = GR_COMBINE_FACTOR_NONE;
+         alphaComb.Other    = GR_COMBINE_OTHER_NONE;
+      }
+      else {
+         /* sum of texel and fragment alpha */
+         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+         alphaComb.Factor   = GR_COMBINE_FACTOR_ONE;
+         alphaComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+      }
+
+      if (ifmt == GL_ALPHA) {
+         /* rgb unchanged */
+         colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         colorComb.Factor   = GR_COMBINE_FACTOR_NONE;
+         colorComb.Other    = GR_COMBINE_OTHER_NONE;
+      }
+      else {
+         /* sum of texel and fragment rgb */
+         colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+         colorComb.Factor   = GR_COMBINE_FACTOR_ONE;
+         colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+      }
+      break;
+   default:
+      if (TDFX_DEBUG & VERBOSE_DRIVER) {
+        fprintf(stderr, "fxSetupTextureSingleTMU_NoLock: %x Texture.EnvMode not yet supported\n",
+                ctx->Texture.Unit[textureset].EnvMode);
+      }
+      return;
+   }
+
+   grAlphaCombine(alphaComb.Function,
+                  alphaComb.Factor,
+                  alphaComb.Local,
+                  alphaComb.Other,
+                  alphaComb.Invert);
+   grColorCombine(colorComb.Function,
+                  colorComb.Factor,
+                  colorComb.Local,
+                  colorComb.Other,
+                  colorComb.Invert);
 }
 
-static void fxSetupTextureSingleTMU(GLcontext *ctx, GLuint textureset) {
-  BEGIN_BOARD_LOCK();
-  fxSetupTextureSingleTMU_NoLock(ctx, textureset);
-  END_BOARD_LOCK();
+#if 00
+static void
+fxSetupTextureSingleTMU(GLcontext * ctx, GLuint textureset)
+{
+   BEGIN_BOARD_LOCK();
+   fxSetupTextureSingleTMU_NoLock(ctx, textureset);
+   END_BOARD_LOCK();
 }
+#endif
+
 
 /************************* Double Texture Set ***************************/
 
-static void fxSetupDoubleTMU_NoLock(fxMesaContext fxMesa, 
-                                   struct gl_texture_object *tObj0,
-                                   struct gl_texture_object *tObj1)
+static void
+fxSetupDoubleTMU_NoLock(fxMesaContext fxMesa,
+                       struct gl_texture_object *tObj0,
+                       struct gl_texture_object *tObj1)
 {
 #define T0_NOT_IN_TMU  0x01
 #define T1_NOT_IN_TMU  0x02
@@ -620,119 +762,149 @@ static void fxSetupDoubleTMU_NoLock(fxMesaContext fxMesa,
 #define T0_IN_TMU1     0x10
 #define T1_IN_TMU1     0x20
 
-  tfxTexInfo *ti0=fxTMGetTexInfo(tObj0);
-  tfxTexInfo *ti1=fxTMGetTexInfo(tObj1);
-  GLuint tstate=0;
-  int tmu0=0, tmu1=1;
-
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
-     fprintf(stderr,"fxmesa: fxSetupDoubleTMU(...)\n");
-  }
-
-  /* We shouldn't need to do this. There is something wrong with
-     mutlitexturing when the TMUs are swapped. So, we're forcing
-     them to always be loaded correctly. !!! */
-  if (ti0->whichTMU==FX_TMU1)
-    fxTMMoveOutTM_NoLock(fxMesa, tObj0);
-  if (ti1->whichTMU==FX_TMU0)
-    fxTMMoveOutTM_NoLock(fxMesa, tObj1);
-
-  if (ti0->isInTM) {
-    switch (ti0->whichTMU) {
-    case FX_TMU0:
-      tstate|=T0_IN_TMU0;
-      break;
-    case FX_TMU1:
-      tstate|=T0_IN_TMU1;
-      break;
-    case FX_TMU_BOTH:
-      tstate|=T0_IN_TMU0|T0_IN_TMU1;
-      break;
-    case FX_TMU_SPLIT:
-      tstate|=T0_NOT_IN_TMU;
-      break;
-    }
-  } else tstate|=T0_NOT_IN_TMU;
+   tfxTexInfo *ti0 = fxTMGetTexInfo(tObj0);
+   tfxTexInfo *ti1 = fxTMGetTexInfo(tObj1);
+   GLuint tstate = 0;
+   int tmu0 = 0, tmu1 = 1;
 
-  if (ti1->isInTM) {
-    switch (ti1->whichTMU) {
-    case FX_TMU0:
-      tstate|=T1_IN_TMU0;
-      break;
-    case FX_TMU1:
-      tstate|=T1_IN_TMU1;
-      break;
-    case FX_TMU_BOTH:
-      tstate|=T1_IN_TMU0|T1_IN_TMU1;
-      break;
-    case FX_TMU_SPLIT:
-      tstate|=T1_NOT_IN_TMU;
-      break;
-    }
-  } else tstate|=T1_NOT_IN_TMU;
-
-  ti0->lastTimeUsed=fxMesa->texBindNumber;
-  ti1->lastTimeUsed=fxMesa->texBindNumber;
-
-  /* Move texture maps into TMUs */ 
-
-  if (!(((tstate&T0_IN_TMU0) && (tstate&T1_IN_TMU1)) ||
-       ((tstate&T0_IN_TMU1) && (tstate&T1_IN_TMU0)))) {
-    if (tObj0==tObj1) fxTMMoveInTM_NoLock(fxMesa, tObj1, FX_TMU_BOTH);
-    else {
-      /* Find the minimal way to correct the situation */
-      if ((tstate&T0_IN_TMU0) || (tstate&T1_IN_TMU1)) {
-       /* We have one in the standard order, setup the other */
-       if (tstate&T0_IN_TMU0) { /* T0 is in TMU0, put T1 in TMU1 */
-         fxTMMoveInTM_NoLock(fxMesa, tObj1, FX_TMU1);
-       } else {
-         fxTMMoveInTM_NoLock(fxMesa, tObj0, FX_TMU0);
-       }
-       /* tmu0 and tmu1 are setup */
-      } else if ((tstate&T0_IN_TMU1) || (tstate&T1_IN_TMU0)) {
-       /* we have one in the reverse order, setup the other */
-       if (tstate&T1_IN_TMU0) { /* T1 is in TMU0, put T0 in TMU1 */
-         fxTMMoveInTM_NoLock(fxMesa, tObj0, FX_TMU1);
-       } else {
-         fxTMMoveInTM_NoLock(fxMesa, tObj1, FX_TMU0);
-       }
-       tmu0=1;
-       tmu1=0;
-      } else { /* Nothing is loaded */
-       fxTMMoveInTM_NoLock(fxMesa, tObj0, FX_TMU0);
-       fxTMMoveInTM_NoLock(fxMesa, tObj1, FX_TMU1);
-       /* tmu0 and tmu1 are setup */
+   if (TDFX_DEBUG & VERBOSE_DRIVER) {
+      fprintf(stderr, "fxSetupDoubleTMU_NoLock(...)\n");
+   }
+
+   /* We shouldn't need to do this. There is something wrong with
+      mutlitexturing when the TMUs are swapped. So, we're forcing
+      them to always be loaded correctly. !!! */
+   if (ti0->whichTMU == FX_TMU1)
+      fxTMMoveOutTM_NoLock(fxMesa, tObj0);
+   if (ti1->whichTMU == FX_TMU0)
+      fxTMMoveOutTM_NoLock(fxMesa, tObj1);
+
+   if (ti0->isInTM) {
+      switch (ti0->whichTMU) {
+      case FX_TMU0:
+        tstate |= T0_IN_TMU0;
+        break;
+      case FX_TMU1:
+        tstate |= T0_IN_TMU1;
+        break;
+      case FX_TMU_BOTH:
+        tstate |= T0_IN_TMU0 | T0_IN_TMU1;
+        break;
+      case FX_TMU_SPLIT:
+        tstate |= T0_NOT_IN_TMU;
+        break;
       }
-    }
-  }
-
-  if (!fxMesa->haveGlobalPaletteTexture) {
-    if (ti0->info.format==GR_TEXFMT_P_8) {
-       if (MESA_VERBOSE&VERBOSE_DRIVER) {
-         fprintf(stderr,"fxmesa: uploading texture palette TMU0\n");
-       }
-       FX_grTexDownloadTable_NoLock(tmu0, GR_TEXTABLE_PALETTE, &(ti0->palette));
-    }
+   }
+   else
+      tstate |= T0_NOT_IN_TMU;
+
+   if (ti1->isInTM) {
+      switch (ti1->whichTMU) {
+      case FX_TMU0:
+        tstate |= T1_IN_TMU0;
+        break;
+      case FX_TMU1:
+        tstate |= T1_IN_TMU1;
+        break;
+      case FX_TMU_BOTH:
+        tstate |= T1_IN_TMU0 | T1_IN_TMU1;
+        break;
+      case FX_TMU_SPLIT:
+        tstate |= T1_NOT_IN_TMU;
+        break;
+      }
+   }
+   else
+      tstate |= T1_NOT_IN_TMU;
+
+   ti0->lastTimeUsed = fxMesa->texBindNumber;
+   ti1->lastTimeUsed = fxMesa->texBindNumber;
+
+   /* Move texture maps into TMUs */
+
+   if (!(((tstate & T0_IN_TMU0) && (tstate & T1_IN_TMU1)) ||
+        ((tstate & T0_IN_TMU1) && (tstate & T1_IN_TMU0)))) {
+      if (tObj0 == tObj1)
+        fxTMMoveInTM_NoLock(fxMesa, tObj1, FX_TMU_BOTH);
+      else {
+        /* Find the minimal way to correct the situation */
+        if ((tstate & T0_IN_TMU0) || (tstate & T1_IN_TMU1)) {
+           /* We have one in the standard order, setup the other */
+           if (tstate & T0_IN_TMU0) {  /* T0 is in TMU0, put T1 in TMU1 */
+              fxTMMoveInTM_NoLock(fxMesa, tObj1, FX_TMU1);
+           }
+           else {
+              fxTMMoveInTM_NoLock(fxMesa, tObj0, FX_TMU0);
+           }
+           /* tmu0 and tmu1 are setup */
+        }
+        else if ((tstate & T0_IN_TMU1) || (tstate & T1_IN_TMU0)) {
+           /* we have one in the reverse order, setup the other */
+           if (tstate & T1_IN_TMU0) {  /* T1 is in TMU0, put T0 in TMU1 */
+              fxTMMoveInTM_NoLock(fxMesa, tObj0, FX_TMU1);
+           }
+           else {
+              fxTMMoveInTM_NoLock(fxMesa, tObj1, FX_TMU0);
+           }
+           tmu0 = 1;
+           tmu1 = 0;
+        }
+        else {                 /* Nothing is loaded */
+           fxTMMoveInTM_NoLock(fxMesa, tObj0, FX_TMU0);
+           fxTMMoveInTM_NoLock(fxMesa, tObj1, FX_TMU1);
+           /* tmu0 and tmu1 are setup */
+        }
+      }
+   }
 
-    if (ti1->info.format==GR_TEXFMT_P_8) {
-       if (MESA_VERBOSE&VERBOSE_DRIVER) {
-         fprintf(stderr,"fxmesa: uploading texture palette TMU1\n");
-       }
-       FX_grTexDownloadTable_NoLock(tmu1, GR_TEXTABLE_PALETTE, &(ti1->palette));
-    }
-  }
+   /* [dBorca] Hack alert:
+    * we put these in reverse order, so that if we can't
+    * do _REAL_ pointcast, the TMU0 table gets broadcasted
+    */
+   if (!fxMesa->haveGlobalPaletteTexture) {
+      /* pointcast */
+      if (ti1->info.format == GR_TEXFMT_P_8) {
+        if (TDFX_DEBUG & VERBOSE_DRIVER) {
+           fprintf(stderr, "fxSetupDoubleTMU_NoLock: uploading texture palette for TMU1\n");
+        }
+        fxMesa->Glide.grTexDownloadTableExt(ti1->whichTMU, ti1->paltype, &(ti1->palette));
+      }
+      if (ti0->info.format == GR_TEXFMT_P_8) {
+        if (TDFX_DEBUG & VERBOSE_DRIVER) {
+           fprintf(stderr, "fxSetupDoubleTMU_NoLock: uploading texture palette for TMU0\n");
+        }
+        fxMesa->Glide.grTexDownloadTableExt(ti0->whichTMU, ti0->paltype, &(ti0->palette));
+      }
+   }
+#if FX_TC_NCC
+   /* pointcast */
+   if ((ti1->info.format == GR_TEXFMT_AYIQ_8422) ||
+       (ti1->info.format == GR_TEXFMT_YIQ_422)) {
+      if (TDFX_DEBUG & VERBOSE_DRIVER) {
+         fprintf(stderr, "fxSetupDoubleTMU_NoLock: uploading NCC0 table for TMU1\n");
+      }
+      fxMesa->Glide.grTexDownloadTableExt(ti1->whichTMU, GR_TEXTABLE_NCC0, &(ti1->palette));
+   }
+   if ((ti0->info.format == GR_TEXFMT_AYIQ_8422) ||
+       (ti0->info.format == GR_TEXFMT_YIQ_422)) {
+      if (TDFX_DEBUG & VERBOSE_DRIVER) {
+         fprintf(stderr, "fxSetupDoubleTMU_NoLock: uploading NCC0 table for TMU0\n");
+      }
+      fxMesa->Glide.grTexDownloadTableExt(ti0->whichTMU, GR_TEXTABLE_NCC0, &(ti0->palette));
+   }
+#endif
 
-  FX_grTexSource_NoLock(tmu0, ti0->tm[tmu0]->startAddr, 
-                       GR_MIPMAPLEVELMASK_BOTH, &(ti0->info));
-  FX_grTexClampMode_NoLock(tmu0, ti0->sClamp, ti0->tClamp);
-  FX_grTexFilterMode_NoLock(tmu0, ti0->minFilt, ti0->maxFilt);
-  FX_grTexMipMapMode_NoLock(tmu0, ti0->mmMode, FXFALSE);
+   grTexSource(tmu0, ti0->tm[tmu0]->startAddr,
+                        GR_MIPMAPLEVELMASK_BOTH, &(ti0->info));
+   grTexClampMode(tmu0, ti0->sClamp, ti0->tClamp);
+   grTexFilterMode(tmu0, ti0->minFilt, ti0->maxFilt);
+   grTexMipMapMode(tmu0, ti0->mmMode, FXFALSE);
 
-  FX_grTexSource_NoLock(tmu1, ti1->tm[tmu1]->startAddr,
-                       GR_MIPMAPLEVELMASK_BOTH, &(ti1->info));
-  FX_grTexClampMode_NoLock(tmu1, ti1->sClamp, ti1->tClamp);
-  FX_grTexFilterMode_NoLock(tmu1, ti1->minFilt, ti1->maxFilt);
-  FX_grTexMipMapMode_NoLock(tmu1, ti1->mmMode, FXFALSE);
+   grTexSource(tmu1, ti1->tm[tmu1]->startAddr,
+                        GR_MIPMAPLEVELMASK_BOTH, &(ti1->info));
+   grTexClampMode(tmu1, ti1->sClamp, ti1->tClamp);
+   grTexFilterMode(tmu1, ti1->minFilt, ti1->maxFilt);
+   grTexMipMapMode(tmu1, ti1->mmMode, FXFALSE);
 
 #undef T0_NOT_IN_TMU
 #undef T1_NOT_IN_TMU
@@ -742,749 +914,1014 @@ static void fxSetupDoubleTMU_NoLock(fxMesaContext fxMesa,
 #undef T1_IN_TMU1
 }
 
-static void fxSetupTextureDoubleTMU_NoLock(GLcontext *ctx)
+static void
+fxSetupTextureDoubleTMU_NoLock(GLcontext * ctx)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  GrCombineLocal_t localc,locala;
-  tfxTexInfo *ti0,*ti1;
-  struct gl_texture_object *tObj0=ctx->Texture.Unit[0].CurrentD[2];
-  struct gl_texture_object *tObj1=ctx->Texture.Unit[1].CurrentD[2];
-  GLuint envmode,ifmt,unitsmode;
-  int tmu0=0, tmu1=1;
-
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
-     fprintf(stderr,"fxmesa: fxSetupTextureDoubleTMU(...) Start\n");
-  }
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   struct tdfx_combine alphaComb, colorComb;
+   struct tdfx_texcombine tex0, tex1;
+   GrCombineLocal_t localc, locala;
+   tfxTexInfo *ti0, *ti1;
+   struct gl_texture_object *tObj0 = ctx->Texture.Unit[1]._Current;
+   struct gl_texture_object *tObj1 = ctx->Texture.Unit[0]._Current;
+   GLuint envmode, ifmt, unitsmode;
+   int tmu0 = 0, tmu1 = 1;
+
+   if (TDFX_DEBUG & VERBOSE_DRIVER) {
+      fprintf(stderr, "fxSetupTextureDoubleTMU_NoLock(...)\n");
+   }
 
-  ti0=fxTMGetTexInfo(tObj0);
-  fxTexValidate(ctx,tObj0);
+   ti0 = fxTMGetTexInfo(tObj0);
+   fxTexValidate(ctx, tObj0);
 
-  ti1=fxTMGetTexInfo(tObj1);
-  fxTexValidate(ctx,tObj1);
+   ti1 = fxTMGetTexInfo(tObj1);
+   fxTexValidate(ctx, tObj1);
 
-  fxSetupDoubleTMU_NoLock(fxMesa,tObj0,tObj1);
+   fxSetupDoubleTMU_NoLock(fxMesa, tObj0, tObj1);
 
-  unitsmode=fxGetTexSetConfiguration(ctx,tObj0,tObj1);
+   unitsmode = fxGetTexSetConfiguration(ctx, tObj0, tObj1);
 
-  if(fxMesa->lastUnitsMode==unitsmode)
-    return;
+/*    if(fxMesa->lastUnitsMode==unitsmode) */
+/*      return; */
 
-  fxMesa->lastUnitsMode=unitsmode;
+   fxMesa->lastUnitsMode = unitsmode;
 
-  fxMesa->stw_hint_state |= GR_STWHINT_ST_DIFF_TMU1;
-  FX_grHints_NoLock(GR_HINT_STWHINT, fxMesa->stw_hint_state);
+   fxMesa->stw_hint_state |= GR_STWHINT_ST_DIFF_TMU1;
+   FX_grHints_NoLock(GR_HINT_STWHINT, fxMesa->stw_hint_state);
 
-  envmode=unitsmode & FX_UM_E_ENVMODE;
-  ifmt=unitsmode & FX_UM_E_IFMT;
+   envmode = unitsmode & FX_UM_E_ENVMODE;
+   ifmt = unitsmode & FX_UM_E_IFMT;
 
-  if(unitsmode & FX_UM_ALPHA_ITERATED)
-    locala=GR_COMBINE_LOCAL_ITERATED;
-  else
-    locala=GR_COMBINE_LOCAL_CONSTANT;
+   if (unitsmode & FX_UM_ALPHA_ITERATED)
+      locala = GR_COMBINE_LOCAL_ITERATED;
+   else
+      locala = GR_COMBINE_LOCAL_CONSTANT;
 
-  if(unitsmode & FX_UM_COLOR_ITERATED)
-    localc=GR_COMBINE_LOCAL_ITERATED;
-  else
-    localc=GR_COMBINE_LOCAL_CONSTANT;
+   if (unitsmode & FX_UM_COLOR_ITERATED)
+      localc = GR_COMBINE_LOCAL_ITERATED;
+   else
+      localc = GR_COMBINE_LOCAL_CONSTANT;
 
 
-  if (MESA_VERBOSE & (VERBOSE_DRIVER|VERBOSE_TEXTURE))
-     fprintf(stderr, "fxMesa: fxSetupTextureDoubleTMU, envmode is %s/%s\n",
-            gl_lookup_enum_by_nr(ctx->Texture.Unit[0].EnvMode),
-            gl_lookup_enum_by_nr(ctx->Texture.Unit[1].EnvMode));
+   if (TDFX_DEBUG & (VERBOSE_DRIVER | VERBOSE_TEXTURE))
+      fprintf(stderr, "fxSetupTextureDoubleTMU_NoLock: envmode is %s/%s\n",
+             _mesa_lookup_enum_by_nr(ctx->Texture.Unit[0].EnvMode),
+             _mesa_lookup_enum_by_nr(ctx->Texture.Unit[1].EnvMode));
 
 
-  if ((ti0->whichTMU==FX_TMU1) || (ti1->whichTMU==FX_TMU0)) {
-    tmu0=1;
-    tmu1=0;
-  }
-  fxMesa->tmuSrc=FX_TMU_BOTH;
-  switch(envmode) {
-  case (FX_UM_E0_MODULATE | FX_UM_E1_MODULATE):
-    {
-      GLboolean isalpha[FX_NUM_TMU];
+   if ((ti0->whichTMU == FX_TMU1) || (ti1->whichTMU == FX_TMU0)) {
+      tmu0 = 1;
+      tmu1 = 0;
+   }
+   fxMesa->tmuSrc = FX_TMU_BOTH;
+
+   tex0.InvertRGB     = FXFALSE;
+   tex0.InvertAlpha   = FXFALSE;
+   tex1.InvertRGB     = FXFALSE;
+   tex1.InvertAlpha   = FXFALSE;
+   alphaComb.Local    = locala;
+   alphaComb.Invert   = FXFALSE;
+   colorComb.Local    = localc;
+   colorComb.Invert   = FXFALSE;
+
+   switch (envmode) {
+   case (FX_UM_E0_MODULATE | FX_UM_E1_MODULATE):
+      {
+        GLboolean isalpha[FX_NUM_TMU];
+
+        isalpha[tmu0] = (ti0->baseLevelInternalFormat == GL_ALPHA);
+        isalpha[tmu1] = (ti1->baseLevelInternalFormat == GL_ALPHA);
+
+        if (isalpha[FX_TMU1]) {
+            tex1.FunctionRGB   = GR_COMBINE_FUNCTION_ZERO;
+            tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+            tex1.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+            tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+            tex1.InvertRGB     = FXTRUE;
+        } else {
+            tex1.FunctionRGB   = GR_COMBINE_FUNCTION_LOCAL;
+            tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+            tex1.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+            tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+         }
+
+        if (isalpha[FX_TMU0]) {
+            tex0.FunctionRGB   = GR_COMBINE_FUNCTION_BLEND_OTHER;
+            tex0.FactorRGB     = GR_COMBINE_FACTOR_ONE;
+            tex0.FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+            tex0.FactorAlpha   = GR_COMBINE_FACTOR_LOCAL;
+        } else {
+            tex0.FunctionRGB   = GR_COMBINE_FUNCTION_BLEND_OTHER;
+            tex0.FactorRGB     = GR_COMBINE_FACTOR_LOCAL;
+            tex0.FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+            tex0.FactorAlpha   = GR_COMBINE_FACTOR_LOCAL;
+         }
+
+         colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         colorComb.Factor   = GR_COMBINE_FACTOR_LOCAL;
+         colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+
+         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         alphaComb.Factor   = GR_COMBINE_FACTOR_LOCAL;
+         alphaComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+        break;
+      }
+   case (FX_UM_E0_REPLACE | FX_UM_E1_BLEND):   /* Only for GLQuake */
+      if (tmu0 == FX_TMU1) {
+         tex1.FunctionRGB   = GR_COMBINE_FUNCTION_LOCAL;
+         tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+         tex1.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+         tex1.InvertRGB     = FXTRUE;
+
+         tex0.FunctionRGB   = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         tex0.FactorRGB     = GR_COMBINE_FACTOR_LOCAL;
+         tex0.FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         tex0.FactorAlpha   = GR_COMBINE_FACTOR_LOCAL;
+      }
+      else {
+         tex1.FunctionRGB   = GR_COMBINE_FUNCTION_LOCAL;
+         tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+         tex1.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+
+         tex0.FunctionRGB   = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         tex0.FactorRGB     = GR_COMBINE_FACTOR_ONE_MINUS_LOCAL;
+         tex0.FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         tex0.FactorAlpha   = GR_COMBINE_FACTOR_ONE_MINUS_LOCAL;
+      }
 
-      if(ti0->baseLevelInternalFormat==GL_ALPHA)
-       isalpha[tmu0]=GL_TRUE;
-      else
-       isalpha[tmu0]=GL_FALSE;
+      alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+      alphaComb.Factor   = GR_COMBINE_FACTOR_NONE;
+      alphaComb.Other    = GR_COMBINE_OTHER_NONE;
 
-      if(ti1->baseLevelInternalFormat==GL_ALPHA)
-       isalpha[tmu1]=GL_TRUE;
-      else
-       isalpha[tmu1]=GL_FALSE;
-       
-      if(isalpha[FX_TMU1])
-       FX_grTexCombine_NoLock(GR_TMU1,
-                              GR_COMBINE_FUNCTION_ZERO,
-                              GR_COMBINE_FACTOR_NONE,
-                              GR_COMBINE_FUNCTION_LOCAL,
-                              GR_COMBINE_FACTOR_NONE,
-                              FXTRUE,FXFALSE);
-      else
-       FX_grTexCombine_NoLock(GR_TMU1,
-                              GR_COMBINE_FUNCTION_LOCAL,
-                              GR_COMBINE_FACTOR_NONE,
-                              GR_COMBINE_FUNCTION_LOCAL,
-                              GR_COMBINE_FACTOR_NONE,
-                              FXFALSE,FXFALSE);
-
-      if(isalpha[FX_TMU0])
-       FX_grTexCombine_NoLock(GR_TMU0,
-                              GR_COMBINE_FUNCTION_BLEND_OTHER,
-                              GR_COMBINE_FACTOR_ONE,
-                              GR_COMBINE_FUNCTION_BLEND_OTHER,
-                              GR_COMBINE_FACTOR_LOCAL,
-                              FXFALSE,FXFALSE);
-      else
-       FX_grTexCombine_NoLock(GR_TMU0,
-                              GR_COMBINE_FUNCTION_BLEND_OTHER,
-                              GR_COMBINE_FACTOR_LOCAL,
-                              GR_COMBINE_FUNCTION_BLEND_OTHER,
-                              GR_COMBINE_FACTOR_LOCAL,
-                              FXFALSE,FXFALSE);
-
-      FX_grColorCombine_NoLock(GR_COMBINE_FUNCTION_SCALE_OTHER,
-                              GR_COMBINE_FACTOR_LOCAL,
-                              localc,
-                              GR_COMBINE_OTHER_TEXTURE,
-                              FXFALSE);
-
-      FX_grAlphaCombine_NoLock(GR_COMBINE_FUNCTION_SCALE_OTHER,
-                              GR_COMBINE_FACTOR_LOCAL,
-                              locala,
-                              GR_COMBINE_OTHER_TEXTURE,
-                              FXFALSE);
+      colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+      colorComb.Factor   = GR_COMBINE_FACTOR_ONE;
+      colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
       break;
-    }
-  case (FX_UM_E0_REPLACE | FX_UM_E1_BLEND): /* Only for GLQuake */
-    if (tmu1==FX_TMU1) {
-      FX_grTexCombine_NoLock(GR_TMU1,
-                            GR_COMBINE_FUNCTION_LOCAL,
-                            GR_COMBINE_FACTOR_NONE,
-                            GR_COMBINE_FUNCTION_LOCAL,
-                            GR_COMBINE_FACTOR_NONE,
-                            FXTRUE,FXFALSE);
-                 
-      FX_grTexCombine_NoLock(GR_TMU0,
-                            GR_COMBINE_FUNCTION_BLEND_OTHER,
-                            GR_COMBINE_FACTOR_LOCAL,
-                            GR_COMBINE_FUNCTION_BLEND_OTHER,
-                            GR_COMBINE_FACTOR_LOCAL,
-                            FXFALSE,FXFALSE);
-    } else {
-      FX_grTexCombine_NoLock(GR_TMU1,
-                            GR_COMBINE_FUNCTION_LOCAL,
-                            GR_COMBINE_FACTOR_NONE,
-                            GR_COMBINE_FUNCTION_LOCAL,
-                            GR_COMBINE_FACTOR_NONE,
-                            FXFALSE,FXFALSE);
-                 
-      FX_grTexCombine_NoLock(GR_TMU0,
-                            GR_COMBINE_FUNCTION_BLEND_OTHER,
-                            GR_COMBINE_FACTOR_ONE_MINUS_LOCAL,
-                            GR_COMBINE_FUNCTION_BLEND_OTHER,
-                            GR_COMBINE_FACTOR_ONE_MINUS_LOCAL,
-                            FXFALSE,FXFALSE);
-    }
-         
-    FX_grAlphaCombine_NoLock(GR_COMBINE_FUNCTION_LOCAL,
-                            GR_COMBINE_FACTOR_NONE,
-                            locala,
-                            GR_COMBINE_OTHER_NONE,
-                            FXFALSE);
-
-    FX_grColorCombine_NoLock(GR_COMBINE_FUNCTION_SCALE_OTHER,
-                            GR_COMBINE_FACTOR_ONE,
-                            localc,
-                            GR_COMBINE_OTHER_TEXTURE,
-                            FXFALSE);
-    break;
-  case (FX_UM_E0_REPLACE | FX_UM_E1_MODULATE): /* Quake 2 and 3 */
-    if (tmu1==FX_TMU1) {
-      FX_grTexCombine_NoLock(GR_TMU1,
-                            GR_COMBINE_FUNCTION_LOCAL,
-                            GR_COMBINE_FACTOR_NONE,
-                            GR_COMBINE_FUNCTION_ZERO,
-                            GR_COMBINE_FACTOR_NONE,
-                            FXFALSE,FXTRUE);
-                 
-      FX_grTexCombine_NoLock(GR_TMU0,
-                            GR_COMBINE_FUNCTION_BLEND_OTHER,
-                            GR_COMBINE_FACTOR_LOCAL,
-                            GR_COMBINE_FUNCTION_BLEND_OTHER,
-                            GR_COMBINE_FACTOR_LOCAL,
-                            FXFALSE,FXFALSE);
+   case (FX_UM_E0_REPLACE | FX_UM_E1_MODULATE):        /* Quake 2 and 3 */
+      if (tmu1 == FX_TMU1) {
+         tex1.FunctionRGB   = GR_COMBINE_FUNCTION_LOCAL;
+         tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+         tex1.FunctionAlpha = GR_COMBINE_FUNCTION_ZERO;
+         tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+         tex1.InvertAlpha   = FXTRUE;
+
+         tex0.FunctionRGB   = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         tex0.FactorRGB     = GR_COMBINE_FACTOR_LOCAL;
+         tex0.FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         tex0.FactorAlpha   = GR_COMBINE_FACTOR_LOCAL;
+      }
+      else {
+         tex1.FunctionRGB   = GR_COMBINE_FUNCTION_LOCAL;
+         tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+         tex1.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+
+         tex0.FunctionRGB   = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         tex0.FactorRGB     = GR_COMBINE_FACTOR_LOCAL;
+         tex0.FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+         tex0.FactorAlpha   = GR_COMBINE_FACTOR_ONE;
+      }
 
-    } else {
-      FX_grTexCombine_NoLock(GR_TMU1,
-                            GR_COMBINE_FUNCTION_LOCAL,
-                            GR_COMBINE_FACTOR_NONE,
-                            GR_COMBINE_FUNCTION_LOCAL,
-                            GR_COMBINE_FACTOR_NONE,
-                            FXFALSE,FXFALSE);
-                 
-      FX_grTexCombine_NoLock(GR_TMU0,
-                            GR_COMBINE_FUNCTION_BLEND_OTHER,
-                            GR_COMBINE_FACTOR_LOCAL,
-                            GR_COMBINE_FUNCTION_BLEND_OTHER,
-                            GR_COMBINE_FACTOR_ONE,
-                            FXFALSE,FXFALSE);
-    }
-         
-    if(ti0->baseLevelInternalFormat==GL_RGB)
-      FX_grAlphaCombine_NoLock(GR_COMBINE_FUNCTION_LOCAL,
-                              GR_COMBINE_FACTOR_NONE,
-                              locala,
-                              GR_COMBINE_OTHER_NONE,
-                              FXFALSE);
-    else
-      FX_grAlphaCombine_NoLock(GR_COMBINE_FUNCTION_SCALE_OTHER,
-                              GR_COMBINE_FACTOR_ONE,
-                              locala,
-                              GR_COMBINE_OTHER_NONE,
-                              FXFALSE);
-
-
-    FX_grColorCombine_NoLock(GR_COMBINE_FUNCTION_SCALE_OTHER,
-                            GR_COMBINE_FACTOR_ONE,
-                            localc,
-                            GR_COMBINE_OTHER_TEXTURE,
-                            FXFALSE);
-    break;
-  
-
-  case (FX_UM_E0_MODULATE | FX_UM_E1_ADD): /* Quake 3 Sky */
-    {
-      GLboolean isalpha[FX_NUM_TMU];
-
-      if(ti0->baseLevelInternalFormat==GL_ALPHA)
-       isalpha[tmu0]=GL_TRUE;
-      else
-       isalpha[tmu0]=GL_FALSE;
+      if (ti0->baseLevelInternalFormat == GL_RGB) {
+         alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+         alphaComb.Factor   = GR_COMBINE_FACTOR_NONE;
+         alphaComb.Other    = GR_COMBINE_OTHER_NONE;
+      } else {
+         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         alphaComb.Factor   = GR_COMBINE_FACTOR_ONE;
+         alphaComb.Other    = GR_COMBINE_OTHER_NONE;
+      }
 
-      if(ti1->baseLevelInternalFormat==GL_ALPHA)
-       isalpha[tmu1]=GL_TRUE;
-      else
-       isalpha[tmu1]=GL_FALSE;
-       
-      if(isalpha[FX_TMU1])
-       FX_grTexCombine_NoLock(GR_TMU1,
-                              GR_COMBINE_FUNCTION_ZERO,
-                              GR_COMBINE_FACTOR_NONE,
-                              GR_COMBINE_FUNCTION_LOCAL,
-                              GR_COMBINE_FACTOR_NONE,
-                              FXTRUE,FXFALSE);
-      else
-       FX_grTexCombine_NoLock(GR_TMU1,
-                              GR_COMBINE_FUNCTION_LOCAL,
-                              GR_COMBINE_FACTOR_NONE,
-                              GR_COMBINE_FUNCTION_LOCAL,
-                              GR_COMBINE_FACTOR_NONE,
-                              FXFALSE,FXFALSE);
-
-      if(isalpha[FX_TMU0])
-       FX_grTexCombine_NoLock(GR_TMU0,
-                              GR_COMBINE_FUNCTION_SCALE_OTHER,
-                              GR_COMBINE_FACTOR_ONE,
-                              GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL,
-                              GR_COMBINE_FACTOR_ONE,
-                              FXFALSE,FXFALSE);
-      else
-       FX_grTexCombine_NoLock(GR_TMU0,
-                              GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL,
-                              GR_COMBINE_FACTOR_ONE,
-                              GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL,
-                              GR_COMBINE_FACTOR_ONE,
-                              FXFALSE,FXFALSE);
-
-      FX_grColorCombine_NoLock(GR_COMBINE_FUNCTION_SCALE_OTHER,
-                              GR_COMBINE_FACTOR_LOCAL,
-                              localc,
-                              GR_COMBINE_OTHER_TEXTURE,
-                              FXFALSE);
-
-      FX_grAlphaCombine_NoLock(GR_COMBINE_FUNCTION_SCALE_OTHER,
-                              GR_COMBINE_FACTOR_LOCAL,
-                              locala,               
-                              GR_COMBINE_OTHER_TEXTURE,
-                              FXFALSE);
+      colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+      colorComb.Factor   = GR_COMBINE_FACTOR_ONE;
+      colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
       break;
-    }
-  default:
-    fprintf(stderr, "Unexpected dual texture mode encountered\n");
-    break;
-  }
-
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
-     fprintf(stderr,"fxmesa: fxSetupTextureDoubleTMU(...) End\n");
-  }
+
+
+   case (FX_UM_E0_MODULATE | FX_UM_E1_ADD):    /* Quake 3 Sky */
+      {
+        GLboolean isalpha[FX_NUM_TMU];
+
+        isalpha[tmu0] = (ti0->baseLevelInternalFormat == GL_ALPHA);
+        isalpha[tmu1] = (ti1->baseLevelInternalFormat == GL_ALPHA);
+
+        if (isalpha[FX_TMU1]) {
+            tex1.FunctionRGB   = GR_COMBINE_FUNCTION_ZERO;
+            tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+            tex1.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+            tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+            tex1.InvertRGB     = FXTRUE;
+        } else {
+            tex1.FunctionRGB   = GR_COMBINE_FUNCTION_LOCAL;
+            tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+            tex1.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+            tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+         }
+
+        if (isalpha[FX_TMU0]) {
+            tex0.FunctionRGB   = GR_COMBINE_FUNCTION_SCALE_OTHER;
+            tex0.FactorRGB     = GR_COMBINE_FACTOR_ONE;
+            tex0.FunctionAlpha = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+            tex0.FactorAlpha   = GR_COMBINE_FACTOR_ONE;
+        } else {
+            tex0.FunctionRGB   = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+            tex0.FactorRGB     = GR_COMBINE_FACTOR_ONE;
+            tex0.FunctionAlpha = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+            tex0.FactorAlpha   = GR_COMBINE_FACTOR_ONE;
+         }
+
+         colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         colorComb.Factor   = GR_COMBINE_FACTOR_LOCAL;
+         colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+
+         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         alphaComb.Factor   = GR_COMBINE_FACTOR_LOCAL;
+         alphaComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+        break;
+      }
+
+   case (FX_UM_E0_REPLACE | FX_UM_E1_ADD):     /* Vulpine Sky */
+      {
+        GLboolean isalpha[FX_NUM_TMU];
+
+        isalpha[tmu0] = (ti0->baseLevelInternalFormat == GL_ALPHA);
+        isalpha[tmu1] = (ti1->baseLevelInternalFormat == GL_ALPHA);
+
+        if (isalpha[FX_TMU1]) {
+            tex1.FunctionRGB   = GR_COMBINE_FUNCTION_ZERO;
+            tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+            tex1.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+            tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+            tex1.InvertRGB     = FXTRUE;
+        } else {
+            tex1.FunctionRGB   = GR_COMBINE_FUNCTION_LOCAL;
+            tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+            tex1.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+            tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+         }
+
+        if (isalpha[FX_TMU0]) {
+            tex0.FunctionRGB   = GR_COMBINE_FUNCTION_SCALE_OTHER;
+            tex0.FactorRGB     = GR_COMBINE_FACTOR_ONE;
+            tex0.FunctionAlpha = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+            tex0.FactorAlpha   = GR_COMBINE_FACTOR_ONE;
+        } else {
+            tex0.FunctionRGB   = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+            tex0.FactorRGB     = GR_COMBINE_FACTOR_ONE;
+            tex0.FunctionAlpha = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+            tex0.FactorAlpha   = GR_COMBINE_FACTOR_ONE;
+         }
+
+         colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         colorComb.Factor   = GR_COMBINE_FACTOR_ONE;
+         colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+
+         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+         alphaComb.Factor   = GR_COMBINE_FACTOR_ONE;
+         alphaComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+        break;
+      }
+
+   case (FX_UM_E0_MODULATE | FX_UM_E1_REPLACE): /* Homeworld2 */
+      {
+         tex1.FunctionRGB   = GR_COMBINE_FUNCTION_ZERO;
+         tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+         tex1.FunctionAlpha = GR_COMBINE_FUNCTION_ZERO;
+         tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+
+         tex0.FunctionRGB   = GR_COMBINE_FUNCTION_LOCAL;
+         tex0.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+         tex0.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         tex0.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+
+         if (ifmt & (FX_UM_E0_RGB | FX_UM_E0_LUMINANCE)) {
+            alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+            alphaComb.Factor   = GR_COMBINE_FACTOR_NONE;
+            alphaComb.Other    = GR_COMBINE_OTHER_NONE;
+         } else {
+            alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+            alphaComb.Factor   = GR_COMBINE_FACTOR_ONE;
+            alphaComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+         }
+
+         if (ifmt & FX_UM_E0_ALPHA) {
+            colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+            colorComb.Factor   = GR_COMBINE_FACTOR_NONE;
+            colorComb.Other    = GR_COMBINE_OTHER_NONE;
+         } else {
+            colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+            colorComb.Factor   = GR_COMBINE_FACTOR_ONE;
+            colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+         }
+         break;
+      }
+   default:
+      fprintf(stderr, "fxSetupTextureDoubleTMU_NoLock: Unexpected dual texture mode encountered\n");
+      return;
+   }
+
+   grAlphaCombine(alphaComb.Function,
+                  alphaComb.Factor,
+                  alphaComb.Local,
+                  alphaComb.Other,
+                  alphaComb.Invert);
+   grColorCombine(colorComb.Function,
+                  colorComb.Factor,
+                  colorComb.Local,
+                  colorComb.Other,
+                  colorComb.Invert);
+   grTexCombine(GR_TMU0,
+                tex0.FunctionRGB,
+                tex0.FactorRGB,
+                tex0.FunctionAlpha,
+                tex0.FactorAlpha,
+                tex0.InvertRGB,
+                tex0.InvertAlpha);
+   grTexCombine(GR_TMU1,
+                tex1.FunctionRGB,
+                tex1.FactorRGB,
+                tex1.FunctionAlpha,
+                tex1.FactorAlpha,
+                tex1.InvertRGB,
+                tex1.InvertAlpha);
 }
 
 /************************* No Texture ***************************/
 
-static void fxSetupTextureNone_NoLock(GLcontext *ctx)
+static void
+fxSetupTextureNone_NoLock(GLcontext * ctx)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  GrCombineLocal_t localc,locala;
-
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
-     fprintf(stderr,"fxmesa: fxSetupTextureNone(...)\n");
-  }
-
-  if((ctx->Light.ShadeModel==GL_SMOOTH) ||
-     (ctx->Point.SmoothFlag) ||
-     (ctx->Line.SmoothFlag) ||
-     (ctx->Polygon.SmoothFlag))
-    locala=GR_COMBINE_LOCAL_ITERATED;
-  else
-    locala=GR_COMBINE_LOCAL_CONSTANT;
-  
-  if(ctx->Light.ShadeModel==GL_SMOOTH)
-    localc=GR_COMBINE_LOCAL_ITERATED;
-  else
-    localc=GR_COMBINE_LOCAL_CONSTANT;
-  
-  FX_grAlphaCombine_NoLock(GR_COMBINE_FUNCTION_LOCAL,
-                          GR_COMBINE_FACTOR_NONE,
-                          locala,
-                          GR_COMBINE_OTHER_NONE,
-                          FXFALSE);
-
-  FX_grColorCombine_NoLock(GR_COMBINE_FUNCTION_LOCAL,
-                          GR_COMBINE_FACTOR_NONE,
-                          localc,
-                          GR_COMBINE_OTHER_NONE,
-                          FXFALSE);
-
-  fxMesa->lastUnitsMode=FX_UM_NONE;
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   GrCombineLocal_t localc, locala;
+
+   if (TDFX_DEBUG & VERBOSE_DRIVER) {
+      fprintf(stderr, "fxSetupTextureNone_NoLock(...)\n");
+   }
+
+   if ((ctx->Light.ShadeModel == GL_SMOOTH) || 1 ||
+       (ctx->Point.SmoothFlag) ||
+       (ctx->Line.SmoothFlag) ||
+       (ctx->Polygon.SmoothFlag)) locala = GR_COMBINE_LOCAL_ITERATED;
+   else
+      locala = GR_COMBINE_LOCAL_CONSTANT;
+
+   if (ctx->Light.ShadeModel == GL_SMOOTH || 1)
+      localc = GR_COMBINE_LOCAL_ITERATED;
+   else
+      localc = GR_COMBINE_LOCAL_CONSTANT;
+
+   grAlphaCombine(GR_COMBINE_FUNCTION_LOCAL,
+                  GR_COMBINE_FACTOR_NONE,
+                  locala,
+                  GR_COMBINE_OTHER_NONE,
+                  FXFALSE);
+
+   grColorCombine(GR_COMBINE_FUNCTION_LOCAL,
+                  GR_COMBINE_FACTOR_NONE,
+                  localc,
+                  GR_COMBINE_OTHER_NONE,
+                  FXFALSE);
+
+   fxMesa->lastUnitsMode = FX_UM_NONE;
 }
 
+#include "fxsetup.h"
+
 /************************************************************************/
 /************************** Texture Mode SetUp **************************/
 /************************************************************************/
 
-static void fxSetupTexture_NoLock(GLcontext *ctx)
+static void
+fxSetupTexture_NoLock(GLcontext * ctx)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  GLuint tex2Denabled;
-
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
-     fprintf(stderr,"fxmesa: fxSetupTexture(...)\n");
-  }
-
-  /* Disable multipass texturing.
-   */
-  ctx->Driver.MultipassFunc = 0;
-
-  /* Texture Combine, Color Combine and Alpha Combine.
-   */  
-  tex2Denabled = (ctx->Texture.ReallyEnabled & TEXTURE0_2D);
-
-  if (fxMesa->emulateTwoTMUs)
-     tex2Denabled |= (ctx->Texture.ReallyEnabled & TEXTURE1_2D);
-  
-  switch(tex2Denabled) {
-  case TEXTURE0_2D:
-    fxSetupTextureSingleTMU_NoLock(ctx,0);    
-    break;
-  case TEXTURE1_2D:
-    fxSetupTextureSingleTMU_NoLock(ctx,1);
-    break;
-  case (TEXTURE0_2D|TEXTURE1_2D):
-     if (fxMesa->haveTwoTMUs)
-       fxSetupTextureDoubleTMU_NoLock(ctx);
-     else {
-       if (MESA_VERBOSE&VERBOSE_DRIVER)
-          fprintf(stderr, "fxmesa: enabling fake multitexture\n");
-
-       fxSetupTextureSingleTMU_NoLock(ctx,0);
-       ctx->Driver.MultipassFunc = fxMultipassTexture;
-     }
-    break;
-  default:
-    fxSetupTextureNone_NoLock(ctx);
-    break;
-  }
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+
+   if (TDFX_DEBUG & VERBOSE_DRIVER) {
+      fprintf(stderr, "fxSetupTexture_NoLock(...)\n");
+   }
+
+   if (fxMesa->HaveCmbExt) {
+      /* Texture Combine, Color Combine and Alpha Combine. */
+      if ((ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) &&
+          (ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) &&
+          fxMesa->haveTwoTMUs) {
+         fxSetupTextureDoubleTMUNapalm_NoLock(ctx);
+      }
+      else if (ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) {
+         fxSetupTextureSingleTMUNapalm_NoLock(ctx, 0);
+      }
+      else if (ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) {
+         fxSetupTextureSingleTMUNapalm_NoLock(ctx, 1);
+      }
+      else {
+         fxSetupTextureNoneNapalm_NoLock(ctx);
+      }
+   } else {
+      /* Texture Combine, Color Combine and Alpha Combine. */
+      if ((ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) &&
+          (ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) &&
+          fxMesa->haveTwoTMUs) {
+         fxSetupTextureDoubleTMU_NoLock(ctx);
+      }
+      else if (ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) {
+         fxSetupTextureSingleTMU_NoLock(ctx, 0);
+      }
+      else if (ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) {
+         fxSetupTextureSingleTMU_NoLock(ctx, 1);
+      }
+      else {
+         fxSetupTextureNone_NoLock(ctx);
+      }
+   }
 }
 
-static void fxSetupTexture(GLcontext *ctx) {
-  BEGIN_BOARD_LOCK();
-  fxSetupTexture_NoLock(ctx);
-  END_BOARD_LOCK();
+void
+fxSetupTexture(GLcontext * ctx)
+{
+   BEGIN_BOARD_LOCK();
+   fxSetupTexture_NoLock(ctx);
+   END_BOARD_LOCK();
 }
 
 /************************************************************************/
 /**************************** Blend SetUp *******************************/
 /************************************************************************/
 
-/* XXX consider supporting GL_INGR_blend_func_separate */
-void fxDDBlendFunc(GLcontext *ctx, GLenum sfactor, GLenum dfactor)
+void
+fxDDBlendFuncSeparate(GLcontext * ctx, GLenum sfactor, GLenum dfactor, GLenum asfactor, GLenum adfactor)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  tfxUnitsState *us=&fxMesa->unitsState;
-  GrAlphaBlendFnc_t sfact,dfact,asfact,adfact;
-
-  /* From the Glide documentation:
-     For alpha source and destination blend function factor
-     parameters, Voodoo Graphics supports only
-     GR_BLEND_ZERO and GR_BLEND_ONE.
-  */
-
-  switch(sfactor) {
-  case GL_ZERO:
-    asfact=sfact=GR_BLEND_ZERO;
-    break;
-  case GL_ONE:
-    asfact=sfact=GR_BLEND_ONE;
-    break;
-  case GL_DST_COLOR:
-    sfact=GR_BLEND_DST_COLOR;
-    asfact=GR_BLEND_ONE;
-    break;
-  case GL_ONE_MINUS_DST_COLOR:
-    sfact=GR_BLEND_ONE_MINUS_DST_COLOR;
-    asfact=GR_BLEND_ONE;
-    break;
-  case GL_SRC_ALPHA:
-    sfact=GR_BLEND_SRC_ALPHA;
-    asfact=GR_BLEND_ONE;
-    break;
-  case GL_ONE_MINUS_SRC_ALPHA:
-    sfact=GR_BLEND_ONE_MINUS_SRC_ALPHA;
-    asfact=GR_BLEND_ONE;
-    break;
-  case GL_DST_ALPHA:
-    sfact=GR_BLEND_DST_ALPHA;
-    asfact=GR_BLEND_ONE;
-    break;
-  case GL_ONE_MINUS_DST_ALPHA:
-    sfact=GR_BLEND_ONE_MINUS_DST_ALPHA;
-    asfact=GR_BLEND_ONE;
-    break;
-  case GL_SRC_ALPHA_SATURATE:
-    sfact=GR_BLEND_ALPHA_SATURATE;
-    asfact=GR_BLEND_ONE;
-    break;
-  case GL_SRC_COLOR:
-  case GL_ONE_MINUS_SRC_COLOR:
-    /* USELESS */
-    asfact=sfact=GR_BLEND_ONE;
-    break;
-  default:
-    asfact=sfact=GR_BLEND_ONE;
-    break;
-  }
-
-  if((sfact!=us->blendSrcFuncRGB) ||
-     (asfact!=us->blendSrcFuncAlpha)) {
-    us->blendSrcFuncRGB=sfact;
-    us->blendSrcFuncAlpha=asfact;
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   tfxUnitsState *us = &fxMesa->unitsState;
+   GLboolean isNapalm = (fxMesa->type >= GR_SSTTYPE_Voodoo4);
+   GLboolean have32bpp = (fxMesa->colDepth == 32);
+   GLboolean haveAlpha = fxMesa->haveHwAlpha;
+   GrAlphaBlendFnc_t sfact, dfact, asfact, adfact;
+
+   /*
+    * 15/16 BPP alpha channel alpha blending modes
+    *   0x0    AZERO           Zero
+    *   0x4    AONE            One
+    *
+    * 32 BPP alpha channel alpha blending modes
+    *   0x0    AZERO           Zero
+    *   0x1    ASRC_ALPHA      Source alpha
+    *   0x3    ADST_ALPHA      Destination alpha
+    *   0x4    AONE            One
+    *   0x5    AOMSRC_ALPHA    1 - Source alpha
+    *   0x7    AOMDST_ALPHA    1 - Destination alpha
+    *
+    * If we don't have HW alpha buffer:
+    *   DST_ALPHA == 1
+    *   ONE_MINUS_DST_ALPHA == 0
+    * Unsupported modes are:
+    *   1 if used as src blending factor
+    *   0 if used as dst blending factor
+    */
+
+   switch (sfactor) {
+   case GL_ZERO:
+      sfact = GR_BLEND_ZERO;
+      break;
+   case GL_ONE:
+      sfact = GR_BLEND_ONE;
+      break;
+   case GL_DST_COLOR:
+      sfact = GR_BLEND_DST_COLOR;
+      break;
+   case GL_ONE_MINUS_DST_COLOR:
+      sfact = GR_BLEND_ONE_MINUS_DST_COLOR;
+      break;
+   case GL_SRC_ALPHA:
+      sfact = GR_BLEND_SRC_ALPHA;
+      break;
+   case GL_ONE_MINUS_SRC_ALPHA:
+      sfact = GR_BLEND_ONE_MINUS_SRC_ALPHA;
+      break;
+   case GL_DST_ALPHA:
+      sfact = haveAlpha ? GR_BLEND_DST_ALPHA : GR_BLEND_ONE/*bad*/;
+      break;
+   case GL_ONE_MINUS_DST_ALPHA:
+      sfact = haveAlpha ? GR_BLEND_ONE_MINUS_DST_ALPHA : GR_BLEND_ZERO/*bad*/;
+      break;
+   case GL_SRC_ALPHA_SATURATE:
+      sfact = GR_BLEND_ALPHA_SATURATE;
+      break;
+   case GL_SRC_COLOR:
+      if (isNapalm) {
+         sfact = GR_BLEND_SAME_COLOR_EXT;
+         break;
+      }
+   case GL_ONE_MINUS_SRC_COLOR:
+      if (isNapalm) {
+         sfact = GR_BLEND_ONE_MINUS_SAME_COLOR_EXT;
+         break;
+      }
+   default:
+      sfact = GR_BLEND_ONE;
+      break;
+   }
+
+   switch (asfactor) {
+   case GL_ZERO:
+      asfact = GR_BLEND_ZERO;
+      break;
+   case GL_ONE:
+      asfact = GR_BLEND_ONE;
+      break;
+   case GL_SRC_COLOR:
+   case GL_SRC_ALPHA:
+      asfact = have32bpp ? GR_BLEND_SRC_ALPHA : GR_BLEND_ONE/*bad*/;
+      break;
+   case GL_ONE_MINUS_SRC_COLOR:
+   case GL_ONE_MINUS_SRC_ALPHA:
+      asfact = have32bpp ? GR_BLEND_ONE_MINUS_SRC_ALPHA : GR_BLEND_ONE/*bad*/;
+      break;
+   case GL_DST_COLOR:
+   case GL_DST_ALPHA:
+      asfact = (have32bpp && haveAlpha) ? GR_BLEND_DST_ALPHA : GR_BLEND_ONE/*bad*/;
+      break;
+   case GL_ONE_MINUS_DST_COLOR:
+   case GL_ONE_MINUS_DST_ALPHA:
+      asfact = (have32bpp && haveAlpha) ? GR_BLEND_ONE_MINUS_DST_ALPHA : GR_BLEND_ZERO/*bad*/;
+      break;
+   case GL_SRC_ALPHA_SATURATE:
+      asfact = GR_BLEND_ONE;
+      break;
+   default:
+      asfact = GR_BLEND_ONE;
+      break;
+   }
+
+   switch (dfactor) {
+   case GL_ZERO:
+      dfact = GR_BLEND_ZERO;
+      break;
+   case GL_ONE:
+      dfact = GR_BLEND_ONE;
+      break;
+   case GL_SRC_COLOR:
+      dfact = GR_BLEND_SRC_COLOR;
+      break;
+   case GL_ONE_MINUS_SRC_COLOR:
+      dfact = GR_BLEND_ONE_MINUS_SRC_COLOR;
+      break;
+   case GL_SRC_ALPHA:
+      dfact = GR_BLEND_SRC_ALPHA;
+      break;
+   case GL_ONE_MINUS_SRC_ALPHA:
+      dfact = GR_BLEND_ONE_MINUS_SRC_ALPHA;
+      break;
+   case GL_DST_ALPHA:
+      dfact = haveAlpha ? GR_BLEND_DST_ALPHA : GR_BLEND_ONE/*bad*/;
+      break;
+   case GL_ONE_MINUS_DST_ALPHA:
+      dfact = haveAlpha ? GR_BLEND_ONE_MINUS_DST_ALPHA : GR_BLEND_ZERO/*bad*/;
+      break;
+   case GL_DST_COLOR:
+      if (isNapalm) {
+         dfact = GR_BLEND_SAME_COLOR_EXT;
+         break;
+      }
+   case GL_ONE_MINUS_DST_COLOR:
+      if (isNapalm) {
+         dfact = GR_BLEND_ONE_MINUS_SAME_COLOR_EXT;
+         break;
+      }
+   default:
+      dfact = GR_BLEND_ZERO;
+      break;
+   }
+
+   switch (adfactor) {
+   case GL_ZERO:
+      adfact = GR_BLEND_ZERO;
+      break;
+   case GL_ONE:
+      adfact = GR_BLEND_ONE;
+      break;
+   case GL_SRC_COLOR:
+   case GL_SRC_ALPHA:
+      adfact = have32bpp ? GR_BLEND_SRC_ALPHA : GR_BLEND_ZERO/*bad*/;
+      break;
+   case GL_ONE_MINUS_SRC_COLOR:
+   case GL_ONE_MINUS_SRC_ALPHA:
+      adfact = have32bpp ? GR_BLEND_ONE_MINUS_SRC_ALPHA : GR_BLEND_ZERO/*bad*/;
+      break;
+   case GL_DST_COLOR:
+   case GL_DST_ALPHA:
+      adfact = (have32bpp && haveAlpha) ? GR_BLEND_DST_ALPHA : GR_BLEND_ONE/*bad*/;
+      break;
+   case GL_ONE_MINUS_DST_COLOR:
+   case GL_ONE_MINUS_DST_ALPHA:
+      adfact = (have32bpp && haveAlpha) ? GR_BLEND_ONE_MINUS_DST_ALPHA : GR_BLEND_ZERO/*bad*/;
+      break;
+   default:
+      adfact = GR_BLEND_ZERO;
+      break;
+   }
+
+   if ((sfact != us->blendSrcFuncRGB) || (asfact != us->blendSrcFuncAlpha)) {
+      us->blendSrcFuncRGB = sfact;
+      us->blendSrcFuncAlpha = asfact;
+      fxMesa->new_state |= FX_NEW_BLEND;
+   }
+
+   if ((dfact != us->blendDstFuncRGB) || (adfact != us->blendDstFuncAlpha)) {
+      us->blendDstFuncRGB = dfact;
+      us->blendDstFuncAlpha = adfact;
+      fxMesa->new_state |= FX_NEW_BLEND;
+   }
+}
+
+void
+fxDDBlendEquationSeparate(GLcontext * ctx, GLenum modeRGB, GLenum modeA)
+{
+ fxMesaContext fxMesa = FX_CONTEXT(ctx);
+ tfxUnitsState *us = &fxMesa->unitsState;
+ GrAlphaBlendOp_t q;
+
+ switch (modeRGB) {
+        case GL_FUNC_ADD:
+             q = GR_BLEND_OP_ADD;
+             break;
+        case GL_FUNC_SUBTRACT:
+             q = GR_BLEND_OP_SUB;
+             break;
+        case GL_FUNC_REVERSE_SUBTRACT:
+             q = GR_BLEND_OP_REVSUB;
+             break;
+        default:
+             q = us->blendEqRGB;
+ }
+ if (q != us->blendEqRGB) {
+    us->blendEqRGB = q;
     fxMesa->new_state |= FX_NEW_BLEND;
-    ctx->Driver.RenderStart = fxSetupFXUnits;
-  }
-
-  switch(dfactor) {
-  case GL_ZERO:
-    adfact=dfact=GR_BLEND_ZERO;
-    break;
-  case GL_ONE:
-    adfact=dfact=GR_BLEND_ONE;
-    break;
-  case GL_SRC_COLOR:
-    dfact=GR_BLEND_SRC_COLOR;
-    adfact=GR_BLEND_ZERO;
-    break;
-  case GL_ONE_MINUS_SRC_COLOR:
-    dfact=GR_BLEND_ONE_MINUS_SRC_COLOR;
-    adfact=GR_BLEND_ZERO;
-    break;
-  case GL_SRC_ALPHA:
-    dfact=GR_BLEND_SRC_ALPHA;
-    adfact=GR_BLEND_ZERO;
-    break;
-  case GL_ONE_MINUS_SRC_ALPHA:
-    dfact=GR_BLEND_ONE_MINUS_SRC_ALPHA;
-    adfact=GR_BLEND_ZERO;
-    break;
-  case GL_DST_ALPHA:
-    /* dfact=GR_BLEND_DST_ALPHA; */
-    /* We can't do DST_ALPHA */
-    dfact=GR_BLEND_ONE;
-    adfact=GR_BLEND_ZERO;
-    break;
-  case GL_ONE_MINUS_DST_ALPHA:
-    /* dfact=GR_BLEND_ONE_MINUS_DST_ALPHA; */
-    /* We can't do DST_ALPHA */
-    dfact=GR_BLEND_ZERO;
-    adfact=GR_BLEND_ZERO;
-    break;
-  case GL_SRC_ALPHA_SATURATE:
-  case GL_DST_COLOR:
-  case GL_ONE_MINUS_DST_COLOR:
-    /* USELESS */
-    adfact=dfact=GR_BLEND_ZERO;
-    break;
-  default:
-    adfact=dfact=GR_BLEND_ZERO;
-    break;
-  }
-
-  if((dfact!=us->blendDstFuncRGB) ||
-     (adfact!=us->blendDstFuncAlpha)) {
-    us->blendDstFuncRGB=dfact;
-    us->blendDstFuncAlpha=adfact;
+ }
+
+ switch (modeA) {
+        case GL_FUNC_ADD:
+             q = GR_BLEND_OP_ADD;
+             break;
+        case GL_FUNC_SUBTRACT:
+             q = GR_BLEND_OP_SUB;
+             break;
+        case GL_FUNC_REVERSE_SUBTRACT:
+             q = GR_BLEND_OP_REVSUB;
+             break;
+        default:
+             q = us->blendEqAlpha;
+ }
+ if (q != us->blendEqAlpha) {
+    us->blendEqAlpha = q;
     fxMesa->new_state |= FX_NEW_BLEND;
-    ctx->Driver.RenderStart = fxSetupFXUnits;
-  }
+ }
 }
 
-static void fxSetupBlend(GLcontext *ctx)
+void
+fxSetupBlend(GLcontext * ctx)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  tfxUnitsState *us=&fxMesa->unitsState;
-
-  if(us->blendEnabled)
-     FX_grAlphaBlendFunction(us->blendSrcFuncRGB,us->blendDstFuncRGB,
-                         us->blendSrcFuncAlpha,us->blendDstFuncAlpha);
-  else
-     FX_grAlphaBlendFunction(GR_BLEND_ONE,GR_BLEND_ZERO,GR_BLEND_ONE,GR_BLEND_ZERO);
+ fxMesaContext fxMesa = FX_CONTEXT(ctx);
+ tfxUnitsState *us = &fxMesa->unitsState;
+
+ if (fxMesa->HavePixExt) {
+    if (us->blendEnabled) {
+       fxMesa->Glide.grAlphaBlendFunctionExt(us->blendSrcFuncRGB, us->blendDstFuncRGB,
+                                             us->blendEqRGB,
+                                             us->blendSrcFuncAlpha, us->blendDstFuncAlpha,
+                                             us->blendEqAlpha);
+    } else {
+       fxMesa->Glide.grAlphaBlendFunctionExt(GR_BLEND_ONE, GR_BLEND_ZERO,
+                                             GR_BLEND_OP_ADD,
+                                             GR_BLEND_ONE, GR_BLEND_ZERO,
+                                             GR_BLEND_OP_ADD);
+    }
+ } else {
+    if (us->blendEnabled) {
+       grAlphaBlendFunction(us->blendSrcFuncRGB, us->blendDstFuncRGB,
+                            us->blendSrcFuncAlpha, us->blendDstFuncAlpha);
+    } else {
+       grAlphaBlendFunction(GR_BLEND_ONE, GR_BLEND_ZERO,
+                            GR_BLEND_ONE, GR_BLEND_ZERO);
+    }
+ }
 }
-  
+
 /************************************************************************/
 /************************** Alpha Test SetUp ****************************/
 /************************************************************************/
 
-void fxDDAlphaFunc(GLcontext *ctx, GLenum func, GLclampf ref)
+void
+fxDDAlphaFunc(GLcontext * ctx, GLenum func, GLfloat ref)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  tfxUnitsState *us=&fxMesa->unitsState;
-  GrCmpFnc_t newfunc;
-
-  switch(func) {
-  case GL_NEVER:
-    newfunc=GR_CMP_NEVER;
-    break;
-  case GL_LESS:
-    newfunc=GR_CMP_LESS;
-    break;
-  case GL_EQUAL:
-    newfunc=GR_CMP_EQUAL;
-    break;
-  case GL_LEQUAL:
-    newfunc=GR_CMP_LEQUAL;
-    break;
-  case GL_GREATER:
-    newfunc=GR_CMP_GREATER;
-    break;
-  case GL_NOTEQUAL:
-    newfunc=GR_CMP_NOTEQUAL;
-    break;
-  case GL_GEQUAL:
-    newfunc=GR_CMP_GEQUAL;
-    break;
-  case GL_ALWAYS:
-    newfunc=GR_CMP_ALWAYS;
-    break;
-  default:
-    fprintf(stderr,"fx Driver: internal error in fxDDAlphaFunc()\n");
-    fxCloseHardware();
-    exit(-1);
-    break;
-  }
-
-  if(newfunc!=us->alphaTestFunc) {
-    us->alphaTestFunc=newfunc;
-    fxMesa->new_state |= FX_NEW_ALPHA;
-    ctx->Driver.RenderStart = fxSetupFXUnits;
-  }
-
-  if(ctx->Color.AlphaRef!=us->alphaTestRefValue) {
-    us->alphaTestRefValue=ctx->Color.AlphaRef;
-    fxMesa->new_state |= FX_NEW_ALPHA;
-    ctx->Driver.RenderStart = fxSetupFXUnits;
-  }
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   tfxUnitsState *us = &fxMesa->unitsState;
+
+   if (
+       (us->alphaTestFunc != func)
+       ||
+       (us->alphaTestRefValue != ref)
+      ) {
+      us->alphaTestFunc = func;
+      us->alphaTestRefValue = ref;
+      fxMesa->new_state |= FX_NEW_ALPHA;
+   }
 }
 
-static void fxSetupAlphaTest(GLcontext *ctx)
+static void
+fxSetupAlphaTest(GLcontext * ctx)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  tfxUnitsState *us=&fxMesa->unitsState;
-
-  if(us->alphaTestEnabled) {
-     FX_grAlphaTestFunction(us->alphaTestFunc);
-     FX_grAlphaTestReferenceValue(us->alphaTestRefValue);
-  } else
-     FX_grAlphaTestFunction(GR_CMP_ALWAYS);
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   tfxUnitsState *us = &fxMesa->unitsState;
+
+   if (us->alphaTestEnabled) {
+      GrAlpha_t ref = (GLint) (us->alphaTestRefValue * 255.0);
+      grAlphaTestFunction(us->alphaTestFunc - GL_NEVER + GR_CMP_NEVER);
+      grAlphaTestReferenceValue(ref);
+   }
+   else
+      grAlphaTestFunction(GR_CMP_ALWAYS);
 }
 
 /************************************************************************/
 /************************** Depth Test SetUp ****************************/
 /************************************************************************/
 
-void fxDDDepthFunc(GLcontext *ctx, GLenum func)
+void
+fxDDDepthFunc(GLcontext * ctx, GLenum func)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  tfxUnitsState *us=&fxMesa->unitsState;
-  GrCmpFnc_t dfunc;
-
-  switch(func) {
-  case GL_NEVER:
-    dfunc=GR_CMP_NEVER;
-    break;
-  case GL_LESS:
-    dfunc=GR_CMP_LESS;
-    break;
-  case GL_GEQUAL:
-    dfunc=GR_CMP_GEQUAL;
-    break;
-  case GL_LEQUAL:
-    dfunc=GR_CMP_LEQUAL;
-    break;
-  case GL_GREATER:
-    dfunc=GR_CMP_GREATER;
-    break;
-  case GL_NOTEQUAL:
-    dfunc=GR_CMP_NOTEQUAL;
-    break;
-  case GL_EQUAL:
-    dfunc=GR_CMP_EQUAL;
-    break;
-  case GL_ALWAYS:
-    dfunc=GR_CMP_ALWAYS;
-    break;
-  default:
-    fprintf(stderr,"fx Driver: internal error in fxDDDepthFunc()\n");
-    fxCloseHardware();
-    exit(-1);
-    break;
-  }
-
-  if(dfunc!=us->depthTestFunc) {
-    us->depthTestFunc=dfunc;
-    fxMesa->new_state |= FX_NEW_DEPTH;
-    ctx->Driver.RenderStart = fxSetupFXUnits;
-  }
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   tfxUnitsState *us = &fxMesa->unitsState;
 
+   if (us->depthTestFunc != func) {
+      us->depthTestFunc = func;
+      fxMesa->new_state |= FX_NEW_DEPTH;
+   }
 }
 
-void fxDDDepthMask(GLcontext *ctx, GLboolean flag)
+void
+fxDDDepthMask(GLcontext * ctx, GLboolean flag)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  tfxUnitsState *us=&fxMesa->unitsState;
-
-  if(flag!=us->depthMask) {
-    us->depthMask=flag;
-    fxMesa->new_state |= FX_NEW_DEPTH;
-    ctx->Driver.RenderStart = fxSetupFXUnits;
-  }
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   tfxUnitsState *us = &fxMesa->unitsState;
+
+   if (flag != us->depthMask) {
+      us->depthMask = flag;
+      fxMesa->new_state |= FX_NEW_DEPTH;
+   }
 }
 
-static void fxSetupDepthTest(GLcontext *ctx)
+void
+fxSetupDepthTest(GLcontext * ctx)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  tfxUnitsState *us=&fxMesa->unitsState;
-
-  if(us->depthTestEnabled)
-     FX_grDepthBufferFunction(us->depthTestFunc);
-  else
-     FX_grDepthBufferFunction(GR_CMP_ALWAYS);
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   tfxUnitsState *us = &fxMesa->unitsState;
 
-  FX_grDepthMask(us->depthMask);
+   if (us->depthTestEnabled) {
+      grDepthBufferFunction(us->depthTestFunc - GL_NEVER + GR_CMP_NEVER);
+      grDepthMask(us->depthMask);
+   }
+   else {
+      grDepthBufferFunction(GR_CMP_ALWAYS);
+      grDepthMask(FXFALSE);
+   }
 }
 
 /************************************************************************/
-/**************************** Color Mask SetUp **************************/
+/************************** Stencil SetUp *******************************/
 /************************************************************************/
 
-GLboolean fxDDColorMask(GLcontext *ctx, 
-                       GLboolean r, GLboolean g, 
-                       GLboolean b, GLboolean a )
+static GrStencil_t convertGLStencilOp( GLenum op )
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  fxMesa->new_state |= FX_NEW_COLOR_MASK;
-  ctx->Driver.RenderStart = fxSetupFXUnits;
-  (void) r; (void) g; (void) b; (void) a;
-  return GL_FALSE;
+   switch ( op ) {
+   case GL_KEEP:
+      return GR_STENCILOP_KEEP;
+   case GL_ZERO:
+      return GR_STENCILOP_ZERO;
+   case GL_REPLACE:
+      return GR_STENCILOP_REPLACE;
+   case GL_INCR:
+      return GR_STENCILOP_INCR_CLAMP;
+   case GL_DECR:
+      return GR_STENCILOP_DECR_CLAMP;
+   case GL_INVERT:
+      return GR_STENCILOP_INVERT;
+   case GL_INCR_WRAP_EXT:
+      return GR_STENCILOP_INCR_WRAP;
+   case GL_DECR_WRAP_EXT:
+      return GR_STENCILOP_DECR_WRAP;
+   default:
+      _mesa_problem( NULL, "bad stencil op in convertGLStencilOp" );
+   }
+   return GR_STENCILOP_KEEP;   /* never get, silence compiler warning */
 }
 
-static void fxSetupColorMask(GLcontext *ctx)
+void
+fxDDStencilFunc (GLcontext *ctx, GLenum func, GLint ref, GLuint mask)
 {
-  fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   tfxUnitsState *us = &fxMesa->unitsState;
+
+   if (
+       (us->stencilFunction != func)
+       ||
+       (us->stencilRefValue != ref)
+       ||
+       (us->stencilValueMask != mask)
+      ) {
+      us->stencilFunction = func;
+      us->stencilRefValue = ref;
+      us->stencilValueMask = mask;
+      fxMesa->new_state |= FX_NEW_STENCIL;
+   }
+}
 
-  FX_grColorMask(ctx->Color.ColorMask[RCOMP] ||
-             ctx->Color.ColorMask[GCOMP] ||
-             ctx->Color.ColorMask[BCOMP],
-             ctx->Color.ColorMask[ACOMP] && fxMesa->haveAlphaBuffer);
+void
+fxDDStencilMask (GLcontext *ctx, GLuint mask)
+{
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   tfxUnitsState *us = &fxMesa->unitsState;
+
+   if (us->stencilWriteMask != mask) {
+      us->stencilWriteMask = mask;
+      fxMesa->new_state |= FX_NEW_STENCIL;
+   }
 }
 
+void
+fxDDStencilOp (GLcontext *ctx, GLenum sfail, GLenum zfail, GLenum zpass)
+{
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   tfxUnitsState *us = &fxMesa->unitsState;
+
+   if (
+       (us->stencilFailFunc != sfail)
+       ||
+       (us->stencilZFailFunc != zfail)
+       ||
+       (us->stencilZPassFunc != zpass)
+      ) {
+      us->stencilFailFunc = sfail;
+      us->stencilZFailFunc = zfail;
+      us->stencilZPassFunc = zpass;
+      fxMesa->new_state |= FX_NEW_STENCIL;
+   }
+}
 
+void
+fxSetupStencil (GLcontext * ctx)
+{
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   tfxUnitsState *us = &fxMesa->unitsState;
+
+   if (us->stencilEnabled) {
+      grEnable(GR_STENCIL_MODE_EXT);
+      fxMesa->Glide.grStencilOpExt(convertGLStencilOp(us->stencilFailFunc),
+                                   convertGLStencilOp(us->stencilZFailFunc),
+                                   convertGLStencilOp(us->stencilZPassFunc));
+      fxMesa->Glide.grStencilFuncExt(us->stencilFunction - GL_NEVER + GR_CMP_NEVER,
+                                     us->stencilRefValue,
+                                     us->stencilValueMask);
+      fxMesa->Glide.grStencilMaskExt(us->stencilWriteMask);
+   } else {
+      grDisable(GR_STENCIL_MODE_EXT);
+   }
+}
 
 /************************************************************************/
-/**************************** Fog Mode SetUp ****************************/
+/**************************** Color Mask SetUp **************************/
 /************************************************************************/
 
-static void fxFogTableGenerate(GLcontext *ctx)
+void
+fxDDColorMask(GLcontext * ctx,
+             GLboolean r, GLboolean g, GLboolean b, GLboolean a)
 {
-  int i;
-  float f,eyez;
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-
-  for(i=0;i<FX_grGetInteger(FX_FOG_TABLE_ENTRIES);i++) {
-    eyez=guFogTableIndexToW(i);
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   fxMesa->new_state |= FX_NEW_COLOR_MASK;
+   (void) r;
+   (void) g;
+   (void) b;
+   (void) a;
+}
 
-    switch(ctx->Fog.Mode) {
-    case GL_LINEAR:
-      f=(ctx->Fog.End-eyez)/(ctx->Fog.End-ctx->Fog.Start);
-      break;
-    case GL_EXP:
-      f=exp(-ctx->Fog.Density*eyez);  
-      break;
-    case GL_EXP2:
-      f=exp(-ctx->Fog.Density*ctx->Fog.Density*eyez*eyez);
-      break;
-    default: /* That should never happen */
-      f=0.0f;
-      break; 
-    }
+void
+fxSetupColorMask(GLcontext * ctx)
+{
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
 
-    fxMesa->fogTable[i]=(GrFog_t)((1.0f-CLAMP(f,0.0f,1.0f))*255.0f);
-  }
+   if (fxMesa->colDepth == 32) {
+      /* 32bpp mode */
+      fxMesa->Glide.grColorMaskExt(ctx->Color.ColorMask[RCOMP],
+                                   ctx->Color.ColorMask[GCOMP],
+                                   ctx->Color.ColorMask[BCOMP],
+                                   ctx->Color.ColorMask[ACOMP] && fxMesa->haveHwAlpha);
+   }
+   else {
+      /* 15/16 bpp mode */
+      grColorMask(ctx->Color.ColorMask[RCOMP] |
+                  ctx->Color.ColorMask[GCOMP] |
+                  ctx->Color.ColorMask[BCOMP],
+                  ctx->Color.ColorMask[ACOMP] && fxMesa->haveHwAlpha);
+   }
 }
 
-static void fxSetupFog(GLcontext *ctx, GLboolean forceTableRebuild)
+
+
+
+/************************************************************************/
+/**************************** Fog Mode SetUp ****************************/
+/************************************************************************/
+
+/*
+ * This is called during state update in order to update the Glide fog state.
+ */
+static void
+fxSetupFog(GLcontext * ctx)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-
-  if(ctx->Fog.Enabled && ctx->FogMode==FOG_FRAGMENT) {
-    GLubyte col[4];
-    FX_grFogMode(GR_FOG_WITH_TABLE);
-
-    col[0]=(unsigned int)(255*ctx->Fog.Color[0]);
-    col[1]=(unsigned int)(255*ctx->Fog.Color[1]);
-    col[2]=(unsigned int)(255*ctx->Fog.Color[2]); 
-    col[3]=(unsigned int)(255*ctx->Fog.Color[3]);
-
-    FX_grFogColorValue(FXCOLOR4(col));
-
-    if(forceTableRebuild ||
-       (fxMesa->fogTableMode!=ctx->Fog.Mode) ||
-       (fxMesa->fogDensity!=ctx->Fog.Density)) {
-      fxFogTableGenerate(ctx);
-         
-      fxMesa->fogTableMode=ctx->Fog.Mode;
-      fxMesa->fogDensity=ctx->Fog.Density;
-    }
-      
-    FX_grFogTable(fxMesa->fogTable);
-  } else
-    FX_grFogMode(GR_FOG_DISABLE);
+   if (ctx->Fog.Enabled /*&& ctx->FogMode==FOG_FRAGMENT */ ) {
+      fxMesaContext fxMesa = FX_CONTEXT(ctx);
+
+      /* update fog color */
+      GLubyte col[4];
+      col[0] = (unsigned int) (255 * ctx->Fog.Color[0]);
+      col[1] = (unsigned int) (255 * ctx->Fog.Color[1]);
+      col[2] = (unsigned int) (255 * ctx->Fog.Color[2]);
+      col[3] = (unsigned int) (255 * ctx->Fog.Color[3]);
+      grFogColorValue(FXCOLOR4(col));
+
+      if (fxMesa->fogTableMode != ctx->Fog.Mode ||
+         fxMesa->fogDensity != ctx->Fog.Density ||
+         fxMesa->fogStart != ctx->Fog.Start ||
+         fxMesa->fogEnd != ctx->Fog.End) {
+        /* reload the fog table */
+        switch (ctx->Fog.Mode) {
+        case GL_LINEAR:
+           guFogGenerateLinear(fxMesa->fogTable, ctx->Fog.Start,
+                               ctx->Fog.End);
+           if (fxMesa->fogTable[0] > 63) {
+              /* [dBorca] Hack alert:
+               * As per Glide3 Programming Guide:
+               * The difference between consecutive fog values
+               * must be less than 64.
+               */
+              fxMesa->fogTable[0] = 63;
+           }
+           break;
+        case GL_EXP:
+           guFogGenerateExp(fxMesa->fogTable, ctx->Fog.Density);
+           break;
+        case GL_EXP2:
+           guFogGenerateExp2(fxMesa->fogTable, ctx->Fog.Density);
+           break;
+        default:
+           ;
+        }
+        fxMesa->fogTableMode = ctx->Fog.Mode;
+        fxMesa->fogDensity = ctx->Fog.Density;
+        fxMesa->fogStart = ctx->Fog.Start;
+        fxMesa->fogEnd = ctx->Fog.End;
+      }
+
+      grFogTable(fxMesa->fogTable);
+      if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT) {
+         grVertexLayout(GR_PARAM_FOG_EXT, GR_VERTEX_FOG_OFFSET << 2,
+                                          GR_PARAM_ENABLE);
+         grFogMode(GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT);
+      } else {
+         grVertexLayout(GR_PARAM_FOG_EXT, GR_VERTEX_FOG_OFFSET << 2,
+                                          GR_PARAM_DISABLE);
+         grFogMode(GR_FOG_WITH_TABLE_ON_Q);
+      }
+   }
+   else {
+      grFogMode(GR_FOG_DISABLE);
+   }
 }
 
-void fxDDFogfv( GLcontext *ctx, GLenum pname, const GLfloat *params )
+void
+fxDDFogfv(GLcontext * ctx, GLenum pname, const GLfloat * params)
 {
    FX_CONTEXT(ctx)->new_state |= FX_NEW_FOG;
-   ctx->Driver.RenderStart = fxSetupFXUnits;
+   switch (pname) {
+      case GL_FOG_COORDINATE_SOURCE_EXT: {
+         GLenum p = (GLenum)*params;
+         if (p == GL_FOG_COORDINATE_EXT) {
+            _swrast_allow_vertex_fog(ctx, GL_TRUE);
+            _swrast_allow_pixel_fog(ctx, GL_FALSE);
+            _tnl_allow_vertex_fog( ctx, GL_TRUE);
+            _tnl_allow_pixel_fog( ctx, GL_FALSE);
+         } else {
+            _swrast_allow_vertex_fog(ctx, GL_FALSE);
+            _swrast_allow_pixel_fog(ctx, GL_TRUE);
+            _tnl_allow_vertex_fog( ctx, GL_FALSE);
+            _tnl_allow_pixel_fog( ctx, GL_TRUE);
+         }
+         break;
+      }
+      default:
+         ;
+   }
 }
 
 /************************************************************************/
@@ -1492,52 +1929,54 @@ void fxDDFogfv( GLcontext *ctx, GLenum pname, const GLfloat *params )
 /************************************************************************/
 
 /* This routine is used in managing the lock state, and therefore can't lock */
-void fxSetScissorValues(GLcontext *ctx)
+void
+fxSetScissorValues(GLcontext * ctx)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  int xmin, xmax;
-  int ymin, ymax, check;
-
-  if (ctx->Scissor.Enabled) {
-    xmin=ctx->Scissor.X;
-    xmax=ctx->Scissor.X+ctx->Scissor.Width;
-    ymin=ctx->Scissor.Y;
-    ymax=ctx->Scissor.Y+ctx->Scissor.Height;
-    check=1;
-  } else {
-    xmin=0;
-    ymin=0;
-    xmax=fxMesa->width;
-    ymax=fxMesa->height;
-    check=0;
-  }
-  xmin+=fxMesa->x_offset;
-  xmax+=fxMesa->x_offset;
-  ymin+=fxMesa->y_delta;
-  ymax+=fxMesa->y_delta;
-  if (xmin<fxMesa->clipMinX) xmin=fxMesa->clipMinX;
-  if (xmax>fxMesa->clipMaxX) xmax=fxMesa->clipMaxX;
-  if (ymin<fxMesa->screen_height-fxMesa->clipMaxY) 
-    ymin=fxMesa->screen_height-fxMesa->clipMaxY;
-  if (ymax>fxMesa->screen_height-fxMesa->clipMinY)
-    ymax=fxMesa->screen_height-fxMesa->clipMinY;
-  FX_grClipWindow_NoLock(xmin, ymin, xmax, ymax);
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   int xmin, xmax;
+   int ymin, ymax;
+
+   if (ctx->Scissor.Enabled) {
+      xmin = ctx->Scissor.X;
+      xmax = ctx->Scissor.X + ctx->Scissor.Width;
+      ymin = ctx->Scissor.Y;
+      ymax = ctx->Scissor.Y + ctx->Scissor.Height;
+
+      if (xmin < 0)
+         xmin = 0;
+      if (xmax > fxMesa->width)
+         xmax = fxMesa->width;
+      if (ymin < fxMesa->screen_height - fxMesa->height)
+         ymin = fxMesa->screen_height - fxMesa->height;
+      if (ymax > fxMesa->screen_height - 0)
+         ymax = fxMesa->screen_height - 0;
+   }
+   else {
+      xmin = 0;
+      ymin = 0;
+      xmax = fxMesa->width;
+      ymax = fxMesa->height;
+   }
+
+   fxMesa->clipMinX = xmin;
+   fxMesa->clipMinY = ymin;
+   fxMesa->clipMaxX = xmax;
+   fxMesa->clipMaxY = ymax;
+   grClipWindow(xmin, ymin, xmax, ymax);
 }
 
-static void fxSetupScissor(GLcontext *ctx)
+void
+fxSetupScissor(GLcontext * ctx)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  if (!fxMesa->needClip) {
-    BEGIN_BOARD_LOCK();
-    fxSetScissorValues(ctx);
-    END_BOARD_LOCK();
-  }
+   BEGIN_BOARD_LOCK();
+   fxSetScissorValues(ctx);
+   END_BOARD_LOCK();
 }
 
-void fxDDScissor( GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h )
+void
+fxDDScissor(GLcontext * ctx, GLint x, GLint y, GLsizei w, GLsizei h)
 {
    FX_CONTEXT(ctx)->new_state |= FX_NEW_SCISSOR;
-   ctx->Driver.RenderStart = fxSetupFXUnits;
 }
 
 /************************************************************************/
@@ -1545,45 +1984,54 @@ void fxDDScissor( GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h )
 /************************************************************************/
 
 
-void fxDDCullFace(GLcontext *ctx, GLenum mode)
+void
+fxDDCullFace(GLcontext * ctx, GLenum mode)
 {
    (void) mode;
    FX_CONTEXT(ctx)->new_state |= FX_NEW_CULL;
-   ctx->Driver.RenderStart = fxSetupFXUnits;   
 }
 
-void fxDDFrontFace(GLcontext *ctx, GLenum mode)
+void
+fxDDFrontFace(GLcontext * ctx, GLenum mode)
 {
    (void) mode;
    FX_CONTEXT(ctx)->new_state |= FX_NEW_CULL;
-   ctx->Driver.RenderStart = fxSetupFXUnits;   
 }
 
 
-static void fxSetupCull(GLcontext *ctx)
+void
+fxSetupCull(GLcontext * ctx)
 {
-  if (ctx->Polygon.CullFlag) {
-    switch (ctx->Polygon.CullFaceMode) {
-    case GL_BACK:
-      if (ctx->Polygon.FrontFace==GL_CCW)
-       FX_CONTEXT(ctx)->cullMode=GR_CULL_NEGATIVE;
-      else
-       FX_CONTEXT(ctx)->cullMode=GR_CULL_POSITIVE;
-      break;
-    case GL_FRONT:
-      if(ctx->Polygon.FrontFace==GL_CCW)
-       FX_CONTEXT(ctx)->cullMode=GR_CULL_POSITIVE;
-      else
-       FX_CONTEXT(ctx)->cullMode=GR_CULL_NEGATIVE;
-      break;
-    case GL_FRONT_AND_BACK:
-      FX_CONTEXT(ctx)->cullMode=GR_CULL_DISABLE;
-      break;
-    default:
-      break;
-    }
-  } else FX_CONTEXT(ctx)->cullMode=GR_CULL_DISABLE;
-  FX_grCullMode(FX_CONTEXT(ctx)->cullMode);
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   GrCullMode_t mode = GR_CULL_DISABLE;
+
+   if (ctx->Polygon.CullFlag && (fxMesa->raster_primitive == GL_TRIANGLES)) {
+      switch (ctx->Polygon.CullFaceMode) {
+      case GL_BACK:
+        if (ctx->Polygon.FrontFace == GL_CCW)
+           mode = GR_CULL_NEGATIVE;
+        else
+           mode = GR_CULL_POSITIVE;
+        break;
+      case GL_FRONT:
+        if (ctx->Polygon.FrontFace == GL_CCW)
+           mode = GR_CULL_POSITIVE;
+        else
+           mode = GR_CULL_NEGATIVE;
+        break;
+      case GL_FRONT_AND_BACK:
+        /* Handled as a fallback on triangles in tdfx_tris.c */
+        return;
+      default:
+        ASSERT(0);
+        break;
+      }
+   }
+
+   if (fxMesa->cullMode != mode) {
+      fxMesa->cullMode = mode;
+      grCullMode(mode);
+   }
 }
 
 
@@ -1591,183 +2039,78 @@ static void fxSetupCull(GLcontext *ctx)
 /****************************** DD Enable ******************************/
 /************************************************************************/
 
-void fxDDEnable(GLcontext *ctx, GLenum cap, GLboolean state)
+void
+fxDDEnable(GLcontext * ctx, GLenum cap, GLboolean state)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  tfxUnitsState *us=&fxMesa->unitsState;
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   tfxUnitsState *us = &fxMesa->unitsState;
 
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
-     fprintf(stderr,"fxmesa: fxDDEnable(...)\n");
-  }
+   if (TDFX_DEBUG & VERBOSE_DRIVER) {
+      fprintf(stderr, "%s(%s)\n", state ? "fxDDEnable" : "fxDDDisable",
+             _mesa_lookup_enum_by_nr(cap));
+   }
 
-  switch(cap) {
-  case GL_ALPHA_TEST:
-    if(state!=us->alphaTestEnabled) {
-      us->alphaTestEnabled=state;
-      fxMesa->new_state |= FX_NEW_ALPHA;
-      ctx->Driver.RenderStart = fxSetupFXUnits;
-    }
-    break;
-  case GL_BLEND:
-    if(state!=us->blendEnabled) {
-      us->blendEnabled=state;
-      fxMesa->new_state |= FX_NEW_BLEND;
-      ctx->Driver.RenderStart = fxSetupFXUnits;
-    }
-    break;
-  case GL_DEPTH_TEST:
-    if(state!=us->depthTestEnabled) {
-      us->depthTestEnabled=state;
-      fxMesa->new_state |= FX_NEW_DEPTH;
-      ctx->Driver.RenderStart = fxSetupFXUnits;
-    }
-    break;
-  case GL_SCISSOR_TEST:
-     fxMesa->new_state |= FX_NEW_SCISSOR;
-     ctx->Driver.RenderStart = fxSetupFXUnits;
-     break;
-  case GL_FOG:
-     fxMesa->new_state |= FX_NEW_FOG;
-     ctx->Driver.RenderStart = fxSetupFXUnits;
-     break;
-  case GL_CULL_FACE:
-     fxMesa->new_state |= FX_NEW_CULL;
-     ctx->Driver.RenderStart = fxSetupFXUnits;
-     break;
-  case GL_LINE_SMOOTH:
-  case GL_POINT_SMOOTH:
-  case GL_POLYGON_SMOOTH:
-  case GL_TEXTURE_2D:
-      fxMesa->new_state |= FX_NEW_TEXTURING;
-      ctx->Driver.RenderStart = fxSetupFXUnits;
+   switch (cap) {
+   case GL_ALPHA_TEST:
+      if (state != us->alphaTestEnabled) {
+        us->alphaTestEnabled = state;
+        fxMesa->new_state |= FX_NEW_ALPHA;
+      }
       break;
-  default:
-    ;  /* XXX no-op??? */
-  }    
-}
-
-#if 0
-/*
-  Multipass to do GL_BLEND texture functions
-  Cf*(1-Ct) has already been written to the buffer during the first pass
-  Cc*Ct gets written during the second pass (in this function)
-  Everything gets reset in the third call (in this function)
-*/
-static GLboolean fxMultipassBlend(struct vertex_buffer *VB, GLuint pass)
-{
-  GLcontext *ctx = VB->ctx;
-  fxMesaContext fxMesa = FX_CONTEXT(ctx);
-
-  switch (pass) {
-  case 1:
-    /* Add Cc*Ct */
-    fxMesa->restoreUnitsState=fxMesa->unitsState;
-    if (ctx->Depth.Mask) {
-      /* We don't want to check or change the depth buffers */
-      switch (ctx->Depth.Func) {
-      case GL_NEVER:
-      case GL_ALWAYS:
-       break;
-      default:
-       fxDDDepthFunc(ctx, GL_EQUAL);
-       break;
+   case GL_BLEND:
+      if (state != us->blendEnabled) {
+        us->blendEnabled = state;
+        fxMesa->new_state |= FX_NEW_BLEND;
       }
-      fxDDDepthMask(ctx, FALSE);
-    }
-    /* Enable Cc*Ct mode */
-    /* ??? Set the Constant Color ??? */
-    fxDDEnable(ctx, GL_BLEND, GL_TRUE);
-    fxDDBlendFunc(ctx, ???, ???);
-    fxSetupTextureSingleTMU(ctx, ???);
-    fxSetupBlend(ctx);
-    fxSetupDepthTest(ctx);
-    break;
-
-  case 2:
-    /* Reset everything back to normal */
-    fxMesa->unitsState = fxMesa->restoreUnitsState;
-    fxMesa->setupdone &= ???;
-    fxSetupTextureSingleTMU(ctx, ???);
-    fxSetupBlend(ctx);
-    fxSetupDepthTest(ctx);
-    break;
-  }
-
-  return pass==1;
-}
-#endif
-
-/************************************************************************/
-/******************** Fake Multitexture Support *************************/
-/************************************************************************/
-
-/* Its considered cheeky to try to fake ARB multitexture by doing
- * multipass rendering, because it is not possible to emulate the full
- * spec in this way.  The fact is that the voodoo 2 supports only a
- * subset of the possible multitexturing modes, and it is possible to
- * support almost the same subset using multipass blending on the
- * voodoo 1.  In all other cases for both voodoo 1 and 2, we fall back
- * to software rendering, satisfying the spec if not the user.  
- */
-static GLboolean fxMultipassTexture( struct vertex_buffer *VB, GLuint pass )
-{
-   GLcontext *ctx = VB->ctx;
-   fxVertex *v = FX_DRIVER_DATA(VB)->verts;
-   fxVertex *last = FX_DRIVER_DATA(VB)->last_vert;
-   fxMesaContext fxMesa = FX_CONTEXT(ctx);
-
-   switch (pass) {
-   case 1:
-      if (MESA_VERBOSE&(VERBOSE_DRIVER|VERBOSE_PIPELINE|VERBOSE_TEXTURE))
-        fprintf(stderr, "fxmesa: Second texture pass\n");
-
-      for ( ; v != last ; v++) {
-        v->f[S0COORD] = v->f[S1COORD];
-        v->f[T0COORD] = v->f[T1COORD];
+      break;
+   case GL_DEPTH_TEST:
+      if (state != us->depthTestEnabled) {
+        us->depthTestEnabled = state;
+        fxMesa->new_state |= FX_NEW_DEPTH;
       }
-
-      fxMesa->restoreUnitsState = fxMesa->unitsState; 
-      fxMesa->tmu_source[0] = 1;
-
-      if (ctx->Depth.Mask) {
-        switch (ctx->Depth.Func) {
-        case GL_NEVER:
-        case GL_ALWAYS:
-           break;
-        default:
-           fxDDDepthFunc( ctx, GL_EQUAL );
-           break;
-        }
-
-        fxDDDepthMask( ctx, GL_FALSE ); 
+      break;
+   case GL_STENCIL_TEST:
+      if (fxMesa->haveHwStencil && state != us->stencilEnabled) {
+        us->stencilEnabled = state;
+        fxMesa->new_state |= FX_NEW_STENCIL;
       }
-      
-      if (ctx->Texture.Unit[1].EnvMode == GL_MODULATE) {
-        fxDDEnable( ctx, GL_BLEND, GL_TRUE );
-        fxDDBlendFunc( ctx, GL_DST_COLOR, GL_ZERO );
+      break;
+   case GL_DITHER:
+      if (state) {
+        grDitherMode(GR_DITHER_4x4);
+      }
+      else {
+        grDitherMode(GR_DITHER_DISABLE);
       }
-
-      fxSetupTextureSingleTMU( ctx, 1 ); 
-      fxSetupBlend( ctx );
-      fxSetupDepthTest( ctx );
       break;
-
-   case 2:
-      /* Restore original state.  
-       */
-      fxMesa->tmu_source[0] = 0;
-      fxMesa->unitsState = fxMesa->restoreUnitsState;
-      fxMesa->setupdone &= ~SETUP_TMU0;
-      fxSetupTextureSingleTMU( ctx, 0 ); 
-      fxSetupBlend( ctx );
-      fxSetupDepthTest( ctx );
+   case GL_SCISSOR_TEST:
+      fxMesa->new_state |= FX_NEW_SCISSOR;
+      break;
+   case GL_SHARED_TEXTURE_PALETTE_EXT:
+      fxDDTexUseGlbPalette(ctx, state);
+      break;
+   case GL_FOG:
+      fxMesa->new_state |= FX_NEW_FOG;
+      break;
+   case GL_CULL_FACE:
+      fxMesa->new_state |= FX_NEW_CULL;
       break;
+   case GL_LINE_SMOOTH:
+   case GL_LINE_STIPPLE:
+   case GL_POINT_SMOOTH:
+   case GL_POLYGON_SMOOTH:
+   case GL_TEXTURE_1D:
+   case GL_TEXTURE_2D:
+      fxMesa->new_state |= FX_NEW_TEXTURING;
+      break;
+   default:
+      ;                                /* XXX no-op? */
    }
-
-   return pass == 1;      
 }
 
 
+
+
 /************************************************************************/
 /************************** Changes to units state **********************/
 /************************************************************************/
@@ -1775,10 +2118,10 @@ static GLboolean fxMultipassTexture( struct vertex_buffer *VB, GLuint pass )
 
 /* All units setup is handled under texture setup.
  */
-void fxDDShadeModel(GLcontext *ctx, GLenum mode)
+void
+fxDDShadeModel(GLcontext * ctx, GLenum mode)
 {
    FX_CONTEXT(ctx)->new_state |= FX_NEW_TEXTURING;
-   ctx->Driver.RenderStart = fxSetupFXUnits;
 }
 
 
@@ -1786,57 +2129,62 @@ void fxDDShadeModel(GLcontext *ctx, GLenum mode)
 /************************************************************************/
 /****************************** Units SetUp *****************************/
 /************************************************************************/
-static void gl_print_fx_state_flags( const char *msg, GLuint flags )
+static void
+fx_print_state_flags(const char *msg, GLuint flags)
 {
-   fprintf(stderr, 
-          "%s: (0x%x) %s%s%s%s%s%s%s\n",
+   fprintf(stderr,
+          "%s: (0x%x) %s%s%s%s%s%s%s%s\n",
           msg,
           flags,
-          (flags & FX_NEW_TEXTURING)   ? "texture, " : "",
-          (flags & FX_NEW_BLEND)       ? "blend, " : "",
-          (flags & FX_NEW_ALPHA)       ? "alpha, " : "",
-          (flags & FX_NEW_FOG)         ? "fog, " : "",
-          (flags & FX_NEW_SCISSOR)     ? "scissor, " : "",
-          (flags & FX_NEW_COLOR_MASK)  ? "colormask, " : "",
-          (flags & FX_NEW_CULL)        ? "cull, " : "");
+          (flags & FX_NEW_TEXTURING) ? "texture, " : "",
+          (flags & FX_NEW_BLEND) ? "blend, " : "",
+          (flags & FX_NEW_ALPHA) ? "alpha, " : "",
+          (flags & FX_NEW_FOG) ? "fog, " : "",
+          (flags & FX_NEW_SCISSOR) ? "scissor, " : "",
+          (flags & FX_NEW_COLOR_MASK) ? "colormask, " : "",
+          (flags & FX_NEW_CULL) ? "cull, " : "",
+          (flags & FX_NEW_STENCIL) ? "stencil, " : "");
 }
 
-void fxSetupFXUnits( GLcontext *ctx )
+void
+fxSetupFXUnits(GLcontext * ctx)
 {
-  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  GLuint newstate = fxMesa->new_state;
+   fxMesaContext fxMesa = FX_CONTEXT(ctx);
+   GLuint newstate = fxMesa->new_state;
 
-  if (MESA_VERBOSE&VERBOSE_DRIVER)
-     gl_print_fx_state_flags("fxmesa: fxSetupFXUnits", newstate);
+   if (TDFX_DEBUG & VERBOSE_DRIVER)
+      fx_print_state_flags("fxSetupFXUnits", newstate);
 
-  if (newstate) {
-     if (newstate & FX_NEW_TEXTURING)
-       fxSetupTexture(ctx);
+   if (newstate) {
+      if (newstate & FX_NEW_TEXTURING)
+        fxSetupTexture(ctx);
 
-     if (newstate & FX_NEW_BLEND)
-       fxSetupBlend(ctx);
+      if (newstate & FX_NEW_BLEND)
+        fxSetupBlend(ctx);
 
-     if (newstate & FX_NEW_ALPHA)
-       fxSetupAlphaTest(ctx);
-     
-     if (newstate & FX_NEW_DEPTH)
-       fxSetupDepthTest(ctx);
+      if (newstate & FX_NEW_ALPHA)
+        fxSetupAlphaTest(ctx);
 
-     if (newstate & FX_NEW_FOG)
-       fxSetupFog(ctx,GL_FALSE);
+      if (newstate & FX_NEW_DEPTH)
+        fxSetupDepthTest(ctx);
 
-     if (newstate & FX_NEW_SCISSOR)
-       fxSetupScissor(ctx);
+      if (newstate & FX_NEW_STENCIL)
+        fxSetupStencil(ctx);
 
-     if (newstate & FX_NEW_COLOR_MASK)
-       fxSetupColorMask(ctx);
+      if (newstate & FX_NEW_FOG)
+        fxSetupFog(ctx);
 
-     if (newstate & FX_NEW_CULL)
-       fxSetupCull(ctx);     
+      if (newstate & FX_NEW_SCISSOR)
+        fxSetupScissor(ctx);
 
-     fxMesa->new_state = 0;
-/*       ctx->Driver.RenderStart = 0; */
-  }
+      if (newstate & FX_NEW_COLOR_MASK)
+        fxSetupColorMask(ctx);
+
+      if (newstate & FX_NEW_CULL)
+        fxSetupCull(ctx);
+
+      fxMesa->new_state = 0;
+   }
 }
 
 
@@ -1848,9 +2196,11 @@ void fxSetupFXUnits( GLcontext *ctx )
  * Need this to provide at least one external definition.
  */
 
-int gl_fx_dummy_function_setup(void)
+extern int gl_fx_dummy_function_setup(void);
+int
+gl_fx_dummy_function_setup(void)
 {
-  return 0;
+   return 0;
 }
 
-#endif  /* FX */
+#endif /* FX */