GL_(UN)PACK_SKIP_IMAGES should only be applied to 3D texture pack/unpacking
[mesa.git] / src / mesa / drivers / dri / r200 / r200_texstate.c
index 8e171669c438d405f99f67fe080d311e82e5d2f4..1e56c78f9bee0800d63dc3b3565e057cffb54aea 100644 (file)
@@ -48,19 +48,29 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "r200_tcl.h"
 
 
+#define R200_TXFORMAT_A8        R200_TXFORMAT_I8
+#define R200_TXFORMAT_L8        R200_TXFORMAT_I8
 #define R200_TXFORMAT_AL88      R200_TXFORMAT_AI88
 #define R200_TXFORMAT_YCBCR     R200_TXFORMAT_YVYU422
 #define R200_TXFORMAT_YCBCR_REV R200_TXFORMAT_VYUY422
+#define R200_TXFORMAT_RGB_DXT1  R200_TXFORMAT_DXT1
+#define R200_TXFORMAT_RGBA_DXT1 R200_TXFORMAT_DXT1
+#define R200_TXFORMAT_RGBA_DXT3 R200_TXFORMAT_DXT23
+#define R200_TXFORMAT_RGBA_DXT5 R200_TXFORMAT_DXT45
 
 #define _COLOR(f) \
     [ MESA_FORMAT_ ## f ] = { R200_TXFORMAT_ ## f, 0 }
+#define _COLOR_REV(f) \
+    [ MESA_FORMAT_ ## f ## _REV ] = { R200_TXFORMAT_ ## f, 0 }
 #define _ALPHA(f) \
     [ MESA_FORMAT_ ## f ] = { R200_TXFORMAT_ ## f | R200_TXFORMAT_ALPHA_IN_MAP, 0 }
+#define _ALPHA_REV(f) \
+    [ MESA_FORMAT_ ## f ## _REV ] = { R200_TXFORMAT_ ## f | R200_TXFORMAT_ALPHA_IN_MAP, 0 }
 #define _YUV(f) \
     [ MESA_FORMAT_ ## f ] = { R200_TXFORMAT_ ## f, R200_YUV_TO_RGB }
 #define _INVALID(f) \
     [ MESA_FORMAT_ ## f ] = { 0xffffffff, 0 }
-#define VALID_FORMAT(f) ( ((f) <= MESA_FORMAT_YCBCR_REV) \
+#define VALID_FORMAT(f) ( ((f) <= MESA_FORMAT_RGBA_DXT5) \
                             && (tx_table[f].format != 0xffffffff) )
 
 static const struct {
@@ -69,18 +79,30 @@ static const struct {
 tx_table[] =
 {
    _ALPHA(RGBA8888),
+   _ALPHA_REV(RGBA8888),
    _ALPHA(ARGB8888),
+   _ALPHA_REV(ARGB8888),
    _INVALID(RGB888),
    _COLOR(RGB565),
+   _COLOR_REV(RGB565),
    _ALPHA(ARGB4444),
+   _ALPHA_REV(ARGB4444),
    _ALPHA(ARGB1555),
+   _ALPHA_REV(ARGB1555),
    _ALPHA(AL88),
-   _INVALID(A8),
-   _INVALID(L8),
-   _COLOR(I8),
+   _ALPHA_REV(AL88),
+   _ALPHA(A8),
+   _COLOR(L8),
+   _ALPHA(I8),
    _INVALID(CI8),
    _YUV(YCBCR),
    _YUV(YCBCR_REV),
+   _INVALID(RGB_FXT1),
+   _INVALID(RGBA_FXT1),
+   _COLOR(RGB_DXT1),
+   _ALPHA(RGBA_DXT1),
+   _ALPHA(RGBA_DXT3),
+   _ALPHA(RGBA_DXT5),
 };
 
 #undef _COLOR
@@ -153,7 +175,24 @@ static void r200SetTexImages( r200ContextPtr rmesa,
 
       /* find image size in bytes */
       if (texImage->IsCompressed) {
-         size = texImage->CompressedSize;
+      /* need to calculate the size AFTER padding even though the texture is
+         submitted without padding.
+         Only handle pot textures currently - don't know if npot is even possible,
+         size calculation would certainly need (trivial) adjustments.
+         Align (and later pad) to 32byte, not sure what that 64byte blit width is
+         good for? */
+         if ((t->pp_txformat & R200_TXFORMAT_FORMAT_MASK) == R200_TXFORMAT_DXT1) {
+            /* RGB_DXT1/RGBA_DXT1, 8 bytes per block */
+            if ((texImage->Width + 3) < 8) /* width one block */
+               size = texImage->CompressedSize * 4;
+            else if ((texImage->Width + 3) < 16)
+               size = texImage->CompressedSize * 2;
+            else size = texImage->CompressedSize;
+         }
+         else /* DXT3/5, 16 bytes per block */
+            if ((texImage->Width + 3) < 8)
+               size = texImage->CompressedSize * 2;
+            else size = texImage->CompressedSize;
       }
       else if (tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
          size = ((texImage->Width * texImage->TexFormat->TexelBytes + 63)
@@ -240,7 +279,7 @@ static void r200SetTexImages( r200ContextPtr rmesa,
       t->pp_txformat_x |= R200_TEXCOORD_VOLUME;
    }
    else if (tObj->Target == GL_TEXTURE_CUBE_MAP) {
-      ASSERT(log2Width == log2height);
+      ASSERT(log2Width == log2Height);
       t->pp_txformat |= ((log2Width << R200_TXFORMAT_F5_WIDTH_SHIFT) |
                          (log2Height << R200_TXFORMAT_F5_HEIGHT_SHIFT) |
                          (R200_TXFORMAT_CUBIC_MAP_ENABLE));
@@ -254,6 +293,12 @@ static void r200SetTexImages( r200ContextPtr rmesa,
                            (log2Width << R200_FACE_WIDTH_4_SHIFT) |
                            (log2Height << R200_FACE_HEIGHT_4_SHIFT));
    }
+   else {
+      /* If we don't in fact send enough texture coordinates, q will be 1,
+       * making TEXCOORD_PROJ act like TEXCOORD_NONPROJ (Right?)
+       */
+      t->pp_txformat_x |= R200_TEXCOORD_PROJ;
+   }
 
    t->pp_txsize = (((tObj->Image[0][t->base.firstLevel]->Width - 1) << 0) |
                    ((tObj->Image[0][t->base.firstLevel]->Height - 1) << 16));
@@ -279,304 +324,6 @@ static void r200SetTexImages( r200ContextPtr rmesa,
  * Texture combine functions
  */
 
-#define R200_DISABLE           0
-#define R200_REPLACE           1
-#define R200_MODULATE          2
-#define R200_DECAL             3
-#define R200_BLEND             4
-#define R200_ADD               5
-#define R200_MAX_COMBFUNC      6
-
-static GLuint r200_color_combine[][R200_MAX_COMBFUNC] =
-{
-   /* Unit 0:
-    */
-   {
-      /* Disable combiner stage
-       */
-      (R200_TXC_ARG_A_ZERO  |
-       R200_TXC_ARG_B_ZERO |
-       R200_TXC_ARG_C_DIFFUSE_COLOR |
-       R200_TXC_OP_MADD),
-
-      /* GL_REPLACE = 0x00802800
-       */
-      (R200_TXC_ARG_A_ZERO |
-       R200_TXC_ARG_B_ZERO |
-       R200_TXC_ARG_C_R0_COLOR |
-       R200_TXC_OP_MADD),
-
-      /* GL_MODULATE = 0x00800142
-       */
-      (R200_TXC_ARG_A_DIFFUSE_COLOR | /* current starts in DIFFUSE */
-       R200_TXC_ARG_B_R0_COLOR |
-       R200_TXC_ARG_C_ZERO |
-       R200_TXC_OP_MADD),
-
-      /* GL_DECAL = 0x008c2d42
-       */
-      (R200_TXC_ARG_A_DIFFUSE_COLOR |
-       R200_TXC_ARG_B_R0_COLOR |
-       R200_TXC_ARG_C_R0_ALPHA |
-       R200_TXC_OP_LERP),
-
-      /* GL_BLEND = 0x008c2902
-       */
-      (R200_TXC_ARG_A_DIFFUSE_COLOR |
-       R200_TXC_ARG_B_TFACTOR_COLOR |
-       R200_TXC_ARG_C_R0_COLOR |
-       R200_TXC_OP_LERP),
-
-      /* GL_ADD = 0x00812802
-       */
-      (R200_TXC_ARG_A_DIFFUSE_COLOR |
-       R200_TXC_ARG_B_ZERO |
-       R200_TXC_ARG_C_R0_COLOR |
-       R200_TXC_COMP_ARG_B |
-       R200_TXC_OP_MADD),
-   },
-
-   /* Unit 1:
-    */
-   {
-      /* Disable combiner stage
-       */
-      (R200_TXC_ARG_A_ZERO |
-       R200_TXC_ARG_B_ZERO |
-       R200_TXC_ARG_C_R0_COLOR |
-       R200_TXC_OP_MADD),
-
-      /* GL_REPLACE = 0x00803000
-       */
-      (R200_TXC_ARG_A_ZERO |
-       R200_TXC_ARG_B_ZERO |
-       R200_TXC_ARG_C_R1_COLOR |
-       R200_TXC_OP_MADD),
-
-      /* GL_MODULATE = 0x00800182
-       */
-      (R200_TXC_ARG_A_R0_COLOR | /* current in R0 thereafter */
-       R200_TXC_ARG_B_R1_COLOR |
-       R200_TXC_ARG_C_ZERO |
-       R200_TXC_OP_MADD),
-
-      /* GL_DECAL = 0x008c3582
-       */
-      (R200_TXC_ARG_A_R0_COLOR |
-       R200_TXC_ARG_B_R1_COLOR |
-       R200_TXC_ARG_C_R1_ALPHA |
-       R200_TXC_OP_LERP),
-
-      /* GL_BLEND = 0x008c3102
-       */
-      (R200_TXC_ARG_A_R0_COLOR |
-       R200_TXC_ARG_B_TFACTOR_COLOR |
-       R200_TXC_ARG_C_R1_COLOR |
-       R200_TXC_OP_LERP),
-
-      /* GL_ADD = 0x00813002
-       */
-      (R200_TXC_ARG_A_R0_COLOR |
-       R200_TXC_ARG_B_ZERO |
-       R200_TXC_ARG_C_R1_COLOR |
-       R200_TXC_COMP_ARG_B |
-       R200_TXC_OP_MADD),
-   },
-
-   /* Unit 2:
-    */
-   {
-      /* Disable combiner stage
-       */
-      (R200_TXC_ARG_A_ZERO |
-       R200_TXC_ARG_B_ZERO |
-       R200_TXC_ARG_C_R0_COLOR |
-       R200_TXC_OP_MADD),
-
-      /* GL_REPLACE = 0x00803800
-       */
-      (R200_TXC_ARG_A_ZERO |
-       R200_TXC_ARG_B_ZERO |
-       R200_TXC_ARG_C_R2_COLOR |
-       R200_TXC_OP_MADD),
-
-      /* GL_MODULATE = 0x008001c2
-       */
-      (R200_TXC_ARG_A_R0_COLOR |
-       R200_TXC_ARG_B_R2_COLOR |
-       R200_TXC_ARG_C_ZERO |
-       R200_TXC_OP_MADD),
-
-      /* GL_DECAL = 0x008c3dc2
-       */
-      (R200_TXC_ARG_A_R0_COLOR |
-       R200_TXC_ARG_B_R2_COLOR |
-       R200_TXC_ARG_C_R2_ALPHA |
-       R200_TXC_OP_LERP),
-
-      /* GL_BLEND = 0x008c3902
-       */
-      (R200_TXC_ARG_A_R0_COLOR |
-       R200_TXC_ARG_B_TFACTOR_COLOR |
-       R200_TXC_ARG_C_R2_COLOR |
-       R200_TXC_OP_LERP),
-
-      /* GL_ADD = 0x00813802
-       */
-      (R200_TXC_ARG_A_R0_COLOR |
-       R200_TXC_ARG_B_ZERO |
-       R200_TXC_ARG_C_R2_COLOR |
-       R200_TXC_COMP_ARG_B |
-       R200_TXC_OP_MADD),
-   }
-};
-
-static GLuint r200_alpha_combine[][R200_MAX_COMBFUNC] =
-{
-   /* Unit 0:
-    */
-   {
-      /* Disable combiner stage
-       */
-      (R200_TXA_ARG_A_ZERO |
-       R200_TXA_ARG_B_ZERO |
-       R200_TXA_ARG_C_DIFFUSE_ALPHA |
-       R200_TXA_OP_MADD),
-
-
-      /* GL_REPLACE = 0x00800500
-       */
-      (R200_TXA_ARG_A_ZERO |
-       R200_TXA_ARG_B_ZERO |
-       R200_TXA_ARG_C_R0_ALPHA |
-       R200_TXA_OP_MADD),
-
-      /* GL_MODULATE = 0x00800051
-       */
-      (R200_TXA_ARG_A_DIFFUSE_ALPHA |
-       R200_TXA_ARG_B_R0_ALPHA |
-       R200_TXA_ARG_C_ZERO |
-       R200_TXA_OP_MADD),
-
-      /* GL_DECAL = 0x00800100
-       */
-      (R200_TXA_ARG_A_ZERO |
-       R200_TXA_ARG_B_ZERO |
-       R200_TXA_ARG_C_DIFFUSE_ALPHA |
-       R200_TXA_OP_MADD),
-
-      /* GL_BLEND = 0x00800051
-       */
-      (R200_TXA_ARG_A_DIFFUSE_ALPHA |
-       R200_TXA_ARG_B_TFACTOR_ALPHA |
-       R200_TXA_ARG_C_R0_ALPHA |
-       R200_TXA_OP_LERP),
-
-      /* GL_ADD = 0x00800051
-       */
-      (R200_TXA_ARG_A_DIFFUSE_ALPHA |
-       R200_TXA_ARG_B_ZERO |
-       R200_TXA_ARG_C_R0_ALPHA |
-       R200_TXA_COMP_ARG_B |
-       R200_TXA_OP_MADD),
-   },
-
-   /* Unit 1:
-    */
-   {
-      /* Disable combiner stage
-       */
-      (R200_TXA_ARG_A_ZERO |
-       R200_TXA_ARG_B_ZERO |
-       R200_TXA_ARG_C_R0_ALPHA |
-       R200_TXA_OP_MADD),
-
-      /* GL_REPLACE = 0x00800600
-       */
-      (R200_TXA_ARG_A_ZERO |
-       R200_TXA_ARG_B_ZERO |
-       R200_TXA_ARG_C_R1_ALPHA |
-       R200_TXA_OP_MADD),
-
-      /* GL_MODULATE = 0x00800061
-       */
-      (R200_TXA_ARG_A_R0_ALPHA |
-       R200_TXA_ARG_B_R1_ALPHA |
-       R200_TXA_ARG_C_ZERO |
-       R200_TXA_OP_MADD),
-
-      /* GL_DECAL = 0x00800100
-       */
-      (R200_TXA_ARG_A_ZERO |
-       R200_TXA_ARG_B_ZERO |
-       R200_TXA_ARG_C_R0_ALPHA |
-       R200_TXA_OP_MADD),
-
-      /* GL_BLEND = 0x00800061
-       */
-      (R200_TXA_ARG_A_R0_ALPHA |
-       R200_TXA_ARG_B_TFACTOR_ALPHA |
-       R200_TXA_ARG_C_R1_ALPHA |
-       R200_TXA_OP_LERP),
-
-      /* GL_ADD = 0x00800061
-       */
-      (R200_TXA_ARG_A_R0_ALPHA |
-       R200_TXA_ARG_B_ZERO |
-       R200_TXA_ARG_C_R1_ALPHA |
-       R200_TXA_COMP_ARG_B |
-       R200_TXA_OP_MADD),
-   },
-
-   /* Unit 2:
-    */
-   {
-      /* Disable combiner stage
-       */
-      (R200_TXA_ARG_A_ZERO |
-       R200_TXA_ARG_B_ZERO |
-       R200_TXA_ARG_C_R0_ALPHA |
-       R200_TXA_OP_MADD),
-
-      /* GL_REPLACE = 0x00800700
-       */
-      (R200_TXA_ARG_A_ZERO |
-       R200_TXA_ARG_B_ZERO |
-       R200_TXA_ARG_C_R2_ALPHA |
-       R200_TXA_OP_MADD),
-
-      /* GL_MODULATE = 0x00800071
-       */
-      (R200_TXA_ARG_A_R0_ALPHA |
-       R200_TXA_ARG_B_R2_ALPHA |
-       R200_TXA_ARG_C_ZERO |
-       R200_TXA_OP_MADD),
-
-      /* GL_DECAL = 0x00800100
-       */
-      (R200_TXA_ARG_A_ZERO |
-       R200_TXA_ARG_B_ZERO |
-       R200_TXA_ARG_C_R0_ALPHA |
-       R200_TXA_OP_MADD),
-
-      /* GL_BLEND = 0x00800071
-       */
-      (R200_TXA_ARG_A_R0_ALPHA |
-       R200_TXA_ARG_B_TFACTOR_ALPHA |
-       R200_TXA_ARG_C_R2_ALPHA |
-       R200_TXA_OP_LERP),
-
-      /* GL_ADD = 0x00800021
-       */
-      (R200_TXA_ARG_A_R0_ALPHA |
-       R200_TXA_ARG_B_ZERO |
-       R200_TXA_ARG_C_R2_ALPHA |
-       R200_TXA_COMP_ARG_B |
-       R200_TXA_OP_MADD),
-   }
-};
-
-
 /* GL_ARB_texture_env_combine support
  */
 
@@ -588,22 +335,34 @@ static GLuint r200_register_color[][R200_MAX_TEXTURE_UNITS] =
    {
       R200_TXC_ARG_A_R0_COLOR,
       R200_TXC_ARG_A_R1_COLOR,
-      R200_TXC_ARG_A_R2_COLOR
+      R200_TXC_ARG_A_R2_COLOR,
+      R200_TXC_ARG_A_R3_COLOR,
+      R200_TXC_ARG_A_R4_COLOR,
+      R200_TXC_ARG_A_R5_COLOR
    },
    {
       R200_TXC_ARG_A_R0_COLOR | R200_TXC_COMP_ARG_A,
       R200_TXC_ARG_A_R1_COLOR | R200_TXC_COMP_ARG_A,
-      R200_TXC_ARG_A_R2_COLOR | R200_TXC_COMP_ARG_A
+      R200_TXC_ARG_A_R2_COLOR | R200_TXC_COMP_ARG_A,
+      R200_TXC_ARG_A_R3_COLOR | R200_TXC_COMP_ARG_A,
+      R200_TXC_ARG_A_R4_COLOR | R200_TXC_COMP_ARG_A,
+      R200_TXC_ARG_A_R5_COLOR | R200_TXC_COMP_ARG_A
    },
    {
       R200_TXC_ARG_A_R0_ALPHA,
       R200_TXC_ARG_A_R1_ALPHA,
-      R200_TXC_ARG_A_R2_ALPHA
+      R200_TXC_ARG_A_R2_ALPHA,
+      R200_TXC_ARG_A_R3_ALPHA,
+      R200_TXC_ARG_A_R4_ALPHA,
+      R200_TXC_ARG_A_R5_ALPHA
    },
    {
       R200_TXC_ARG_A_R0_ALPHA | R200_TXC_COMP_ARG_A,
       R200_TXC_ARG_A_R1_ALPHA | R200_TXC_COMP_ARG_A,
-      R200_TXC_ARG_A_R2_ALPHA | R200_TXC_COMP_ARG_A
+      R200_TXC_ARG_A_R2_ALPHA | R200_TXC_COMP_ARG_A,
+      R200_TXC_ARG_A_R3_ALPHA | R200_TXC_COMP_ARG_A,
+      R200_TXC_ARG_A_R4_ALPHA | R200_TXC_COMP_ARG_A,
+      R200_TXC_ARG_A_R5_ALPHA | R200_TXC_COMP_ARG_A
    },
 };
 
@@ -642,12 +401,18 @@ static GLuint r200_register_alpha[][R200_MAX_TEXTURE_UNITS] =
    {
       R200_TXA_ARG_A_R0_ALPHA,
       R200_TXA_ARG_A_R1_ALPHA,
-      R200_TXA_ARG_A_R2_ALPHA
+      R200_TXA_ARG_A_R2_ALPHA,
+      R200_TXA_ARG_A_R3_ALPHA,
+      R200_TXA_ARG_A_R4_ALPHA,
+      R200_TXA_ARG_A_R5_ALPHA
    },
    {
       R200_TXA_ARG_A_R0_ALPHA | R200_TXA_COMP_ARG_A,
       R200_TXA_ARG_A_R1_ALPHA | R200_TXA_COMP_ARG_A,
-      R200_TXA_ARG_A_R2_ALPHA | R200_TXA_COMP_ARG_A
+      R200_TXA_ARG_A_R2_ALPHA | R200_TXA_COMP_ARG_A,
+      R200_TXA_ARG_A_R3_ALPHA | R200_TXA_COMP_ARG_A,
+      R200_TXA_ARG_A_R4_ALPHA | R200_TXA_COMP_ARG_A,
+      R200_TXA_ARG_A_R5_ALPHA | R200_TXA_COMP_ARG_A
    },
 };
 
@@ -707,8 +472,10 @@ static GLboolean r200UpdateTextureEnv( GLcontext *ctx, int unit )
    r200ContextPtr rmesa = R200_CONTEXT(ctx);
    const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
    GLuint color_combine, alpha_combine;
-   GLuint color_scale = rmesa->hw.pix[unit].cmd[PIX_PP_TXCBLEND2];
-   GLuint alpha_scale = rmesa->hw.pix[unit].cmd[PIX_PP_TXABLEND2];
+   GLuint color_scale = rmesa->hw.pix[unit].cmd[PIX_PP_TXCBLEND2] &
+      ~(R200_TXC_SCALE_MASK);
+   GLuint alpha_scale = rmesa->hw.pix[unit].cmd[PIX_PP_TXABLEND2] &
+      ~(R200_TXA_DOT_ALPHA | R200_TXA_SCALE_MASK);
 
    /* texUnit->_Current can be NULL if and only if the texture unit is
     * not actually enabled.
@@ -726,448 +493,279 @@ static GLboolean r200UpdateTextureEnv( GLcontext *ctx, int unit )
     * reduces the amount of special-casing we have to do, alpha-only
     * textures being a notable exception.
     */
+   /* Don't cache these results.
+    */
+   rmesa->state.texture.unit[unit].format = 0;
+   rmesa->state.texture.unit[unit].envMode = 0;
+
    if ( !texUnit->_ReallyEnabled ) {
-      /* Don't cache these results.
-       */
-      rmesa->state.texture.unit[unit].format = 0;
-      rmesa->state.texture.unit[unit].envMode = 0;
-      color_combine = r200_color_combine[unit][R200_DISABLE];
-      alpha_combine = r200_alpha_combine[unit][R200_DISABLE];
+      if ( unit == 0 ) {
+        color_combine = R200_TXC_ARG_A_ZERO | R200_TXC_ARG_B_ZERO
+            | R200_TXC_ARG_C_DIFFUSE_COLOR | R200_TXC_OP_MADD;
+        alpha_combine = R200_TXA_ARG_A_ZERO | R200_TXA_ARG_B_ZERO
+            | R200_TXA_ARG_C_DIFFUSE_ALPHA | R200_TXA_OP_MADD;
+      }
+      else {
+        color_combine = R200_TXC_ARG_A_ZERO | R200_TXC_ARG_B_ZERO
+            | R200_TXC_ARG_C_R0_COLOR | R200_TXC_OP_MADD;
+        alpha_combine = R200_TXA_ARG_A_ZERO | R200_TXA_ARG_B_ZERO
+            | R200_TXA_ARG_C_R0_ALPHA | R200_TXA_OP_MADD;
+      }
    }
    else {
-      const struct gl_texture_object *tObj = texUnit->_Current;
-      const GLenum format = tObj->Image[0][tObj->BaseLevel]->Format;
       GLuint color_arg[3], alpha_arg[3];
-      GLuint i, numColorArgs = 0, numAlphaArgs = 0;
-      GLuint RGBshift = texUnit->CombineScaleShiftRGB;
-      GLuint Ashift = texUnit->CombineScaleShiftA;
+      GLuint i;
+      const GLuint numColorArgs = texUnit->_CurrentCombine->_NumArgsRGB;
+      const GLuint numAlphaArgs = texUnit->_CurrentCombine->_NumArgsA;
+      GLuint RGBshift = texUnit->_CurrentCombine->ScaleShiftRGB;
+      GLuint Ashift = texUnit->_CurrentCombine->ScaleShiftA;
 
-      switch ( texUnit->EnvMode ) {
-      case GL_REPLACE:
-        switch ( format ) {
-        case GL_RGBA:
-        case GL_LUMINANCE_ALPHA:
-        case GL_INTENSITY:
-           color_combine = r200_color_combine[unit][R200_REPLACE];
-           alpha_combine = r200_alpha_combine[unit][R200_REPLACE];
-           break;
-        case GL_ALPHA:
-           color_combine = r200_color_combine[unit][R200_DISABLE];
-           alpha_combine = r200_alpha_combine[unit][R200_REPLACE];
-           break;
-        case GL_LUMINANCE:
-        case GL_RGB:
-        case GL_YCBCR_MESA:
-           color_combine = r200_color_combine[unit][R200_REPLACE];
-           alpha_combine = r200_alpha_combine[unit][R200_DISABLE];
-           break;
-        case GL_COLOR_INDEX:
-        default:
-           return GL_FALSE;
-        }
-        break;
 
-      case GL_MODULATE:
-        switch ( format ) {
-        case GL_RGBA:
-        case GL_LUMINANCE_ALPHA:
-        case GL_INTENSITY:
-           color_combine = r200_color_combine[unit][R200_MODULATE];
-           alpha_combine = r200_alpha_combine[unit][R200_MODULATE];
+      /* Step 1:
+       * Extract the color and alpha combine function arguments.
+       */
+      for ( i = 0 ; i < numColorArgs ; i++ ) {
+        const GLint op = texUnit->_CurrentCombine->OperandRGB[i] - GL_SRC_COLOR;
+        assert(op >= 0);
+        assert(op <= 3);
+        switch ( texUnit->_CurrentCombine->SourceRGB[i] ) {
+        case GL_TEXTURE:
+           color_arg[i] = r200_register_color[op][unit];
            break;
-        case GL_ALPHA:
-           color_combine = r200_color_combine[unit][R200_DISABLE];
-           alpha_combine = r200_alpha_combine[unit][R200_MODULATE];
+        case GL_CONSTANT:
+           color_arg[i] = r200_tfactor_color[op];
            break;
-        case GL_RGB:
-        case GL_LUMINANCE:
-        case GL_YCBCR_MESA:
-           color_combine = r200_color_combine[unit][R200_MODULATE];
-           alpha_combine = r200_alpha_combine[unit][R200_DISABLE];
+        case GL_PRIMARY_COLOR:
+           color_arg[i] = r200_primary_color[op];
            break;
-        case GL_COLOR_INDEX:
-        default:
-           return GL_FALSE;
-        }
-        break;
-
-      case GL_DECAL:
-        switch ( format ) {
-        case GL_RGBA:
-        case GL_RGB:
-        case GL_YCBCR_MESA:
-           color_combine = r200_color_combine[unit][R200_DECAL];
-           alpha_combine = r200_alpha_combine[unit][R200_DISABLE];
+        case GL_PREVIOUS:
+           if (unit == 0)
+               color_arg[i] = r200_primary_color[op];
+           else
+               color_arg[i] = r200_register_color[op][0];
            break;
-        case GL_ALPHA:
-        case GL_LUMINANCE:
-        case GL_LUMINANCE_ALPHA:
-        case GL_INTENSITY:
-           color_combine = r200_color_combine[unit][R200_DISABLE];
-           alpha_combine = r200_alpha_combine[unit][R200_DISABLE];
+        case GL_ZERO:
+           color_arg[i] = r200_zero_color[op];
            break;
-        case GL_COLOR_INDEX:
-        default:
-           return GL_FALSE;
-        }
-        break;
-
-      case GL_BLEND:
-        switch ( format ) {
-        case GL_RGBA:
-        case GL_RGB:
-        case GL_LUMINANCE:
-        case GL_LUMINANCE_ALPHA:
-        case GL_YCBCR_MESA:
-           color_combine = r200_color_combine[unit][R200_BLEND];
-           alpha_combine = r200_alpha_combine[unit][R200_MODULATE];
+        case GL_ONE:
+           color_arg[i] = r200_zero_color[op+1];
            break;
-        case GL_ALPHA:
-           color_combine = r200_color_combine[unit][R200_DISABLE];
-           alpha_combine = r200_alpha_combine[unit][R200_MODULATE];
-           break;
-        case GL_INTENSITY:
-           color_combine = r200_color_combine[unit][R200_BLEND];
-           alpha_combine = r200_alpha_combine[unit][R200_BLEND];
-           break;
-        case GL_COLOR_INDEX:
         default:
            return GL_FALSE;
         }
-        break;
+      }
 
-      case GL_ADD:
-        switch ( format ) {
-        case GL_RGBA:
-        case GL_RGB:
-        case GL_LUMINANCE:
-        case GL_LUMINANCE_ALPHA:
-        case GL_YCBCR_MESA:
-           color_combine = r200_color_combine[unit][R200_ADD];
-           alpha_combine = r200_alpha_combine[unit][R200_MODULATE];
+      for ( i = 0 ; i < numAlphaArgs ; i++ ) {
+        const GLint op = texUnit->_CurrentCombine->OperandA[i] - GL_SRC_ALPHA;
+        assert(op >= 0);
+        assert(op <= 1);
+        switch ( texUnit->_CurrentCombine->SourceA[i] ) {
+        case GL_TEXTURE:
+           alpha_arg[i] = r200_register_alpha[op][unit];
            break;
-        case GL_ALPHA:
-           color_combine = r200_color_combine[unit][R200_DISABLE];
-           alpha_combine = r200_alpha_combine[unit][R200_MODULATE];
+        case GL_CONSTANT:
+           alpha_arg[i] = r200_tfactor_alpha[op];
            break;
-        case GL_INTENSITY:
-           color_combine = r200_color_combine[unit][R200_ADD];
-           alpha_combine = r200_alpha_combine[unit][R200_ADD];
+        case GL_PRIMARY_COLOR:
+           alpha_arg[i] = r200_primary_alpha[op];
            break;
-        case GL_COLOR_INDEX:
-        default:
-           return GL_FALSE;
-        }
-        break;
-
-      case GL_COMBINE:
-        /* Don't cache these results.
-         */
-        rmesa->state.texture.unit[unit].format = 0;
-        rmesa->state.texture.unit[unit].envMode = 0;
-
-        /* Step 0:
-         * Calculate how many arguments we need to process.
-         */
-        switch ( texUnit->CombineModeRGB ) {
-        case GL_REPLACE:
-           numColorArgs = 1;
+        case GL_PREVIOUS:
+           if (unit == 0)
+               alpha_arg[i] = r200_primary_alpha[op];
+           else
+               alpha_arg[i] = r200_register_alpha[op][0];
            break;
-        case GL_MODULATE:
-        case GL_ADD:
-        case GL_ADD_SIGNED:
-        case GL_SUBTRACT:
-        case GL_DOT3_RGB:
-        case GL_DOT3_RGBA:
-        case GL_DOT3_RGB_EXT:
-        case GL_DOT3_RGBA_EXT:
-           numColorArgs = 2;
+        case GL_ZERO:
+           alpha_arg[i] = r200_zero_alpha[op];
            break;
-        case GL_INTERPOLATE:
-        case GL_MODULATE_ADD_ATI:
-        case GL_MODULATE_SIGNED_ADD_ATI:
-        case GL_MODULATE_SUBTRACT_ATI:
-           numColorArgs = 3;
+        case GL_ONE:
+           alpha_arg[i] = r200_zero_alpha[op+1];
            break;
         default:
            return GL_FALSE;
         }
+      }
 
-        switch ( texUnit->CombineModeA ) {
-        case GL_REPLACE:
-           numAlphaArgs = 1;
-           break;
-        case GL_MODULATE:
-        case GL_ADD:
-        case GL_ADD_SIGNED:
-        case GL_SUBTRACT:
-           numAlphaArgs = 2;
-           break;
-        case GL_INTERPOLATE:
-        case GL_MODULATE_ADD_ATI:
-        case GL_MODULATE_SIGNED_ADD_ATI:
-        case GL_MODULATE_SUBTRACT_ATI:
-           numAlphaArgs = 3;
-           break;
-        default:
-           return GL_FALSE;
-        }
+      /* Step 2:
+       * Build up the color and alpha combine functions.
+       */
+      switch ( texUnit->_CurrentCombine->ModeRGB ) {
+      case GL_REPLACE:
+        color_combine = (R200_TXC_ARG_A_ZERO |
+                         R200_TXC_ARG_B_ZERO |
+                         R200_TXC_OP_MADD);
+        R200_COLOR_ARG( 0, C );
+        break;
+      case GL_MODULATE:
+        color_combine = (R200_TXC_ARG_C_ZERO |
+                         R200_TXC_OP_MADD);
+        R200_COLOR_ARG( 0, A );
+        R200_COLOR_ARG( 1, B );
+        break;
+      case GL_ADD:
+        color_combine = (R200_TXC_ARG_B_ZERO |
+                         R200_TXC_COMP_ARG_B | 
+                         R200_TXC_OP_MADD);
+        R200_COLOR_ARG( 0, A );
+        R200_COLOR_ARG( 1, C );
+        break;
+      case GL_ADD_SIGNED:
+        color_combine = (R200_TXC_ARG_B_ZERO |
+                         R200_TXC_COMP_ARG_B |
+                         R200_TXC_BIAS_ARG_C | /* new */
+                         R200_TXC_OP_MADD); /* was ADDSIGNED */
+        R200_COLOR_ARG( 0, A );
+        R200_COLOR_ARG( 1, C );
+        break;
+      case GL_SUBTRACT:
+        color_combine = (R200_TXC_ARG_B_ZERO |
+                         R200_TXC_COMP_ARG_B | 
+                         R200_TXC_NEG_ARG_C |
+                         R200_TXC_OP_MADD);
+        R200_COLOR_ARG( 0, A );
+        R200_COLOR_ARG( 1, C );
+        break;
+      case GL_INTERPOLATE:
+        color_combine = (R200_TXC_OP_LERP);
+        R200_COLOR_ARG( 0, B );
+        R200_COLOR_ARG( 1, A );
+        R200_COLOR_ARG( 2, C );
+        break;
 
-        /* Step 1:
-         * Extract the color and alpha combine function arguments.
+      case GL_DOT3_RGB_EXT:
+      case GL_DOT3_RGBA_EXT:
+        /* The EXT version of the DOT3 extension does not support the
+         * scale factor, but the ARB version (and the version in OpenGL
+         * 1.3) does.
          */
-        for ( i = 0 ; i < numColorArgs ; i++ ) {
-           const GLuint op = texUnit->CombineOperandRGB[i] - GL_SRC_COLOR;
-           assert(op >= 0);
-           assert(op <= 3);
-           switch ( texUnit->CombineSourceRGB[i] ) {
-           case GL_TEXTURE:
-              color_arg[i] = r200_register_color[op][unit];
-              break;
-           case GL_CONSTANT:
-              color_arg[i] = r200_tfactor_color[op];
-              break;
-           case GL_PRIMARY_COLOR:
-              color_arg[i] = r200_primary_color[op];
-              break;
-           case GL_PREVIOUS:
-              if (unit == 0)
-                 color_arg[i] = r200_primary_color[op];
-              else
-                 color_arg[i] = r200_register_color[op][0];
-              break;
-           case GL_ZERO:
-              color_arg[i] = r200_zero_color[op];
-              break;
-           case GL_ONE:
-              color_arg[i] = r200_zero_color[op+1];
-              break;
-           default:
-              return GL_FALSE;
-           }
-        }
-
-        for ( i = 0 ; i < numAlphaArgs ; i++ ) {
-           const GLuint op = texUnit->CombineOperandA[i] - GL_SRC_ALPHA;
-           assert(op >= 0);
-           assert(op <= 1);
-           switch ( texUnit->CombineSourceA[i] ) {
-           case GL_TEXTURE:
-              alpha_arg[i] = r200_register_alpha[op][unit];
-              break;
-           case GL_CONSTANT:
-              alpha_arg[i] = r200_tfactor_alpha[op];
-              break;
-           case GL_PRIMARY_COLOR:
-              alpha_arg[i] = r200_primary_alpha[op];
-              break;
-           case GL_PREVIOUS:
-              if (unit == 0)
-                 alpha_arg[i] = r200_primary_alpha[op];
-              else
-                 alpha_arg[i] = r200_register_alpha[op][0];
-              break;
-           case GL_ZERO:
-              alpha_arg[i] = r200_zero_alpha[op];
-              break;
-           case GL_ONE:
-              alpha_arg[i] = r200_zero_alpha[op+1];
-              break;
-           default:
-              return GL_FALSE;
-           }
-        }
-
-        /* Step 2:
-         * Build up the color and alpha combine functions.
+        RGBshift = 0;
+        /* FALLTHROUGH */
+
+      case GL_DOT3_RGB:
+      case GL_DOT3_RGBA:
+        /* DOT3 works differently on R200 than on R100.  On R100, just
+         * setting the DOT3 mode did everything for you.  On R200, the
+         * driver has to enable the biasing and scale in the inputs to
+         * put them in the proper [-1,1] range.  This is what the 4x and
+         * the -0.5 in the DOT3 spec do.  The post-scale is then set
+         * normally.
          */
-        switch ( texUnit->CombineModeRGB ) {
-        case GL_REPLACE:
-           color_combine = (R200_TXC_ARG_A_ZERO |
-                            R200_TXC_ARG_B_ZERO |
-                            R200_TXC_OP_MADD);
-           R200_COLOR_ARG( 0, C );
-           break;
-        case GL_MODULATE:
-           color_combine = (R200_TXC_ARG_C_ZERO |
-                            R200_TXC_OP_MADD);
-           R200_COLOR_ARG( 0, A );
-           R200_COLOR_ARG( 1, B );
-           break;
-        case GL_ADD:
-           color_combine = (R200_TXC_ARG_B_ZERO |
-                            R200_TXC_COMP_ARG_B | 
-                            R200_TXC_OP_MADD);
-           R200_COLOR_ARG( 0, A );
-           R200_COLOR_ARG( 1, C );
-           break;
-        case GL_ADD_SIGNED:
-           color_combine = (R200_TXC_ARG_B_ZERO |
-                            R200_TXC_COMP_ARG_B |
-                            R200_TXC_BIAS_ARG_C |      /* new */
-                            R200_TXC_OP_MADD); /* was ADDSIGNED */
-           R200_COLOR_ARG( 0, A );
-           R200_COLOR_ARG( 1, C );
-           break;
-        case GL_SUBTRACT:
-           color_combine = (R200_TXC_ARG_B_ZERO |
-                            R200_TXC_COMP_ARG_B | 
-                            R200_TXC_NEG_ARG_C |
-                            R200_TXC_OP_MADD);
-           R200_COLOR_ARG( 0, A );
-           R200_COLOR_ARG( 1, C );
-           break;
-        case GL_INTERPOLATE:
-           color_combine = (R200_TXC_OP_LERP);
-           R200_COLOR_ARG( 0, B );
-           R200_COLOR_ARG( 1, A );
-           R200_COLOR_ARG( 2, C );
-           break;
-
-        case GL_DOT3_RGB_EXT:
-        case GL_DOT3_RGBA_EXT:
-           /* The EXT version of the DOT3 extension does not support the
-            * scale factor, but the ARB version (and the version in OpenGL
-            * 1.3) does.
-            */
-           RGBshift = 0;
-           Ashift = 0;
-           /* FALLTHROUGH */
-
-        case GL_DOT3_RGB:
-        case GL_DOT3_RGBA:
-           /* DOT3 works differently on R200 than on R100.  On R100, just
-            * setting the DOT3 mode did everything for you.  On R200, the
-            * driver has to enable the biasing and scale in the inputs to
-            * put them in the proper [-1,1] range.  This is what the 4x and
-            * the -0.5 in the DOT3 spec do.  The post-scale is then set
-            * normally.
-            */
-
-           RGBshift++;
-           Ashift = RGBshift;
-
-           color_combine = (R200_TXC_ARG_C_ZERO |
-                            R200_TXC_OP_DOT3 |
-                            R200_TXC_BIAS_ARG_A |
-                            R200_TXC_BIAS_ARG_B |
-                            R200_TXC_SCALE_ARG_A |
-                            R200_TXC_SCALE_ARG_B);
-           R200_COLOR_ARG( 0, A );
-           R200_COLOR_ARG( 1, B );
-           break;
-
-        case GL_MODULATE_ADD_ATI:
-           color_combine = (R200_TXC_OP_MADD);
-           R200_COLOR_ARG( 0, A );
-           R200_COLOR_ARG( 1, C );
-           R200_COLOR_ARG( 2, B );
-           break;
-        case GL_MODULATE_SIGNED_ADD_ATI:
-           color_combine = (R200_TXC_BIAS_ARG_C |      /* new */
-                            R200_TXC_OP_MADD); /* was ADDSIGNED */
-           R200_COLOR_ARG( 0, A );
-           R200_COLOR_ARG( 1, C );
-           R200_COLOR_ARG( 2, B );
-           break;
-        case GL_MODULATE_SUBTRACT_ATI:
-           color_combine = (R200_TXC_NEG_ARG_C |
-                            R200_TXC_OP_MADD);
-           R200_COLOR_ARG( 0, A );
-           R200_COLOR_ARG( 1, C );
-           R200_COLOR_ARG( 2, B );
-           break;
-        default:
-           return GL_FALSE;
-        }
-
-        switch ( texUnit->CombineModeA ) {
-        case GL_REPLACE:
-           alpha_combine = (R200_TXA_ARG_A_ZERO |
-                            R200_TXA_ARG_B_ZERO |
-                            R200_TXA_OP_MADD);
-           R200_ALPHA_ARG( 0, C );
-           break;
-        case GL_MODULATE:
-           alpha_combine = (R200_TXA_ARG_C_ZERO |
-                            R200_TXA_OP_MADD);
-           R200_ALPHA_ARG( 0, A );
-           R200_ALPHA_ARG( 1, B );
-           break;
-        case GL_ADD:
-           alpha_combine = (R200_TXA_ARG_B_ZERO |
-                            R200_TXA_COMP_ARG_B |
-                            R200_TXA_OP_MADD);
-           R200_ALPHA_ARG( 0, A );
-           R200_ALPHA_ARG( 1, C );
-           break;
-        case GL_ADD_SIGNED:
-           alpha_combine = (R200_TXA_ARG_B_ZERO |
-                            R200_TXA_COMP_ARG_B |
-                            R200_TXA_BIAS_ARG_C |      /* new */
-                            R200_TXA_OP_MADD); /* was ADDSIGNED */
-           R200_ALPHA_ARG( 0, A );
-           R200_ALPHA_ARG( 1, C );
-           break;
-        case GL_SUBTRACT:
-           alpha_combine = (R200_TXA_ARG_B_ZERO |
-                            R200_TXA_COMP_ARG_B |
-                            R200_TXA_NEG_ARG_C |
-                            R200_TXA_OP_MADD);
-           R200_ALPHA_ARG( 0, A );
-           R200_ALPHA_ARG( 1, C );
-           break;
-        case GL_INTERPOLATE:
-           alpha_combine = (R200_TXA_OP_LERP);
-           R200_ALPHA_ARG( 0, B );
-           R200_ALPHA_ARG( 1, A );
-           R200_ALPHA_ARG( 2, C );
-           break;
-
-        case GL_MODULATE_ADD_ATI:
-           alpha_combine = (R200_TXA_OP_MADD);
-           R200_ALPHA_ARG( 0, A );
-           R200_ALPHA_ARG( 1, C );
-           R200_ALPHA_ARG( 2, B );
-           break;
-        case GL_MODULATE_SIGNED_ADD_ATI:
-           alpha_combine = (R200_TXA_BIAS_ARG_C |      /* new */
-                            R200_TXA_OP_MADD); /* was ADDSIGNED */
-           R200_ALPHA_ARG( 0, A );
-           R200_ALPHA_ARG( 1, C );
-           R200_ALPHA_ARG( 2, B );
-           break;
-        case GL_MODULATE_SUBTRACT_ATI:
-           alpha_combine = (R200_TXA_NEG_ARG_C |
-                            R200_TXA_OP_MADD);
-           R200_ALPHA_ARG( 0, A );
-           R200_ALPHA_ARG( 1, C );
-           R200_ALPHA_ARG( 2, B );
-           break;
-        default:
-           return GL_FALSE;
-        }
 
-        if ( (texUnit->CombineModeRGB == GL_DOT3_RGB_EXT)
-             || (texUnit->CombineModeRGB == GL_DOT3_RGB) ) {
-           alpha_scale |= R200_TXA_DOT_ALPHA;
-        }
+        color_combine = (R200_TXC_ARG_C_ZERO |
+                         R200_TXC_OP_DOT3 |
+                         R200_TXC_BIAS_ARG_A |
+                         R200_TXC_BIAS_ARG_B |
+                         R200_TXC_SCALE_ARG_A |
+                         R200_TXC_SCALE_ARG_B);
+        R200_COLOR_ARG( 0, A );
+        R200_COLOR_ARG( 1, B );
+        break;
 
-        /* Step 3:
-         * Apply the scale factor.
-         */
-        color_scale &= ~R200_TXC_SCALE_MASK;
-        alpha_scale &= ~R200_TXA_SCALE_MASK;
-        color_scale |= (RGBshift << R200_TXC_SCALE_SHIFT);
-        alpha_scale |= (Ashift   << R200_TXA_SCALE_SHIFT);
+      case GL_MODULATE_ADD_ATI:
+        color_combine = (R200_TXC_OP_MADD);
+        R200_COLOR_ARG( 0, A );
+        R200_COLOR_ARG( 1, C );
+        R200_COLOR_ARG( 2, B );
+        break;
+      case GL_MODULATE_SIGNED_ADD_ATI:
+        color_combine = (R200_TXC_BIAS_ARG_C | /* new */
+                         R200_TXC_OP_MADD); /* was ADDSIGNED */
+        R200_COLOR_ARG( 0, A );
+        R200_COLOR_ARG( 1, C );
+        R200_COLOR_ARG( 2, B );
+        break;
+      case GL_MODULATE_SUBTRACT_ATI:
+        color_combine = (R200_TXC_NEG_ARG_C |
+                         R200_TXC_OP_MADD);
+        R200_COLOR_ARG( 0, A );
+        R200_COLOR_ARG( 1, C );
+        R200_COLOR_ARG( 2, B );
+        break;
+      default:
+        return GL_FALSE;
+      }
 
-        /* All done!
-         */
+      switch ( texUnit->_CurrentCombine->ModeA ) {
+      case GL_REPLACE:
+        alpha_combine = (R200_TXA_ARG_A_ZERO |
+                         R200_TXA_ARG_B_ZERO |
+                         R200_TXA_OP_MADD);
+        R200_ALPHA_ARG( 0, C );
+        break;
+      case GL_MODULATE:
+        alpha_combine = (R200_TXA_ARG_C_ZERO |
+                         R200_TXA_OP_MADD);
+        R200_ALPHA_ARG( 0, A );
+        R200_ALPHA_ARG( 1, B );
+        break;
+      case GL_ADD:
+        alpha_combine = (R200_TXA_ARG_B_ZERO |
+                         R200_TXA_COMP_ARG_B |
+                         R200_TXA_OP_MADD);
+        R200_ALPHA_ARG( 0, A );
+        R200_ALPHA_ARG( 1, C );
+        break;
+      case GL_ADD_SIGNED:
+        alpha_combine = (R200_TXA_ARG_B_ZERO |
+                         R200_TXA_COMP_ARG_B |
+                         R200_TXA_BIAS_ARG_C | /* new */
+                         R200_TXA_OP_MADD); /* was ADDSIGNED */
+        R200_ALPHA_ARG( 0, A );
+        R200_ALPHA_ARG( 1, C );
+        break;
+      case GL_SUBTRACT:
+        alpha_combine = (R200_TXA_ARG_B_ZERO |
+                         R200_TXA_COMP_ARG_B |
+                         R200_TXA_NEG_ARG_C |
+                         R200_TXA_OP_MADD);
+        R200_ALPHA_ARG( 0, A );
+        R200_ALPHA_ARG( 1, C );
+        break;
+      case GL_INTERPOLATE:
+        alpha_combine = (R200_TXA_OP_LERP);
+        R200_ALPHA_ARG( 0, B );
+        R200_ALPHA_ARG( 1, A );
+        R200_ALPHA_ARG( 2, C );
         break;
 
+      case GL_MODULATE_ADD_ATI:
+        alpha_combine = (R200_TXA_OP_MADD);
+        R200_ALPHA_ARG( 0, A );
+        R200_ALPHA_ARG( 1, C );
+        R200_ALPHA_ARG( 2, B );
+        break;
+      case GL_MODULATE_SIGNED_ADD_ATI:
+        alpha_combine = (R200_TXA_BIAS_ARG_C | /* new */
+                         R200_TXA_OP_MADD); /* was ADDSIGNED */
+        R200_ALPHA_ARG( 0, A );
+        R200_ALPHA_ARG( 1, C );
+        R200_ALPHA_ARG( 2, B );
+        break;
+      case GL_MODULATE_SUBTRACT_ATI:
+        alpha_combine = (R200_TXA_NEG_ARG_C |
+                         R200_TXA_OP_MADD);
+        R200_ALPHA_ARG( 0, A );
+        R200_ALPHA_ARG( 1, C );
+        R200_ALPHA_ARG( 2, B );
+        break;
       default:
         return GL_FALSE;
       }
+
+      if ( (texUnit->_CurrentCombine->ModeRGB == GL_DOT3_RGBA_EXT)
+          || (texUnit->_CurrentCombine->ModeRGB == GL_DOT3_RGBA) ) {
+        alpha_scale |= R200_TXA_DOT_ALPHA;
+        Ashift = RGBshift;
+      }
+
+      /* Step 3:
+       * Apply the scale factor.
+       */
+      color_scale |= (RGBshift << R200_TXC_SCALE_SHIFT);
+      alpha_scale |= (Ashift   << R200_TXA_SCALE_SHIFT);
+
+      /* All done!
+       */
    }
 
    if ( rmesa->hw.pix[unit].cmd[PIX_PP_TXCBLEND] != color_combine ||
@@ -1205,6 +803,7 @@ static GLboolean r200UpdateTextureEnv( GLcontext *ctx, int unit )
 
 #define TEXOBJ_TXFORMAT_X_MASK (R200_DEPTH_LOG2_MASK |         \
                                 R200_TEXCOORD_MASK |           \
+                                R200_CLAMP_Q_MASK |            \
                                 R200_VOLUME_FILTER_MASK)
 
 
@@ -1229,7 +828,7 @@ static void import_tex_obj_state( r200ContextPtr rmesa,
    if (texobj->base.tObj->Target == GL_TEXTURE_CUBE_MAP) {
       GLuint *cube_cmd = R200_DB_STATE( cube[unit] );
       GLuint bytesPerFace = texobj->base.totalSize / 6;
-      ASSERT(texobj->totalSize % 6 == 0);
+      ASSERT(texobj->base.totalSize % 6 == 0);
       cube_cmd[CUBE_PP_CUBIC_FACES] = texobj->pp_cubic_faces;
       cube_cmd[CUBE_PP_CUBIC_OFFSET_F1] = texobj->pp_txoffset + 1 * bytesPerFace;
       cube_cmd[CUBE_PP_CUBIC_OFFSET_F2] = texobj->pp_txoffset + 2 * bytesPerFace;
@@ -1243,71 +842,42 @@ static void import_tex_obj_state( r200ContextPtr rmesa,
 }
 
 
-
-
 static void set_texgen_matrix( r200ContextPtr rmesa, 
                               GLuint unit,
                               const GLfloat *s_plane,
                               const GLfloat *t_plane,
-                              const GLfloat *r_plane )
+                              const GLfloat *r_plane,
+                              const GLfloat *q_plane )
 {
-   static const GLfloat scale_identity[4] = { 1,1,1,1 };
-
-   if (!TEST_EQ_4V( s_plane, scale_identity) ||
-       !TEST_EQ_4V( t_plane, scale_identity) ||
-       !TEST_EQ_4V( r_plane, scale_identity)) {
-      rmesa->TexGenEnabled |= R200_TEXMAT_0_ENABLE<<unit;
-      rmesa->TexGenMatrix[unit].m[0]  = s_plane[0];
-      rmesa->TexGenMatrix[unit].m[4]  = s_plane[1];
-      rmesa->TexGenMatrix[unit].m[8]  = s_plane[2];
-      rmesa->TexGenMatrix[unit].m[12] = s_plane[3];
-
-      rmesa->TexGenMatrix[unit].m[1]  = t_plane[0];
-      rmesa->TexGenMatrix[unit].m[5]  = t_plane[1];
-      rmesa->TexGenMatrix[unit].m[9]  = t_plane[2];
-      rmesa->TexGenMatrix[unit].m[13] = t_plane[3];
-
-      /* NOTE: r_plane goes in the 4th row, not 3rd! */
-      rmesa->TexGenMatrix[unit].m[3]  = r_plane[0];
-      rmesa->TexGenMatrix[unit].m[7]  = r_plane[1];
-      rmesa->TexGenMatrix[unit].m[11] = r_plane[2];
-      rmesa->TexGenMatrix[unit].m[15] = r_plane[3];
+   GLfloat m[16];
 
-      rmesa->NewGLState |= _NEW_TEXTURE_MATRIX;
-   }
-}
+   m[0]  = s_plane[0];
+   m[4]  = s_plane[1];
+   m[8]  = s_plane[2];
+   m[12] = s_plane[3];
 
-/* Need this special matrix to get correct reflection map coords */
-static void
-set_texgen_reflection_matrix( r200ContextPtr rmesa, GLuint unit )
-{
-   static const GLfloat m[16] = {
-      -1,  0,  0,  0,
-       0, -1,  0,  0,
-       0,  0,  0, -1,
-       0,  0, -1,  0 };
-   _math_matrix_loadf( &(rmesa->TexGenMatrix[unit]), m);
-   _math_matrix_analyse( &(rmesa->TexGenMatrix[unit]) );
-   rmesa->TexGenEnabled |= R200_TEXMAT_0_ENABLE<<unit;
-}
+   m[1]  = t_plane[0];
+   m[5]  = t_plane[1];
+   m[9]  = t_plane[2];
+   m[13] = t_plane[3];
+
+   m[2]  = r_plane[0];
+   m[6]  = r_plane[1];
+   m[10] = r_plane[2];
+   m[14] = r_plane[3];
+
+   m[3]  = q_plane[0];
+   m[7]  = q_plane[1];
+   m[11] = q_plane[2];
+   m[15] = q_plane[3];
 
-/* Need this special matrix to get correct normal map coords */
-static void
-set_texgen_normal_map_matrix( r200ContextPtr rmesa, GLuint unit )
-{
-   static const GLfloat m[16] = {
-      1, 0, 0, 0,
-      0, 1, 0, 0,
-      0, 0, 0, 1,
-      0, 0, 1, 0 };
    _math_matrix_loadf( &(rmesa->TexGenMatrix[unit]), m);
    _math_matrix_analyse( &(rmesa->TexGenMatrix[unit]) );
    rmesa->TexGenEnabled |= R200_TEXMAT_0_ENABLE<<unit;
 }
 
 
-/* Ignoring the Q texcoord for now.
- *
+/*
  * Returns GL_FALSE if fallback required.  
  */
 static GLboolean r200_validate_texgen( GLcontext *ctx, GLuint unit )
@@ -1315,98 +885,130 @@ static GLboolean r200_validate_texgen( GLcontext *ctx, GLuint unit )
    r200ContextPtr rmesa = R200_CONTEXT(ctx);
    const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
    GLuint inputshift = R200_TEXGEN_0_INPUT_SHIFT + unit*4;
-   GLuint tmp = rmesa->TexGenEnabled;
+   GLuint tgi, tgcm;
+   GLuint mode = 0;
+   GLboolean mixed_fallback = GL_FALSE;
+   static const GLfloat I[16] = {
+      1,  0,  0,  0,
+      0,  1,  0,  0,
+      0,  0,  1,  0,
+      0,  0,  0,  1 };
+   static const GLfloat reflect[16] = {
+      -1,  0,  0,  0,
+       0, -1,  0,  0,
+       0,  0,  -1, 0,
+       0,  0,  0,  1 };
 
    rmesa->TexGenCompSel &= ~(R200_OUTPUT_TEX_0 << unit);
    rmesa->TexGenEnabled &= ~(R200_TEXGEN_TEXMAT_0_ENABLE<<unit);
    rmesa->TexGenEnabled &= ~(R200_TEXMAT_0_ENABLE<<unit);
-   rmesa->TexGenInputs &= ~(R200_TEXGEN_INPUT_MASK<<inputshift);
-   rmesa->TexGenNeedNormals[unit] = 0;
+   rmesa->TexGenNeedNormals[unit] = GL_FALSE;
+   tgi = rmesa->hw.tcg.cmd[TCG_TEX_PROC_CTL_1] & ~(R200_TEXGEN_INPUT_MASK <<
+                                                  inputshift);
+   tgcm = rmesa->hw.tcg.cmd[TCG_TEX_PROC_CTL_2] & ~(R200_TEXGEN_COMP_MASK <<
+                                                   (unit * 4));
 
    if (0) 
       fprintf(stderr, "%s unit %d\n", __FUNCTION__, unit);
 
-   if ((texUnit->TexGenEnabled & (S_BIT|T_BIT|R_BIT)) == 0) {
-      /* Disabled, no fallback:
-       */
-      rmesa->TexGenInputs |= 
-        (R200_TEXGEN_INPUT_TEXCOORD_0+unit) << inputshift;
-      return GL_TRUE;
+   if (texUnit->TexGenEnabled & S_BIT) {
+      mode = texUnit->GenModeS;
+   } else {
+      tgcm |= R200_TEXGEN_COMP_S << (unit * 4);
    }
-   else if (texUnit->TexGenEnabled & Q_BIT) {
-      /* Very easy to do this, in fact would remove a fallback case
-       * elsewhere, but I haven't done it yet...  Fallback: 
-       */
-      /*fprintf(stderr, "fallback Q_BIT\n");*/
-      return GL_FALSE;
+
+   if (texUnit->TexGenEnabled & T_BIT) {
+      if (texUnit->GenModeT != mode)
+        mixed_fallback = GL_TRUE;
+   } else {
+      tgcm |= R200_TEXGEN_COMP_T << (unit * 4);
    }
-   else if (texUnit->TexGenEnabled == (S_BIT|T_BIT) &&
-           texUnit->GenModeS == texUnit->GenModeT) {
-      /* OK */
-      rmesa->TexGenEnabled |= R200_TEXGEN_TEXMAT_0_ENABLE << unit;
-      /* continue */
+
+   if (texUnit->TexGenEnabled & R_BIT) {
+      if (texUnit->GenModeR != mode)
+        mixed_fallback = GL_TRUE;
+   } else {
+      tgcm |= R200_TEXGEN_COMP_R << (unit * 4);
    }
-   else if (texUnit->TexGenEnabled == (S_BIT|T_BIT|R_BIT) &&
-           texUnit->GenModeS == texUnit->GenModeT &&
-            texUnit->GenModeT == texUnit->GenModeR) {
-      /* OK */
-      rmesa->TexGenEnabled |= R200_TEXGEN_TEXMAT_0_ENABLE << unit;
-      /* continue */
+
+   if (texUnit->TexGenEnabled & Q_BIT) {
+      if (texUnit->GenModeQ != mode)
+        mixed_fallback = GL_TRUE;
+   } else {
+      tgcm |= R200_TEXGEN_COMP_Q << (unit * 4);
    }
-   else {
-      /* Mixed modes, fallback:
-       */
-      /* fprintf(stderr, "fallback mixed texgen\n"); */
+
+   if (mixed_fallback) {
+      if (R200_DEBUG & DEBUG_FALLBACKS)
+        fprintf(stderr, "fallback mixed texgen, 0x%x (0x%x 0x%x 0x%x 0x%x)\n",
+                texUnit->TexGenEnabled, texUnit->GenModeS, texUnit->GenModeT,
+                texUnit->GenModeR, texUnit->GenModeQ);
       return GL_FALSE;
    }
 
-   rmesa->TexGenEnabled |= R200_TEXGEN_TEXMAT_0_ENABLE << unit;
-
-   switch (texUnit->GenModeS) {
+   switch (mode) {
    case GL_OBJECT_LINEAR:
-      rmesa->TexGenInputs |= R200_TEXGEN_INPUT_OBJ << inputshift;
+      tgi |= R200_TEXGEN_INPUT_OBJ << inputshift;
       set_texgen_matrix( rmesa, unit, 
-                        texUnit->ObjectPlaneS,
-                        texUnit->ObjectPlaneT,
-                         texUnit->ObjectPlaneR);
+        (texUnit->TexGenEnabled & S_BIT) ? texUnit->ObjectPlaneS : I,
+        (texUnit->TexGenEnabled & T_BIT) ? texUnit->ObjectPlaneT : I + 4,
+        (texUnit->TexGenEnabled & R_BIT) ? texUnit->ObjectPlaneR : I + 8,
+        (texUnit->TexGenEnabled & Q_BIT) ? texUnit->ObjectPlaneQ : I + 12);
       break;
 
    case GL_EYE_LINEAR:
-      rmesa->TexGenInputs |= R200_TEXGEN_INPUT_EYE << inputshift;
+      tgi |= R200_TEXGEN_INPUT_EYE << inputshift;
       set_texgen_matrix( rmesa, unit, 
-                        texUnit->EyePlaneS,
-                        texUnit->EyePlaneT,
-                        texUnit->EyePlaneR);
+        (texUnit->TexGenEnabled & S_BIT) ? texUnit->EyePlaneS : I,
+        (texUnit->TexGenEnabled & T_BIT) ? texUnit->EyePlaneT : I + 4,
+        (texUnit->TexGenEnabled & R_BIT) ? texUnit->EyePlaneR : I + 8,
+        (texUnit->TexGenEnabled & Q_BIT) ? texUnit->EyePlaneQ : I + 12);
       break;
 
    case GL_REFLECTION_MAP_NV:
       rmesa->TexGenNeedNormals[unit] = GL_TRUE;
-      rmesa->TexGenInputs |= R200_TEXGEN_INPUT_EYE_REFLECT<<inputshift;
-      set_texgen_reflection_matrix(rmesa, unit);
+      tgi |= R200_TEXGEN_INPUT_EYE_REFLECT<<inputshift;
+      set_texgen_matrix( rmesa, unit, 
+        (texUnit->TexGenEnabled & S_BIT) ? reflect : I,
+        (texUnit->TexGenEnabled & T_BIT) ? reflect + 4 : I + 4,
+        (texUnit->TexGenEnabled & R_BIT) ? reflect + 8 : I + 8,
+        I + 12);
       break;
 
    case GL_NORMAL_MAP_NV:
       rmesa->TexGenNeedNormals[unit] = GL_TRUE;
-      rmesa->TexGenInputs |= R200_TEXGEN_INPUT_EYE_NORMAL<<inputshift;
-      set_texgen_normal_map_matrix(rmesa, unit);
+      tgi |= R200_TEXGEN_INPUT_EYE_NORMAL<<inputshift;
       break;
 
    case GL_SPHERE_MAP:
       rmesa->TexGenNeedNormals[unit] = GL_TRUE;
-      rmesa->TexGenInputs |= R200_TEXGEN_INPUT_SPHERE<<inputshift;
+      tgi |= R200_TEXGEN_INPUT_SPHERE<<inputshift;
+      /* GL_SPHERE_MAP doesn't appear to work. */
+      return GL_FALSE;
+
+   case 0:
+      /* All texgen units were disabled, so just pass coords through. */
+      tgi |= unit << inputshift;
       break;
 
    default:
       /* Unsupported mode, fallback:
        */
-      /*  fprintf(stderr, "fallback unsupported texgen\n"); */
+      if (R200_DEBUG & DEBUG_FALLBACKS)
+        fprintf(stderr, "fallback unsupported texgen, %d\n",
+                texUnit->GenModeS);
       return GL_FALSE;
    }
 
+   rmesa->TexGenEnabled |= R200_TEXGEN_TEXMAT_0_ENABLE << unit;
    rmesa->TexGenCompSel |= R200_OUTPUT_TEX_0 << unit;
 
-   if (tmp != rmesa->TexGenEnabled) {
-      rmesa->NewGLState |= _NEW_TEXTURE_MATRIX;
+   if (tgi != rmesa->hw.tcg.cmd[TCG_TEX_PROC_CTL_1] || 
+       tgcm != rmesa->hw.tcg.cmd[TCG_TEX_PROC_CTL_2])
+   {
+      R200_STATECHANGE(rmesa, tcg);
+      rmesa->hw.tcg.cmd[TCG_TEX_PROC_CTL_1] = tgi;
+      rmesa->hw.tcg.cmd[TCG_TEX_PROC_CTL_2] = tgcm;
    }
 
    return GL_TRUE;
@@ -1433,7 +1035,7 @@ static void disable_tex( GLcontext *ctx, int unit )
                                           R200_TEX_BLEND_0_ENABLE) << unit);
       rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= R200_TEX_BLEND_0_ENABLE; 
         
-      R200_STATECHANGE( rmesa, tcl );
+      R200_STATECHANGE( rmesa, vtx );
       rmesa->hw.vtx.cmd[VTX_TCL_OUTPUT_VTXFMT_1] &= ~(7 << (unit * 3));
         
       if (rmesa->TclFallback & (R200_TCL_FALLBACK_TEXGEN_0<<unit)) {
@@ -1449,15 +1051,12 @@ static void disable_tex( GLcontext *ctx, int unit )
 
 
       {
-        GLuint inputshift = R200_TEXGEN_0_INPUT_SHIFT + unit*4;
         GLuint tmp = rmesa->TexGenEnabled;
 
         rmesa->TexGenEnabled &= ~(R200_TEXGEN_TEXMAT_0_ENABLE<<unit);
         rmesa->TexGenEnabled &= ~(R200_TEXMAT_0_ENABLE<<unit);
-        rmesa->TexGenEnabled &= ~(R200_TEXGEN_INPUT_MASK<<inputshift);
-        rmesa->TexGenNeedNormals[unit] = 0;
+        rmesa->TexGenNeedNormals[unit] = GL_FALSE;
         rmesa->TexGenCompSel &= ~(R200_OUTPUT_TEX_0 << unit);
-        rmesa->TexGenInputs &= ~(R200_TEXGEN_INPUT_MASK<<inputshift);
 
         if (tmp != rmesa->TexGenEnabled) {
            rmesa->recheck_texgen[unit] = GL_TRUE;
@@ -1467,6 +1066,22 @@ static void disable_tex( GLcontext *ctx, int unit )
    }
 }
 
+static void set_re_cntl_d3d( GLcontext *ctx, int unit, GLboolean use_d3d )
+{
+   r200ContextPtr rmesa = R200_CONTEXT(ctx);
+
+   GLuint re_cntl;
+
+   re_cntl = rmesa->hw.set.cmd[SET_RE_CNTL] & ~(R200_VTX_STQ0_D3D << (2 * unit));
+   if (use_d3d)
+      re_cntl |= R200_VTX_STQ0_D3D << (2 * unit);
+
+   if ( re_cntl != rmesa->hw.set.cmd[SET_RE_CNTL] ) {
+      R200_STATECHANGE( rmesa, set );
+      rmesa->hw.set.cmd[SET_RE_CNTL] = re_cntl;
+   }
+}
+
 static GLboolean enable_tex_2d( GLcontext *ctx, int unit )
 {
    r200ContextPtr rmesa = R200_CONTEXT(ctx);
@@ -1491,6 +1106,8 @@ static GLboolean enable_tex_2d( GLcontext *ctx, int unit )
         return GL_FALSE;
    }
 
+   set_re_cntl_d3d( ctx, unit, GL_FALSE );
+
    return GL_TRUE;
 }
 
@@ -1525,6 +1142,8 @@ static GLboolean enable_tex_3d( GLcontext *ctx, int unit )
         return GL_FALSE;
    }
 
+   set_re_cntl_d3d( ctx, unit, GL_TRUE );
+
    return GL_TRUE;
 }
 #endif
@@ -1568,6 +1187,8 @@ static GLboolean enable_tex_cube( GLcontext *ctx, int unit )
       return GL_FALSE;
    }
 
+   set_re_cntl_d3d( ctx, unit, GL_TRUE );
+
    return GL_TRUE;
 }
 
@@ -1593,6 +1214,8 @@ static GLboolean enable_tex_rect( GLcontext *ctx, int unit )
         return GL_FALSE;
    }
 
+   set_re_cntl_d3d( ctx, unit, GL_FALSE );
+
    return GL_TRUE;
 }
 
@@ -1637,6 +1260,7 @@ static GLboolean update_tex_common( GLcontext *ctx, int unit )
                                         R200_TEX_BLEND_0_ENABLE) << unit;
 
       R200_STATECHANGE( rmesa, vtx );
+      rmesa->hw.vtx.cmd[VTX_TCL_OUTPUT_VTXFMT_1] &= ~(7 << (unit * 3));
       rmesa->hw.vtx.cmd[VTX_TCL_OUTPUT_VTXFMT_1] |= 4 << (unit * 3);
 
       rmesa->recheck_texgen[unit] = GL_TRUE;
@@ -1708,73 +1332,105 @@ void r200UpdateTextureState( GLcontext *ctx )
    GLuint dbg;
 
    ok = (r200UpdateTextureUnit( ctx, 0 ) &&
-        r200UpdateTextureUnit( ctx, 1 ));
+        r200UpdateTextureUnit( ctx, 1 ) &&
+        r200UpdateTextureUnit( ctx, 2 ) &&
+        r200UpdateTextureUnit( ctx, 3 ) &&
+        r200UpdateTextureUnit( ctx, 4 ) &&
+        r200UpdateTextureUnit( ctx, 5 ));
 
    FALLBACK( rmesa, R200_FALLBACK_TEXTURE, !ok );
 
    if (rmesa->TclFallback)
       r200ChooseVertexState( ctx );
 
-   /*
-    * T0 hang workaround -------------
-    */
-#if 1
-   if ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_ENABLE_MASK) == R200_TEX_0_ENABLE &&
-       (rmesa->hw.tex[0].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK) > R200_MIN_FILTER_LINEAR) {
-
-      R200_STATECHANGE(rmesa, ctx);
-      R200_STATECHANGE(rmesa, tex[1]);
-      rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= R200_TEX_1_ENABLE;
-      rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] &= ~TEXOBJ_TXFORMAT_MASK;
-      rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] |= 0x08000000;
-   }
-   else {
-      if ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_1_ENABLE) &&
-         (rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] & 0x08000000)) {
-        R200_STATECHANGE(rmesa, tex[1]);
-        rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] &= ~0x08000000;
-      }
-   }
-#endif
 
