Implement GL_ARB_texture_env_combine, GL_EXT_texture_env_combine, and
authorIan Romanick <idr@us.ibm.com>
Mon, 29 Aug 2005 15:43:02 +0000 (15:43 +0000)
committerIan Romanick <idr@us.ibm.com>
Mon, 29 Aug 2005 15:43:02 +0000 (15:43 +0000)
GL_ARB_texture_env_crossbar for i810.  This passes both demos/texenv and all
of glean's texCombine tests.

src/mesa/drivers/dri/i810/i810_3d_reg.h
src/mesa/drivers/dri/i810/i810context.c
src/mesa/drivers/dri/i810/i810state.c
src/mesa/drivers/dri/i810/i810texstate.c

index dade1a826c7d65e3a9b78b13fca8d873274fc68d..7cc59d5c86ae2b4ea688672bef0fc5a2ebecb9ec 100644 (file)
 
 /* GFXRENDERSTATE_MAP_ALPHA_BLEND_STAGES, p132
  */
-#define GFX_OP_MAP_ALPHA_STAGES  ((0x3<<29)|(0x1<<24))
-#define MA_STAGE_SHIFT           20
-#define MA_STAGE_0               (0<<20)
-#define MA_STAGE_1               (1<<20)
-#define MA_STAGE_2               (2<<20)
-#define MA_UPDATE_ARG1           (1<<18)
-#define MA_ARG1_MASK             ((0x7<<15)|(0x1<<13))
-#define MA_ARG1_ALPHA_FACTOR     (0x1<<15)
-#define MA_ARG1_ITERATED_ALPHA   (0x3<<15)
-#define MA_ARG1_CURRENT_ALPHA    (0x5<<15)
-#define MA_ARG1_TEX0_ALPHA       (0x6<<15)
-#define MA_ARG1_TEX1_ALPHA       (0x7<<15)
-#define MA_ARG1_INVERT           (0x1<<13)
-#define MA_ARG1_DONT_INVERT      (0x0<<13)
-#define MA_UPDATE_ARG2           (1<<12)
-#define MA_ARG2_MASK             ((0x7<<8)|(0x1<<6))
-#define MA_ARG2_ALPHA_FACTOR     (0x1<<8)
-#define MA_ARG2_ITERATED_ALPHA   (0x3<<8)
-#define MA_ARG2_CURRENT_ALPHA    (0x5<<8)
-#define MA_ARG2_TEX0_ALPHA       (0x6<<8)
-#define MA_ARG2_TEX1_ALPHA       (0x7<<8)
-#define MA_ARG2_INVERT           (0x1<<6)
-#define MA_ARG2_DONT_INVERT      (0x0<<6)
-#define MA_UPDATE_OP             (1<<5)
+#define GFX_OP_MAP_ALPHA_STAGES      ((0x3<<29)|(0x1<<24))
+#define MA_STAGE_SHIFT               20
+#define MA_STAGE_0                   (0<<20)
+#define MA_STAGE_1                   (1<<20)
+#define MA_STAGE_2                   (2<<20)
+
+#define MA_ARG_ONE                   (0x0<<2)
+#define MA_ARG_ALPHA_FACTOR          (0x1<<2)
+#define MA_ARG_ITERATED_ALPHA        (0x3<<2)
+#define MA_ARG_CURRENT_ALPHA         (0x5<<2)
+#define MA_ARG_TEX0_ALPHA            (0x6<<2)
+#define MA_ARG_TEX1_ALPHA            (0x7<<2)
+#define MA_ARG_INVERT                (0x1)
+#define MA_ARG_DONT_INVERT           (0x0)
+
+#define MA_UPDATE_ARG1               (1<<18)
+#define MA_ARG1_SHIFT                13
+#define MA_ARG1_MASK                 (0x1d << MA_ARG1_SHIFT)
+
+#define MA_UPDATE_ARG2               (1<<12)
+#define MA_ARG2_SHIFT                6
+#define MA_ARG2_MASK                 (0x1d << MA_ARG2_SHIFT)
+
+#define MA_UPDATE_OP                 (1<<5)
 #define MA_OP_MASK                   (0xf)
 #define MA_OP_ARG1                   (0x1)
 #define MA_OP_ARG2                   (0x2)
 #define MA_OP_LIN_BLEND_ALPHA_FACTOR (0xa)
 #define MA_OP_LIN_BLEND_TEX0_ALPHA   (0x10)
 #define MA_OP_LIN_BLEND_TEX1_ALPHA   (0x11)
+#define MA_OP_SUBTRACT               (0x14)
 
 
 /* GFXRENDERSTATE_MAP_COLOR_BLEND_STAGES, p129
  */