-#if 1
-   /*
-    * Texture cache LRU hang workaround -------------
-    */
-   dbg = 0x0;
-   if (((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_0_ENABLE) &&
-       ((((rmesa->hw.tex[0].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & 
-         0x04) == 0)))
-   {
-      dbg |= 0x02;
-   }
+   if (rmesa->r200Screen->chipset & R200_CHIPSET_REAL_R200) {
 
-   if (((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_1_ENABLE) &&
-       ((((rmesa->hw.tex[1].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & 
-         0x04) == 0)))
-   {
-      dbg |= 0x04;
-   }
+      /*
+       * T0 hang workaround -------------
+       * not needed for r200 derivatives?
+       */
+      if ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_ENABLE_MASK) == R200_TEX_0_ENABLE &&
+         (rmesa->hw.tex[0].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK) > R200_MIN_FILTER_LINEAR) {
+
+         R200_STATECHANGE(rmesa, ctx);
+         R200_STATECHANGE(rmesa, tex[1]);
+         rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= R200_TEX_1_ENABLE;
+         rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] &= ~TEXOBJ_TXFORMAT_MASK;
+         rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] |= 0x08000000;
+      }
+      else {
+         if ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_1_ENABLE) &&
+            (rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] & 0x08000000)) {
+               R200_STATECHANGE(rmesa, tex[1]);
+               rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] &= ~0x08000000;
+         }
+      }
 
-   if (dbg != rmesa->hw.tam.cmd[TAM_DEBUG3]) {
-      R200_STATECHANGE( rmesa, tam );
-      rmesa->hw.tam.cmd[TAM_DEBUG3] = dbg;
-      if (0) printf("TEXCACHE LRU HANG WORKAROUND %x\n", dbg);
-   }
-#endif
-}
+      /* maybe needs to be done pairwise due to 2 parallel (physical) tex units ?
+         looks like that's not the case, if 8500/9100 owners don't complain remove this...
+      for ( i = 0; i < ctx->Const.MaxTextureUnits; i += 2) {
+         if (((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & ((R200_TEX_0_ENABLE |
+            R200_TEX_1_ENABLE ) << i)) == (R200_TEX_0_ENABLE << i)) &&
+            ((rmesa->hw.tex[i].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK) >
+            R200_MIN_FILTER_LINEAR)) {
+            R200_STATECHANGE(rmesa, ctx);
+            R200_STATECHANGE(rmesa, tex[i+1]);
+            rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= (R200_TEX_1_ENABLE << i);
+            rmesa->hw.tex[i+1].cmd[TEX_PP_TXFORMAT] &= ~TEXOBJ_TXFORMAT_MASK;
+            rmesa->hw.tex[i+1].cmd[TEX_PP_TXFORMAT] |= 0x08000000;
+         }
+         else {
+            if ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (R200_TEX_1_ENABLE << i)) &&
+               (rmesa->hw.tex[i+1].cmd[TEX_PP_TXFORMAT] & 0x08000000)) {
+               R200_STATECHANGE(rmesa, tex[i+1]);
+               rmesa->hw.tex[i+1].cmd[TEX_PP_TXFORMAT] &= ~0x08000000;
+            }
+         }
+      } */
 