-#define GFX_OP_MAP_COLOR_STAGES  ((0x3<<29)|(0x0<<24))
-#define MC_STAGE_SHIFT           20
-#define MC_STAGE_0               (0<<20)
-#define MC_STAGE_1               (1<<20)
-#define MC_STAGE_2               (2<<20)
-#define MC_UPDATE_DEST           (1<<19)
-#define MC_DEST_MASK             (1<<18)
-#define MC_DEST_CURRENT          (0<<18)
-#define MC_DEST_ACCUMULATOR      (1<<18)
-#define MC_UPDATE_ARG1           (1<<17)
-#define MC_ARG1_MASK             ((0x7<<14)|(0x1<<13)|(0x1<<12))
-#define MC_ARG1_ONE              (0x0<<14)
-#define MC_ARG1_COLOR_FACTOR     (0x1<<14)
-#define MC_ARG1_ACCUMULATOR      (0x2<<14)
-#define MC_ARG1_ITERATED_COLOR   (0x3<<14)
-#define MC_ARG1_SPECULAR_COLOR   (0x4<<14)
-#define MC_ARG1_CURRENT_COLOR    (0x5<<14)
-#define MC_ARG1_TEX0_COLOR       (0x6<<14)
-#define MC_ARG1_TEX1_COLOR       (0x7<<14)
-#define MC_ARG1_DONT_REPLICATE_ALPHA   (0x0<<13)
-#define MC_ARG1_REPLICATE_ALPHA        (0x1<<13)
-#define MC_ARG1_DONT_INVERT      (0x0<<12)
-#define MC_ARG1_INVERT           (0x1<<12)
-#define MC_UPDATE_ARG2           (1<<11)
-#define MC_ARG2_MASK             ((0x7<<8)|(0x1<<7)|(0x1<<6))
-#define MC_ARG2_ONE              (0x0<<8)
-#define MC_ARG2_COLOR_FACTOR     (0x1<<8)
-#define MC_ARG2_ACCUMULATOR      (0x2<<8)
-#define MC_ARG2_ITERATED_COLOR   (0x3<<8)
-#define MC_ARG2_SPECULAR_COLOR   (0x4<<8)
-#define MC_ARG2_CURRENT_COLOR    (0x5<<8)
-#define MC_ARG2_TEX0_COLOR       (0x6<<8)
-#define MC_ARG2_TEX1_COLOR       (0x7<<8)
-#define MC_ARG2_DONT_REPLICATE_ALPHA   (0x0<<7)
-#define MC_ARG2_REPLICATE_ALPHA        (0x1<<7)
-#define MC_ARG2_DONT_INVERT      (0x0<<6)
-#define MC_ARG2_INVERT           (0x1<<6)
-#define MC_UPDATE_OP             (1<<5)
-#define MC_OP_MASK                   (0xf)
-#define MC_OP_DISABLE                (0x0)
-#define MC_OP_ARG1                   (0x1)
-#define MC_OP_ARG2                   (0x2)
-#define MC_OP_MODULATE               (0x3)
-#define MC_OP_MODULATE_X2            (0x4)
-#define MC_OP_MODULATE_X4            (0x5)
-#define MC_OP_ADD                    (0x6)
-#define MC_OP_ADD_SIGNED             (0x7)
-#define MC_OP_LIN_BLEND_ITER_ALPHA   (0x8)
-#define MC_OP_LIN_BLEND_ALPHA_FACTOR (0xa)
-#define MC_OP_LIN_BLEND_TEX0_ALPHA   (0x10)
-#define MC_OP_LIN_BLEND_TEX1_ALPHA   (0x11)
-#define MC_OP_LIN_BLEND_TEX0_COLOR   (0x12)
-#define MC_OP_LIN_BLEND_TEX1_COLOR   (0x13)
-#define MC_OP_SUBTRACT               (0x14)
+#define GFX_OP_MAP_COLOR_STAGES        ((0x3<<29)|(0x0<<24))
+#define MC_STAGE_SHIFT                 20
+#define MC_STAGE_0                     (0<<20)
+#define MC_STAGE_1                     (1<<20)
+#define MC_STAGE_2                     (2<<20)
+#define MC_UPDATE_DEST                 (1<<19)
+#define MC_DEST_MASK                   (1<<18)
+#define MC_DEST_CURRENT                (0<<18)
+#define MC_DEST_ACCUMULATOR            (1<<18)
+
+#define MC_ARG_ONE                     (0x0<<2)
+#define MC_ARG_COLOR_FACTOR            (0x1<<2)
+#define MC_ARG_ACCUMULATOR             (0x2<<2)
+#define MC_ARG_ITERATED_COLOR          (0x3<<2)
+#define MC_ARG_SPECULAR_COLOR          (0x4<<2)
+#define MC_ARG_CURRENT_COLOR           (0x5<<2)
+#define MC_ARG_TEX0_COLOR              (0x6<<2)
+#define MC_ARG_TEX1_COLOR              (0x7<<2)
+#define MC_ARG_DONT_REPLICATE_ALPHA    (0x0<<1)
+#define MC_ARG_REPLICATE_ALPHA         (0x1<<1)
+#define MC_ARG_DONT_INVERT             (0x0)
+#define MC_ARG_INVERT                  (0x1)
+
+#define MC_UPDATE_ARG1                 (1<<17)
+#define MC_ARG1_SHIFT                  12
+#define MC_ARG1_MASK                   (0x1f << MC_ARG1_SHIFT)
+
+#define MC_UPDATE_ARG2                 (1<<11)
+#define MC_ARG2_SHIFT                  6
+#define MC_ARG2_MASK                   (0x1f << MC_ARG2_SHIFT)
+
+#define MC_UPDATE_OP                   (1<<5)
+#define MC_OP_MASK                     (0xf)
+#define MC_OP_DISABLE                  (0x0)
+#define MC_OP_ARG1                     (0x1)
+#define MC_OP_ARG2                     (0x2)
+#define MC_OP_MODULATE                 (0x3)
+#define MC_OP_MODULATE_X2              (0x4)
+#define MC_OP_MODULATE_X4              (0x5)
+#define MC_OP_ADD                      (0x6)
+#define MC_OP_ADD_SIGNED               (0x7)
+#define MC_OP_LIN_BLEND_ITER_ALPHA     (0x8)
+#define MC_OP_LIN_BLEND_ALPHA_FACTOR   (0xa)
+#define MC_OP_LIN_BLEND_TEX0_ALPHA     (0x10)
+#define MC_OP_LIN_BLEND_TEX1_ALPHA     (0x11)
+#define MC_OP_LIN_BLEND_TEX0_COLOR     (0x12)
+#define MC_OP_LIN_BLEND_TEX1_COLOR     (0x13)
+#define MC_OP_SUBTRACT                 (0x14)
 
 /* GFXRENDERSTATE_MAP_PALETTE_LOAD, p128
  *
index 47c41c5db281aec2bee32d54f6a2365f134d1c20..fd80e7675c4ced8efca777ede09c84592e72fd03 100644 (file)
@@ -73,7 +73,7 @@ int I810_DEBUG = (0);
 PUBLIC const char __driConfigOptions[] = { 0 };
 const GLuint __driNConfigOptions = 0;
 
-#define DRIVER_DATE                     "20050818"
+#define DRIVER_DATE                     "20050821"
 
 static const GLubyte *i810GetString( GLcontext *ctx, GLenum name )
 {
@@ -125,9 +125,12 @@ const struct dri_extension card_extensions[] =
     { "GL_ARB_multitexture",               NULL },
     { "GL_ARB_texture_compression",        GL_ARB_texture_compression_functions },
     { "GL_ARB_texture_env_add",            NULL },
+    { "GL_ARB_texture_env_combine",        NULL },
+    { "GL_ARB_texture_env_crossbar",       NULL },
     { "GL_ARB_texture_mirrored_repeat",    NULL },
     { "GL_EXT_stencil_wrap",               NULL },
     { "GL_EXT_texture_edge_clamp",         NULL },
+    { "GL_EXT_texture_env_combine",        NULL },
     { "GL_EXT_texture_lod_bias",           NULL },
     { "GL_MESA_ycbcr_texture",             NULL },
     { "GL_NV_blend_square",                NULL },
index 62dc819b32b78a8bf0942bfe2e463a86f548a98e..c4662e8958018b75dda17f0cbb21592339eb74ef 100644 (file)
@@ -746,13 +746,13 @@ void i810InitState( GLcontext *ctx )
                                     MC_UPDATE_DEST |
                                     MC_DEST_CURRENT |
                                     MC_UPDATE_ARG1 |
-                                    MC_ARG1_ITERATED_COLOR |
-                                    MC_ARG1_DONT_REPLICATE_ALPHA |
-                                    MC_ARG1_DONT_INVERT |
+                                    ((MC_ARG_ITERATED_COLOR |
+                                      MC_ARG_DONT_REPLICATE_ALPHA |
+                                      MC_ARG_DONT_INVERT) << MC_ARG1_SHIFT) |
                                     MC_UPDATE_ARG2 |
-                                    MC_ARG2_ONE |
-                                    MC_ARG2_DONT_REPLICATE_ALPHA |
-                                    MC_ARG2_DONT_INVERT |
+                                    ((MC_ARG_ONE |
+                                      MC_ARG_DONT_REPLICATE_ALPHA |
+                                      MC_ARG_DONT_INVERT) << MC_ARG2_SHIFT) |
                                     MC_UPDATE_OP |
                                     MC_OP_ARG1 );
 
@@ -761,13 +761,13 @@ void i810InitState( GLcontext *ctx )
                                     MC_UPDATE_DEST |
                                     MC_DEST_CURRENT |
                                     MC_UPDATE_ARG1 |
-                                    MC_ARG1_ONE |
-                                    MC_ARG1_DONT_REPLICATE_ALPHA |
-                                    MC_ARG1_DONT_INVERT |
+                                    ((MC_ARG_ONE |
+                                      MC_ARG_DONT_REPLICATE_ALPHA |
+                                      MC_ARG_DONT_INVERT) << MC_ARG1_SHIFT) |
                                     MC_UPDATE_ARG2 |
-                                    MC_ARG2_ONE |
-                                    MC_ARG2_DONT_REPLICATE_ALPHA |
-                                    MC_ARG2_DONT_INVERT |
+                                    ((MC_ARG_ONE |
+                                      MC_ARG_DONT_REPLICATE_ALPHA |
+                                      MC_ARG_DONT_INVERT) << MC_ARG2_SHIFT) |
                                     MC_UPDATE_OP |
                                     MC_OP_DISABLE );
 
@@ -777,13 +777,13 @@ void i810InitState( GLcontext *ctx )
                                     MC_UPDATE_DEST |
                                     MC_DEST_CURRENT |
                                     MC_UPDATE_ARG1 |
-                                    MC_ARG1_CURRENT_COLOR |
-                                    MC_ARG1_REPLICATE_ALPHA |
-                                    MC_ARG1_DONT_INVERT |
+                                    ((MC_ARG_CURRENT_COLOR |
+                                      MC_ARG_REPLICATE_ALPHA |
+                                      MC_ARG_DONT_INVERT) << MC_ARG1_SHIFT) |
                                     MC_UPDATE_ARG2 |
-                                    MC_ARG2_ONE |
-                                    MC_ARG2_DONT_REPLICATE_ALPHA |
-                                    MC_ARG2_DONT_INVERT |
+                                    ((MC_ARG_ONE |
+                                      MC_ARG_DONT_REPLICATE_ALPHA |
+                                      MC_ARG_DONT_INVERT) << MC_ARG2_SHIFT) |
                                     MC_UPDATE_OP |
                                     MC_OP_DISABLE );
 
@@ -791,11 +791,11 @@ void i810InitState( GLcontext *ctx )
    imesa->Setup[I810_CTXREG_MA0] = ( GFX_OP_MAP_ALPHA_STAGES |
                                     MA_STAGE_0 |
                                     MA_UPDATE_ARG1 |
-                                    MA_ARG1_ITERATED_ALPHA |
-                                    MA_ARG1_DONT_INVERT |
+                                    ((MA_ARG_ITERATED_ALPHA |
+                                      MA_ARG_DONT_INVERT) << MA_ARG1_SHIFT) |
                                     MA_UPDATE_ARG2 |
-                                    MA_ARG2_CURRENT_ALPHA |
-                                    MA_ARG2_DONT_INVERT |
+                                    ((MA_ARG_CURRENT_ALPHA |
+                                      MA_ARG_DONT_INVERT) << MA_ARG2_SHIFT) |
                                     MA_UPDATE_OP |
                                     MA_OP_ARG1 );
 
@@ -803,11 +803,11 @@ void i810InitState( GLcontext *ctx )
    imesa->Setup[I810_CTXREG_MA1] = ( GFX_OP_MAP_ALPHA_STAGES |
                                     MA_STAGE_1 |
                                     MA_UPDATE_ARG1 |
-                                    MA_ARG1_CURRENT_ALPHA |
-                                    MA_ARG1_DONT_INVERT |
+                                    ((MA_ARG_CURRENT_ALPHA |
+                                      MA_ARG_DONT_INVERT) << MA_ARG1_SHIFT) |
                                     MA_UPDATE_ARG2 |
-                                    MA_ARG2_CURRENT_ALPHA |
-                                    MA_ARG2_DONT_INVERT |
+                                    ((MA_ARG_CURRENT_ALPHA |
+                                      MA_ARG_DONT_INVERT) << MA_ARG2_SHIFT) |
                                     MA_UPDATE_OP |
                                     MA_OP_ARG1 );
 
@@ -815,11 +815,11 @@ void i810InitState( GLcontext *ctx )
    imesa->Setup[I810_CTXREG_MA2] = ( GFX_OP_MAP_ALPHA_STAGES |
                                     MA_STAGE_2 |
                                     MA_UPDATE_ARG1 |
-                                    MA_ARG1_CURRENT_ALPHA |
-                                    MA_ARG1_DONT_INVERT |
+                                    ((MA_ARG_CURRENT_ALPHA |
+                                      MA_ARG_DONT_INVERT) << MA_ARG1_SHIFT) |
                                     MA_UPDATE_ARG2 |
-                                    MA_ARG2_CURRENT_ALPHA |
-                                    MA_ARG2_DONT_INVERT |
+                                    ((MA_ARG_CURRENT_ALPHA |
+                                      MA_ARG_DONT_INVERT) << MA_ARG2_SHIFT) |
                                     MA_UPDATE_OP |
                                     MA_OP_ARG1 );
 
index 10a15f961f623934e734177a2c3d98fb0eb09f8c..6b6d1d727fceac6fd55e9616825cc55eea3f209d 100644 (file)
@@ -132,620 +132,567 @@ static void i810SetTexImages( i810ContextPtr imesa,
  * Texture combine functions
  */
 