-/*
-  also tests for higher texunits:
+      /*
+       * Texture cache LRU hang workaround -------------
+       * not needed for r200 derivatives?
+       */
 
-       ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_2_ENABLE) &&
-       ((((rmesa->hw.tex[2].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & 0x04) == 0)) ||
-       ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_4_ENABLE) &&
-       ((((rmesa->hw.tex[4].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & 0x04) == 0)))
+      /* While the cases below attempt to only enable the workaround in the
+       * specific cases necessary, they were insufficient.  See bugzilla #1519,
+       * #729, #814.  Tests with quake3 showed no impact on performance.
+       */
+      dbg = 0x6;
+
+      /*
+      if (((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (R200_TEX_0_ENABLE )) &&
+         ((((rmesa->hw.tex[0].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) &
+         0x04) == 0)) ||
+         ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_2_ENABLE) &&
+         ((((rmesa->hw.tex[2].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) &
+         0x04) == 0)) ||
+         ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_4_ENABLE) &&
+         ((((rmesa->hw.tex[4].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) &
+         0x04) == 0)))
+      {
+         dbg |= 0x02;
+      }
 
-       ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_3_ENABLE) &&
-       ((((rmesa->hw.tex[3].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & 0x04) == 0)) ||
-       ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_5_ENABLE) &&
-       ((((rmesa->hw.tex[5].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & 0x04) == 0)))
+      if (((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (R200_TEX_1_ENABLE )) &&
+         ((((rmesa->hw.tex[1].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) &
+         0x04) == 0)) ||
+         ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_3_ENABLE) &&
+         ((((rmesa->hw.tex[3].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) &
+         0x04) == 0)) ||
+         ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_5_ENABLE) &&
+         ((((rmesa->hw.tex[5].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) &
+         0x04) == 0)))
+      {
+         dbg |= 0x04;
+      }*/
 
-*/
+      if (dbg != rmesa->hw.tam.cmd[TAM_DEBUG3]) {
+         R200_STATECHANGE( rmesa, tam );
+         rmesa->hw.tam.cmd[TAM_DEBUG3] = dbg;
+         if (0) printf("TEXCACHE LRU HANG WORKAROUND %x\n", dbg);
+      }
+   }
+}