-#define I810_DISABLE           0
-#define I810_PASSTHRU          1
-#define I810_REPLACE           2
-#define I810_MODULATE          3
-#define I810_DECAL             4
-#define I810_BLEND             5
-#define I810_ALPHA_BLEND       6
-#define I810_ADD               7
-#define I810_MAX_COMBFUNC      8
-
-
-static GLuint i810_color_combine[][I810_MAX_COMBFUNC] =
-{
-   /* Unit 0:
-    */
-   {
-      /* Disable combiner stage
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_0 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_ITERATED_COLOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_ONE |
-       MC_UPDATE_OP |
-       MC_OP_ARG1 ),           /* actually passthru */
-
-      /* Passthru
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_0 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_ITERATED_COLOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_ONE |
-       MC_UPDATE_OP |
-       MC_OP_ARG1 ),
-
-      /* GL_REPLACE 
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_0 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_TEX0_COLOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_ONE |
-       MC_UPDATE_OP |
-       MC_OP_ARG1 ),
-
-      /* GL_MODULATE
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_0 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_TEX0_COLOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_ITERATED_COLOR |
-       MC_UPDATE_OP |
-       MC_OP_MODULATE ),
-
-      /* GL_DECAL 
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_0 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_COLOR_FACTOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_TEX0_COLOR |
-       MC_UPDATE_OP |
-       MC_OP_LIN_BLEND_TEX0_ALPHA ),
-
-      /* GL_BLEND 
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_0 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_COLOR_FACTOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_ITERATED_COLOR |
-       MC_UPDATE_OP |
-       MC_OP_LIN_BLEND_TEX0_COLOR ),
-
-      /* GL_BLEND according to alpha
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_0 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_TEX0_COLOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_ITERATED_COLOR |
-       MC_UPDATE_OP |
-       MC_OP_LIN_BLEND_TEX0_ALPHA ),
-
-      /* GL_ADD 
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_0 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_TEX0_COLOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_ITERATED_COLOR |
-       MC_UPDATE_OP |
-       MC_OP_ADD ),
-   },
-
-   /* Unit 1:
-    */
-   {
-      /* Disable combiner stage (Note: disables all subsequent stages)
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_1 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_ONE | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_ONE |
-       MC_UPDATE_OP |
-       MC_OP_DISABLE ),
 
-      
-      /* Passthru
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_1 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_CURRENT_COLOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_ONE |
-       MC_UPDATE_OP |
-       MC_OP_ARG1 ),
-
-      /* GL_REPLACE
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_1 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_TEX1_COLOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_ONE |
-       MC_UPDATE_OP |
-       MC_OP_ARG1 ),
-
-      /* GL_MODULATE
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_1 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_TEX1_COLOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_CURRENT_COLOR |
-       MC_UPDATE_OP |
-       MC_OP_MODULATE ),
-
-      /* GL_DECAL
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_1 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_COLOR_FACTOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_TEX1_COLOR |
-       MC_UPDATE_OP |
-       MC_OP_LIN_BLEND_TEX1_ALPHA ),
-      
-      /* GL_BLEND 
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_1 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_COLOR_FACTOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_CURRENT_COLOR |
-       MC_UPDATE_OP |
-       MC_OP_LIN_BLEND_TEX1_COLOR ),
-
-      /* GL_BLEND according to alpha
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_1 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_TEX1_COLOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_CURRENT_COLOR |
-       MC_UPDATE_OP |
-       MC_OP_LIN_BLEND_TEX1_ALPHA ),
-
-      /* GL_ADD 
-       */
-      ( GFX_OP_MAP_COLOR_STAGES |
-       MC_STAGE_1 |
-       MC_UPDATE_DEST |
-       MC_DEST_CURRENT |
-       MC_UPDATE_ARG1 |
-       MC_ARG1_TEX1_COLOR | 
-       MC_UPDATE_ARG2 |
-       MC_ARG2_CURRENT_COLOR |
-       MC_UPDATE_OP |
-       MC_OP_ADD ),
+static void set_color_stage( unsigned color, int stage,
+                             i810ContextPtr imesa )
+{
+   if ( color != imesa->Setup[I810_CTXREG_MC0 + stage] ) {
+      I810_STATECHANGE( imesa, I810_UPLOAD_CTX );
+      imesa->Setup[I810_CTXREG_MC0 + stage] = color;
    }
-};
+}
+
 
-static GLuint i810_alpha_combine[][I810_MAX_COMBFUNC] =
+static void set_alpha_stage( unsigned alpha, int stage,
+                                   i810ContextPtr imesa )
 {
-   /* Unit 0:
-    */
-   {
-      /* Disable combiner stage
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_0 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_ITERATED_ALPHA |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_TEX0_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_ARG1 ),
-
-      /* Passthru
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_0 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_ITERATED_ALPHA |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_TEX0_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_ARG1 ),
-
-      /* GL_REPLACE 
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_0 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_ITERATED_ALPHA |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_TEX0_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_ARG2 ),
-
-      /* GL_MODULATE
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_0 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_ITERATED_ALPHA |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_TEX0_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_MODULATE ),
-
-      /* GL_DECAL 
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_0 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_ALPHA_FACTOR |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_ALPHA_FACTOR |
-       MA_UPDATE_OP |
-       MA_OP_ARG1 ),
-
-      /* GL_BLEND 
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_0 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_ALPHA_FACTOR |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_ITERATED_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_LIN_BLEND_TEX0_ALPHA ),
-
-      /* GL_BLEND according to alpha (same as above)
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_0 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_ALPHA_FACTOR |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_ITERATED_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_LIN_BLEND_TEX0_ALPHA ),
-
-      /* GL_ADD 
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_0 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_ITERATED_ALPHA |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_TEX0_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_ADD ),
-   },
-
-   /* Unit 1:
-    */
-   {
-      /* Disable combiner stage
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_1 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_CURRENT_ALPHA |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_CURRENT_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_ARG1 ),
-
-      /* Passthru
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_1 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_CURRENT_ALPHA |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_CURRENT_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_ARG1 ),
-
-      /* GL_REPLACE 
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_1 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_CURRENT_ALPHA |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_TEX1_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_ARG2 ),
-
-      /* GL_MODULATE 
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_1 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_CURRENT_ALPHA |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_TEX1_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_MODULATE ),
-
-      /* GL_DECAL 
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_1 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_ALPHA_FACTOR |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_ALPHA_FACTOR |
-       MA_UPDATE_OP |
-       MA_OP_ARG1 ),
-
-      /* GL_BLEND 
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_1 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_ALPHA_FACTOR |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_ITERATED_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_LIN_BLEND_TEX1_ALPHA ),
-
-      /* GL_BLEND according to alpha (same as above)
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_1 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_ALPHA_FACTOR |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_ITERATED_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_LIN_BLEND_TEX1_ALPHA ),
-
-      /* GL_ADD 
-       */
-      ( GFX_OP_MAP_ALPHA_STAGES |
-       MA_STAGE_1 |
-       MA_UPDATE_ARG1 |
-       MA_ARG1_CURRENT_ALPHA |
-       MA_UPDATE_ARG2 |
-       MA_ARG2_TEX1_ALPHA |
-       MA_UPDATE_OP |
-       MA_OP_ADD ),
+   if ( alpha != imesa->Setup[I810_CTXREG_MA0 + stage] ) {
+      I810_STATECHANGE( imesa, I810_UPLOAD_CTX );
+      imesa->Setup[I810_CTXREG_MA0 + stage] = alpha;
    }
-
-};
+}
 
 
+static const unsigned operand_modifiers[] = {
+   0,                       MC_ARG_INVERT,
+   MC_ARG_REPLICATE_ALPHA,  MC_ARG_INVERT | MC_ARG_REPLICATE_ALPHA
+};
 
-static void i810UpdateTexEnv( GLcontext *ctx, GLuint unit )
+/**
+ * Configure the hardware bits for the specified texture environment.
+ *
+ * Configures the hardware bits for the texture environment state for the
+ * specified texture unit.  As combine stages are added, the values pointed
+ * to by \c color_stage and \c alpha_stage are incremented.
+ *
+ * \param ctx          GL context pointer.
+ * \param unit         Texture unit to be added.
+ * \param color_stage  Next available hardware color combine stage.
+ * \param alpha_stage  Next available hardware alpha combine stage.
+ *
+ * \returns
+ * If the combine mode for the specified texture unit could be added without
+ * requiring a software fallback, \c GL_TRUE is returned.  Otherwise,
+ * \c GL_FALSE is returned.
+ *
+ * \todo
+ * If the mode is (GL_REPLACE, GL_PREVIOUS), treat it as though the texture
+ * stage is disabled.  That is, don't emit any combine stages.
+ *
+ * \todo
+ * Add support for ATI_texture_env_combine3 modes.  This will require using
+ * two combine stages.
+ *
+ * \todo
+ * Add support for the missing \c GL_INTERPOLATE modes.  This will require
+ * using all three combine stages.  There is a comment in the function
+ * describing how this might work.
+ *
+ * \todo
+ * If, after all the combine stages have been emitted, a texture is never
+ * actually used, disable the texture unit.  That should save texture some
+ * memory bandwidth.  This won't happen in this function, but this seems like
+ * a reasonable place to make note of it.
+ */
+static GLboolean
+i810UpdateTexEnvCombine( GLcontext *ctx, GLuint unit, 
+                        int * color_stage, int * alpha_stage )
 {
    i810ContextPtr imesa = I810_CONTEXT(ctx);
    const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
-   const struct gl_texture_object *tObj = texUnit->_Current;
-   const GLuint format = tObj->Image[0][tObj->BaseLevel]->Format;
+   GLuint color_arg[3] = {
+      MC_ARG_ONE,            MC_ARG_ONE,            MC_ARG_ONE
+   };
+   GLuint alpha_arg[3] = {
+      MA_ARG_ITERATED_ALPHA, MA_ARG_ITERATED_ALPHA, MA_ARG_ITERATED_ALPHA
+   };
+   GLuint i;
    GLuint color_combine, alpha_combine;
+   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:
-      if (format == GL_ALPHA) {
-        color_combine = i810_color_combine[unit][I810_PASSTHRU];
-        alpha_combine = i810_alpha_combine[unit][I810_REPLACE];
-      } else if (format == GL_LUMINANCE || format == GL_RGB) {
-        color_combine = i810_color_combine[unit][I810_REPLACE];
-        alpha_combine = i810_alpha_combine[unit][I810_PASSTHRU];
-      } else {
-        color_combine = i810_color_combine[unit][I810_REPLACE];
-        alpha_combine = i810_alpha_combine[unit][I810_REPLACE];
-      }
-      break;
 
-   case GL_MODULATE:
-      if (format == GL_ALPHA) {
-        color_combine = i810_color_combine[unit][I810_PASSTHRU];
-        alpha_combine = i810_alpha_combine[unit][I810_MODULATE];
-      } else {
-        color_combine = i810_color_combine[unit][I810_MODULATE];
-        alpha_combine = i810_alpha_combine[unit][I810_MODULATE];
+   if ( !texUnit->_ReallyEnabled ) {
+      return GL_TRUE;
+   }
+
+      
+   if ((*color_stage >= 3) || (*alpha_stage >= 3)) {
+      return GL_FALSE;
+   }
+
+
+   /* Step 1:
+    * Extract the color and alpha combine function arguments.
+    */
+
+   for ( i = 0 ; i < numColorArgs ; i++ ) {
+      unsigned op = texUnit->_CurrentCombine->OperandRGB[i] - GL_SRC_COLOR;
+      assert(op >= 0);
+      assert(op <= 3);
+      switch ( texUnit->_CurrentCombine->SourceRGB[i] ) {
+      case GL_TEXTURE0:
+        color_arg[i] = MC_ARG_TEX0_COLOR;
+        break;
+      case GL_TEXTURE1:
+        color_arg[i] = MC_ARG_TEX1_COLOR;
+        break;
+      case GL_TEXTURE:
+        color_arg[i] = (unit == 0) 
+          ? MC_ARG_TEX0_COLOR : MC_ARG_TEX1_COLOR;
+        break;
+      case GL_CONSTANT:
+        color_arg[i] = MC_ARG_COLOR_FACTOR;
+        break;
+      case GL_PRIMARY_COLOR:
+        color_arg[i] = MC_ARG_ITERATED_COLOR;
+        break;
+      case GL_PREVIOUS:
+        color_arg[i] = (unit == 0)
+          ? MC_ARG_ITERATED_COLOR : MC_ARG_CURRENT_COLOR;
+        break;
+      case GL_ZERO:
+        /* Toggle the low bit of the op value.  The is the 'invert' bit,
+         * and it acts to convert GL_ZERO+op to the equivalent GL_ONE+op.
+         */
+        op ^= 1;
+
+        /*FALLTHROUGH*/
+
+      case GL_ONE:
+        color_arg[i] = MC_ARG_ONE;
+        break;
+      default:
+        return GL_FALSE;
       }
-      break;
 
-   case GL_DECAL:
-      switch (format) {
-      case GL_RGBA:
-        color_combine = i810_color_combine[unit][I810_ALPHA_BLEND];
-        alpha_combine = i810_alpha_combine[unit][I810_PASSTHRU];
+      color_arg[i] |= operand_modifiers[op];
+   }
+
+
+   for ( i = 0 ; i < numAlphaArgs ; i++ ) {
+      unsigned op = texUnit->_CurrentCombine->OperandA[i] - GL_SRC_ALPHA;
+      assert(op >= 0);
+      assert(op <= 1);
+      switch ( texUnit->_CurrentCombine->SourceA[i] ) {
+      case GL_TEXTURE0:
+        alpha_arg[i] = MA_ARG_TEX0_ALPHA;
+        break;
+      case GL_TEXTURE1:
+        alpha_arg[i] = MA_ARG_TEX1_ALPHA;
         break;
-      case GL_RGB:
-        color_combine = i810_color_combine[unit][I810_REPLACE];
-        alpha_combine = i810_alpha_combine[unit][I810_PASSTHRU];
+      case GL_TEXTURE:
+        alpha_arg[i] = (unit == 0)
+          ? MA_ARG_TEX0_ALPHA : MA_ARG_TEX1_ALPHA;
         break;
-      case GL_ALPHA:
-      case GL_LUMINANCE:
-      case GL_LUMINANCE_ALPHA:
-      case GL_INTENSITY:
-        color_combine = i810_color_combine[unit][I810_PASSTHRU];
-        alpha_combine = i810_alpha_combine[unit][I810_PASSTHRU];
+      case GL_CONSTANT:
+        alpha_arg[i] = MA_ARG_ALPHA_FACTOR;
+        break;
+      case GL_PRIMARY_COLOR:
+        alpha_arg[i] = MA_ARG_ITERATED_ALPHA;
+        break;
+      case GL_PREVIOUS:
+        alpha_arg[i] = (unit == 0)
+          ? MA_ARG_ITERATED_ALPHA : MA_ARG_CURRENT_ALPHA;
+        break;
+      case GL_ZERO:
+        /* Toggle the low bit of the op value.  The is the 'invert' bit,
+         * and it acts to convert GL_ZERO+op to the equivalent GL_ONE+op.
+         */
+        op ^= 1;
+
+        /*FALLTHROUGH*/
+
+      case GL_ONE:
+        if (i != 2) {
+           return GL_FALSE;
+        }
+
+        alpha_arg[i] = MA_ARG_ONE;
         break;
-      case GL_COLOR_INDEX:
       default:
-        return;
+        return GL_FALSE;
       }
+
+      alpha_arg[i] |= operand_modifiers[op];
+   }
+
+
+   /* Step 2:
+    * Build up the color and alpha combine functions.
+    */
+   switch ( texUnit->_CurrentCombine->ModeRGB ) {
+   case GL_REPLACE:
+      color_combine = MC_OP_ARG1;
+      break;
+   case GL_MODULATE:
+      color_combine = MC_OP_MODULATE + RGBshift;
+      RGBshift = 0;
+      break;
+   case GL_ADD:
+      color_combine = MC_OP_ADD;
+      break;
+   case GL_ADD_SIGNED:
+      color_combine = MC_OP_ADD_SIGNED;
       break;
+   case GL_SUBTRACT:
+      color_combine = MC_OP_SUBTRACT;
+      break;
+   case GL_INTERPOLATE:
+      /* For interpolation, the i810 hardware has some limitations.  It
+       * can't handle using the secondary or diffuse color (diffuse alpha
+       * is okay) for the third argument.
+       *
+       * It is possible to emulate the missing modes by using multiple
+       * combine stages.  Unfortunately it requires all three stages to
+       * emulate a single interpolate stage.  The (arg0*arg2) portion is
+       * done in stage zero and writes to MC_DEST_ACCUMULATOR.  The
+       * (arg1*(1-arg2)) portion is done in stage 1, and the final stage is
+       * (MC_ARG1_ACCUMULATOR | MC_ARG2_CURRENT_COLOR | MC_OP_ADD).
+       * 
+       * It can also be done without using the accumulator by rearranging
+       * the equation as (arg1 + (arg2 * (arg0 - arg1))).  Too bad the i810
+       * doesn't support the MODULATE_AND_ADD mode that the i830 supports.
+       * If it did, the interpolate could be done in only two stages.
+       */
+        
+      if ( (color_arg[2] & MC_ARG_INVERT) != 0 ) {
+        unsigned temp = color_arg[0];
+
+        color_arg[0] = color_arg[1];
+        color_arg[1] = temp;
+        color_arg[2] &= ~MC_ARG_INVERT;
+      }
+
+      switch (color_arg[2]) {
+      case (MC_ARG_ONE):
+      case (MC_ARG_ONE | MC_ARG_REPLICATE_ALPHA):
+        color_combine = MC_OP_ARG1;
+        color_arg[1] = MC_ARG_ONE;
+        break;
+
+      case (MC_ARG_COLOR_FACTOR):
+        return GL_FALSE;
+
+      case (MC_ARG_COLOR_FACTOR | MC_ARG_REPLICATE_ALPHA):
+        color_combine = MC_OP_LIN_BLEND_ALPHA_FACTOR;
+        break;
+
+      case (MC_ARG_ITERATED_COLOR):
+        return GL_FALSE;
+
+      case (MC_ARG_ITERATED_COLOR | MC_ARG_REPLICATE_ALPHA):
+        color_combine = MC_OP_LIN_BLEND_ITER_ALPHA;
+        break;
+
+      case (MC_ARG_SPECULAR_COLOR):
+      case (MC_ARG_SPECULAR_COLOR | MC_ARG_REPLICATE_ALPHA):
+        return GL_FALSE;
 
-   case GL_BLEND:
-      switch (format) {
-      case GL_RGB:
-      case GL_LUMINANCE:
-        color_combine = i810_color_combine[unit][I810_BLEND];
-        alpha_combine = i810_alpha_combine[unit][I810_PASSTHRU];
+      case (MC_ARG_TEX0_COLOR):
+        color_combine = MC_OP_LIN_BLEND_TEX0_COLOR;
         break;
-      case GL_RGBA:
-      case GL_LUMINANCE_ALPHA:
-        color_combine = i810_color_combine[unit][I810_BLEND];
-        alpha_combine = i810_alpha_combine[unit][I810_MODULATE];
+
+      case (MC_ARG_TEX0_COLOR | MC_ARG_REPLICATE_ALPHA):
+        color_combine = MC_OP_LIN_BLEND_TEX0_ALPHA;
         break;
-      case GL_ALPHA:
-        color_combine = i810_color_combine[unit][I810_PASSTHRU];
-        alpha_combine = i810_alpha_combine[unit][I810_MODULATE];
+
+      case (MC_ARG_TEX1_COLOR):
+        color_combine = MC_OP_LIN_BLEND_TEX1_COLOR;
         break;
-      case GL_INTENSITY:
-        color_combine = i810_color_combine[unit][I810_BLEND];
-        alpha_combine = i810_alpha_combine[unit][I810_BLEND];
+
+      case (MC_ARG_TEX1_COLOR | MC_ARG_REPLICATE_ALPHA):
+        color_combine = MC_OP_LIN_BLEND_TEX1_ALPHA;
         break;
-      case GL_COLOR_INDEX:
+
       default:
-        return;
+        return GL_FALSE;
       }
       break;
 
+   default:
+      return GL_FALSE;
+   }
+
+   
+   switch ( texUnit->_CurrentCombine->ModeA ) {
+   case GL_REPLACE:
+      alpha_combine = MA_OP_ARG1;
+      break;
+   case GL_MODULATE:
+      alpha_combine = MA_OP_MODULATE + Ashift;
+      Ashift = 0;
+      break;
    case GL_ADD:
-      switch (format) {
-      case GL_RGB:
-      case GL_LUMINANCE:
-        color_combine = i810_color_combine[unit][I810_ADD];
-        alpha_combine = i810_alpha_combine[unit][I810_PASSTHRU];
+      alpha_combine = MA_OP_ADD;
+      break;
+   case GL_ADD_SIGNED:
+      alpha_combine = MA_OP_ADD_SIGNED;
+      break;
+   case GL_SUBTRACT:
+      alpha_combine = MA_OP_SUBTRACT;
+      break;
+   case GL_INTERPOLATE:
+      if ( (alpha_arg[2] & MA_ARG_INVERT) != 0 ) {
+        unsigned temp = alpha_arg[0];
+
+        alpha_arg[0] = alpha_arg[1];
+        alpha_arg[1] = temp;
+        alpha_arg[2] &= ~MA_ARG_INVERT;
+      }
+
+      switch (alpha_arg[2]) {
+      case MA_ARG_ONE:
+        alpha_combine = MA_OP_ARG1;
+        alpha_arg[1] = MA_ARG_ITERATED_ALPHA;
+        break;
+
+      case MA_ARG_ALPHA_FACTOR:
+        alpha_combine = MA_OP_LIN_BLEND_ALPHA_FACTOR;
         break;
-      case GL_RGBA:
-      case GL_LUMINANCE_ALPHA:
-        color_combine = i810_color_combine[unit][I810_ADD];
-        alpha_combine = i810_alpha_combine[unit][I810_MODULATE];
+
+      case MA_ARG_ITERATED_ALPHA:
+        alpha_combine = MA_OP_LIN_BLEND_ITER_ALPHA;
         break;
-      case GL_ALPHA:
-        color_combine = i810_color_combine[unit][I810_PASSTHRU];
-        alpha_combine = i810_alpha_combine[unit][I810_MODULATE];
+
+      case MA_ARG_TEX0_ALPHA:
+        alpha_combine = MA_OP_LIN_BLEND_TEX0_ALPHA;
         break;
-      case GL_INTENSITY:
-        color_combine = i810_color_combine[unit][I810_ADD];
-        alpha_combine = i810_alpha_combine[unit][I810_ADD];
+
+      case MA_ARG_TEX1_ALPHA:
+        alpha_combine = MA_OP_LIN_BLEND_TEX1_ALPHA;
         break;
-      case GL_COLOR_INDEX:
+
       default:
-        return;
+        return GL_FALSE;
       }
       break;
 
    default:
-      return;
+      return GL_FALSE;
    }
 
-   if (alpha_combine != imesa->Setup[I810_CTXREG_MA0 + unit] ||
-       color_combine != imesa->Setup[I810_CTXREG_MC0 + unit]) 
-   {
-      I810_STATECHANGE( imesa, I810_UPLOAD_CTX );
-      imesa->Setup[I810_CTXREG_MA0 + unit] = alpha_combine;
-      imesa->Setup[I810_CTXREG_MC0 + unit] = color_combine;
-   }   
-}
 
+   color_combine |= GFX_OP_MAP_COLOR_STAGES | (*color_stage << MC_STAGE_SHIFT)
+     | MC_UPDATE_DEST | MC_DEST_CURRENT
+     | MC_UPDATE_ARG1 | (color_arg[0] << MC_ARG1_SHIFT)
+     | MC_UPDATE_ARG2 | (color_arg[1] << MC_ARG2_SHIFT)
+     | MC_UPDATE_OP;
+
+   alpha_combine |= GFX_OP_MAP_ALPHA_STAGES | (*alpha_stage << MA_STAGE_SHIFT)
+     | MA_UPDATE_ARG1 | (alpha_arg[0] << MA_ARG1_SHIFT)
+     | MA_UPDATE_ARG2 | (alpha_arg[1] << MA_ARG2_SHIFT)
+     | MA_UPDATE_OP;
 
+   set_color_stage( color_combine, *color_stage, imesa );
+   set_alpha_stage( alpha_combine, *alpha_stage, imesa );
+   (*color_stage)++;
+   (*alpha_stage)++;
 
 
-static void i810UpdateTexUnit( GLcontext *ctx, GLuint unit )
+   /* Step 3:
+    * Apply the scale factor.
+    */
+   /* The only operation where the i810 directly supports adding a post-
+    * scale factor is modulate.  For all the other modes the post-scale is
+    * emulated by inserting and extra modulate stage.  For the modulate
+    * case, the scaling is handled above when color_combine / alpha_combine
+    * are initially set.
+    */
+
+   if ( RGBshift != 0 ) {
+      const unsigned color_scale = GFX_OP_MAP_COLOR_STAGES
+       | (*color_stage << MC_STAGE_SHIFT)
+       | MC_UPDATE_DEST | MC_DEST_CURRENT
+       | MC_UPDATE_ARG1 | (MC_ARG_CURRENT_COLOR << MC_ARG1_SHIFT)
+       | MC_UPDATE_ARG2 | (MC_ARG_ONE           << MC_ARG2_SHIFT)
+       | MC_UPDATE_OP   | (MC_OP_MODULATE + RGBshift);
+
+      if ( *color_stage >= 3 ) {
+        return GL_FALSE;
+      }
+
+      set_color_stage( color_scale, *color_stage, imesa );
+      (*color_stage)++;
+   }
+
+   
+   if ( Ashift != 0 ) {
+      const unsigned alpha_scale = GFX_OP_MAP_ALPHA_STAGES
+       | (*alpha_stage << MA_STAGE_SHIFT)
+       | MA_UPDATE_ARG1 | (MA_ARG_CURRENT_ALPHA << MA_ARG1_SHIFT)
+       | MA_UPDATE_ARG2 | (MA_ARG_ONE           << MA_ARG2_SHIFT)
+       | MA_UPDATE_OP   | (MA_OP_MODULATE + Ashift);
+
+      if ( *alpha_stage >= 3 ) {
+        return GL_FALSE;
+      }
+
+      set_alpha_stage( alpha_scale, *alpha_stage, imesa );
+      (*alpha_stage)++;
+   }
+
+   return GL_TRUE;
+}
+
+
+/**
+ * Update hardware state for a texture unit.
+ *
+ * \todo
+ * 1D textures should be supported!  Just use a 2D texture with the second
+ * texture coordinate value fixed at 0.0.
+ */
+static void i810UpdateTexUnit( GLcontext *ctx, GLuint unit, 
+                             int * next_color_stage, int * next_alpha_stage )
 {
    i810ContextPtr imesa = I810_CONTEXT(ctx);
    struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
 
-   if (texUnit->_ReallyEnabled == TEXTURE_2D_BIT) 
-   {
-      struct gl_texture_object *tObj = texUnit->_Current;
-      i810TextureObjectPtr t = (i810TextureObjectPtr)tObj->DriverData;
+   if ( (texUnit->_ReallyEnabled == TEXTURE_2D_BIT)
+       || (texUnit->_ReallyEnabled == 0) ) {
+      if (texUnit->_ReallyEnabled != 0) {
+        struct gl_texture_object *tObj = texUnit->_Current;
+        i810TextureObjectPtr t = (i810TextureObjectPtr)tObj->DriverData;
 
-      /* Upload teximages (not pipelined)
-       */
-      if (t->base.dirty_images[0]) {
-        I810_FIREVERTICES(imesa);
-        i810SetTexImages( imesa, tObj );
-        if (!t->base.memBlock) {
+        if (tObj->Image[0][tObj->BaseLevel]->Border > 0) {
            FALLBACK( imesa, I810_FALLBACK_TEXTURE, GL_TRUE );
            return;
         }
-      }
 
-      if (tObj->Image[0][tObj->BaseLevel]->Border > 0) {
-         FALLBACK( imesa, I810_FALLBACK_TEXTURE, GL_TRUE );
-         return;
-      }
 
-      /* Update state if this is a different texture object to last
-       * time.
-       */
-      if (imesa->CurrentTexObj[unit] != t) {
-        I810_STATECHANGE(imesa, (I810_UPLOAD_TEX0<<unit));
-        imesa->CurrentTexObj[unit] = t;
-        t->base.bound |= (1U << unit);
-        
-        driUpdateTextureLRU( (driTextureObject *) t ); /* XXX: should be locked */
+        /* Upload teximages (not pipelined)
+         */
+        if (t->base.dirty_images[0]) {
+           I810_FIREVERTICES(imesa);
+           i810SetTexImages( imesa, tObj );
+           if (!t->base.memBlock) {
+              FALLBACK( imesa, I810_FALLBACK_TEXTURE, GL_TRUE );
+              return;
+           }
+        }
 
-      }
+
+        /* Update state if this is a different texture object to last
+         * time.
+         */
+        if (imesa->CurrentTexObj[unit] != t) {
+           I810_STATECHANGE(imesa, (I810_UPLOAD_TEX0<<unit));
+           imesa->CurrentTexObj[unit] = t;
+           t->base.bound |= (1U << unit);
+
+           /* XXX: should be locked */
+           driUpdateTextureLRU( (driTextureObject *) t );
+        }
       
-      /* Update texture environment if texture object image format or 
-       * texture environment state has changed.
-       */
-      if (tObj->Image[0][tObj->BaseLevel]->Format != imesa->TexEnvImageFmt[unit]) {
+        /* Update texture environment if texture object image format or 
+         * texture environment state has changed.
+         */
+
         imesa->TexEnvImageFmt[unit] = tObj->Image[0][tObj->BaseLevel]->Format;
-        i810UpdateTexEnv( ctx, unit );
+      }
+      else {
+        imesa->CurrentTexObj[unit] = 0;
+        imesa->TexEnvImageFmt[unit] = 0;       
+        imesa->dirty &= ~(I810_UPLOAD_TEX0<<unit); 
+      }
+      
+      if (!i810UpdateTexEnvCombine( ctx, unit, 
+                                   next_color_stage, next_alpha_stage )) {
+        FALLBACK( imesa, I810_FALLBACK_TEXTURE, GL_TRUE );
       }
    }
    else if (texUnit->_ReallyEnabled) {
       FALLBACK( imesa, I810_FALLBACK_TEXTURE, GL_TRUE );
    }
-   else /*if (imesa->CurrentTexObj[unit])*/ {
-      imesa->CurrentTexObj[unit] = 0;
-      imesa->TexEnvImageFmt[unit] = 0; 
-      imesa->dirty &= ~(I810_UPLOAD_TEX0<<unit); 
-      imesa->Setup[I810_CTXREG_MA0 + unit] = 
-        i810_alpha_combine[unit][I810_DISABLE];
-      imesa->Setup[I810_CTXREG_MC0 + unit] = 
-        i810_color_combine[unit][I810_DISABLE];
-      I810_STATECHANGE( imesa, I810_UPLOAD_CTX );
-   }
+
+   return;
 }
 
 
 void i810UpdateTextureState( GLcontext *ctx )
 {
+   static const unsigned color_pass[3] = {
+      GFX_OP_MAP_COLOR_STAGES | MC_STAGE_0 | MC_UPDATE_DEST | MC_DEST_CURRENT
+       | MC_UPDATE_ARG1 | (MC_ARG_ITERATED_COLOR << MC_ARG1_SHIFT)
+       | MC_UPDATE_ARG2 | (MC_ARG_ONE            << MC_ARG2_SHIFT)
+       | MC_UPDATE_OP   | MC_OP_ARG1,
+      GFX_OP_MAP_COLOR_STAGES | MC_STAGE_1 | MC_UPDATE_DEST | MC_DEST_CURRENT
+       | MC_UPDATE_ARG1 | (MC_ARG_CURRENT_COLOR  << MC_ARG1_SHIFT)
+       | MC_UPDATE_ARG2 | (MC_ARG_ONE            << MC_ARG2_SHIFT)
+       | MC_UPDATE_OP   | MC_OP_ARG1,
+      GFX_OP_MAP_COLOR_STAGES | MC_STAGE_2 | MC_UPDATE_DEST | MC_DEST_CURRENT
+       | MC_UPDATE_ARG1 | (MC_ARG_CURRENT_COLOR  << MC_ARG1_SHIFT)
+       | MC_UPDATE_ARG2 | (MC_ARG_ONE            << MC_ARG2_SHIFT)
+       | MC_UPDATE_OP   | MC_OP_ARG1
+   };
+   static const unsigned alpha_pass[3] = {
+      GFX_OP_MAP_ALPHA_STAGES | MA_STAGE_0
+       | MA_UPDATE_ARG1 | (MA_ARG_ITERATED_ALPHA << MA_ARG1_SHIFT)
+       | MA_UPDATE_ARG2 | (MA_ARG_ITERATED_ALPHA << MA_ARG2_SHIFT)
+       | MA_UPDATE_OP   | MA_OP_ARG1,
+      GFX_OP_MAP_ALPHA_STAGES | MA_STAGE_1
+       | MA_UPDATE_ARG1 | (MA_ARG_CURRENT_ALPHA  << MA_ARG1_SHIFT)
+       | MA_UPDATE_ARG2 | (MA_ARG_CURRENT_ALPHA  << MA_ARG2_SHIFT)
+       | MA_UPDATE_OP   | MA_OP_ARG1,
+      GFX_OP_MAP_ALPHA_STAGES | MA_STAGE_2
+       | MA_UPDATE_ARG1 | (MA_ARG_CURRENT_ALPHA  << MA_ARG1_SHIFT)
+       | MA_UPDATE_ARG2 | (MA_ARG_CURRENT_ALPHA  << MA_ARG2_SHIFT)
+       | MA_UPDATE_OP   | MA_OP_ARG1
+   };
    i810ContextPtr imesa = I810_CONTEXT(ctx);
+   int next_color_stage = 0;
+   int next_alpha_stage = 0;
+
+
    /*  fprintf(stderr, "%s\n", __FUNCTION__); */
    FALLBACK( imesa, I810_FALLBACK_TEXTURE, GL_FALSE );
-   i810UpdateTexUnit( ctx, 0 );
-   i810UpdateTexUnit( ctx, 1 );
-}
 
+   i810UpdateTexUnit( ctx, 0, & next_color_stage, & next_alpha_stage );
+   i810UpdateTexUnit( ctx, 1, & next_color_stage, & next_alpha_stage );
 
+   /* There needs to be at least one combine stage emitted that just moves
+    * the incoming primary color to the current color register.  In addition,
+    * there number be the same number of color and alpha stages emitted.
+    * Finally, if there are less than 3 combine stages, a MC_OP_DISABLE stage
+    * must be emitted.
+    */
+
+   while ( (next_color_stage == 0) ||
+          (next_color_stage < next_alpha_stage) ) {
+      set_color_stage( color_pass[ next_color_stage ], next_color_stage,
+                      imesa );
+      next_color_stage++;
+   }
 
+   assert( next_color_stage <= 3 );
+
+   while ( next_alpha_stage < next_color_stage ) {
+      set_alpha_stage( alpha_pass[ next_alpha_stage ], next_alpha_stage,
+                      imesa );
+      next_alpha_stage++;
+   }
+
+   assert( next_alpha_stage <= 3 );
+   assert( next_color_stage == next_alpha_stage );
+
+   if ( next_color_stage < 3 ) {
+      const unsigned color = GFX_OP_MAP_COLOR_STAGES
+       | (next_color_stage << MC_STAGE_SHIFT)
+       | MC_UPDATE_DEST | MC_DEST_CURRENT
+       | MC_UPDATE_ARG1 | (MC_ARG_ONE << MC_ARG1_SHIFT)
+       | MC_UPDATE_ARG2 | (MC_ARG_ONE << MC_ARG2_SHIFT)
+       | MC_UPDATE_OP   | (MC_OP_DISABLE);
+
+      const unsigned alpha = GFX_OP_MAP_ALPHA_STAGES
+       | (next_color_stage << MC_STAGE_SHIFT)
+       | MA_UPDATE_ARG1 | (MA_ARG_CURRENT_ALPHA << MA_ARG1_SHIFT)
+       | MA_UPDATE_ARG2 | (MA_ARG_CURRENT_ALPHA << MA_ARG2_SHIFT)
+       | MA_UPDATE_OP   | (MA_OP_ARG1);
+
+      set_color_stage( color, next_color_stage, imesa );
+      set_alpha_stage( alpha, next_alpha_stage, imesa );
+   }
+}