This patch implements these extensions:
 GL_ARB_texture_env_combine
 GL_EXT_texture_env_combine
 GL_ARB_texture_env_crossbar

G400 or better needed obviously.

My older texenv stuff is included with a slight modification. Since I
can't easily play with FCOL like I did before GL_BLEND has some more
restricions. Now both Cc and Ac must be either 0.0 or 1.0. I could
still add a Cc==Ac case which would work with other formats except
GL_INTENSITY.

Also I had to change GL_ALPHA and GL_LUMINANCE to use TW8AL format since
TW8A behaves like GL_INTENSITY and now it's possible to specify
SRC_ALPHA operand for GL_LUMINANCE and so on. I'm hoping Mesa will take
care of fillning the unused component with 0.0 or 1.0...

I made the mapping between OpenGL args and hw args flexible. This way
it doesn't matter in which order the user specifies the arguments.

Hw can't support dot3 stuff. Also RGB_SCALE and ALPHA_SCALE only work
fully with GL_MODULATE. GL_REPLACE can't support this at all the others
support only a value of 1.

So far I've only tested with an emboss bumpmapping sample from ATI. Good
news is that it looks ok :) It uses GL_MODULATE, GL_REPLACE and
GL_ADD_SIGNED. Are there any other good tests I could try?


PS.
I use Mesa embedded-2-branch as my working copy so I made the changes
to dri sources manually. Hopefully I got all of them...

-- 
Ville Syrjälä
[EMAIL PROTECTED]
http://www.sci.fi/~syrjala/
Index: Imakefile.inc
===================================================================
RCS file: /cvsroot/dri/xc/xc/lib/GL/mesa/src/drv/mga/Imakefile.inc,v
retrieving revision 1.6
diff -u -r1.6 Imakefile.inc
--- Imakefile.inc       30 Apr 2003 01:50:40 -0000      1.6
+++ Imakefile.inc       3 Aug 2003 16:07:23 -0000
@@ -43,6 +43,7 @@
                $(MESADRVMGABUILDDIR)mgatex.c \
                $(MESADRVMGABUILDDIR)mgatexmem.c \
                $(MESADRVMGABUILDDIR)mga_texstate.c \
+               $(MESADRVMGABUILDDIR)mga_texcombine.c \
                $(MESADRVMGABUILDDIR)mgatris.c \
                $(MESADRVMGABUILDDIR)mgavb.c \
                $(MESADRVMGABUILDDIR)mga_xmesa.c \
@@ -56,6 +57,7 @@
                $(MESADRVMGABUILDDIR)mgatex.o \
                $(MESADRVMGABUILDDIR)mgatexmem.o \
                $(MESADRVMGABUILDDIR)mga_texstate.o \
+               $(MESADRVMGABUILDDIR)mga_texcombine.o \
                $(MESADRVMGABUILDDIR)mgatris.o \
                $(MESADRVMGABUILDDIR)mgavb.o \
                $(MESADRVMGABUILDDIR)mga_xmesa.o
@@ -69,6 +71,7 @@
                $(MESADRVMGABUILDDIR)unshared/mgatex.o \
                $(MESADRVMGABUILDDIR)unshared/mgatexmem.o \
                $(MESADRVMGABUILDDIR)unshared/mga_texstate.o \
+               $(MESADRVMGABUILDDIR)unshared/mga_texcombine.o \
                $(MESADRVMGABUILDDIR)unshared/mgatris.o \
                $(MESADRVMGABUILDDIR)unshared/mgavb.o \
                $(MESADRVMGABUILDDIR)unshared/mga_xmesa.o
@@ -82,6 +85,7 @@
                $(MESADRVMGABUILDDIR)debugger/mgatex.o \
                $(MESADRVMGABUILDDIR)debugger/mgatexmem.o \
                $(MESADRVMGABUILDDIR)debugger/mga_texstate.o \
+               $(MESADRVMGABUILDDIR)debugger/mga_texcombine.o \
                $(MESADRVMGABUILDDIR)debugger/mgatris.o \
                $(MESADRVMGABUILDDIR)debugger/mgavb.o \
                $(MESADRVMGABUILDDIR)debugger/mga_xmesa.o
@@ -95,6 +99,7 @@
                $(MESADRVMGABUILDDIR)profiled/mgatex.o \
                $(MESADRVMGABUILDDIR)profiled/mgatexmem.o \
                $(MESADRVMGABUILDDIR)profiled/mga_texstate.o \
+               $(MESADRVMGABUILDDIR)profiled/mga_texcombine.o \
                $(MESADRVMGABUILDDIR)profiled/mgatris.o \
                $(MESADRVMGABUILDDIR)profiled/mgavb.o \
                $(MESADRVMGABUILDDIR)profiled/mga_xmesa.o
@@ -109,6 +114,7 @@
 LinkSourceFile(mgatex.c, $(MESADRVSRCDIR)/mga)
 LinkSourceFile(mgatexmem.c, $(MESADRVSRCDIR)/mga)
 LinkSourceFile(mga_texstate.c, $(MESADRVSRCDIR)/mga)
+LinkSourceFile(mga_texcombine.c, $(MESADRVSRCDIR)/mga)
 LinkSourceFile(mgatris.c, $(MESADRVSRCDIR)/mga)
 LinkSourceFile(mgavb.c, $(MESADRVSRCDIR)/mga)
 LinkSourceFile(mga_xmesa.c, $(MESADRVSRCDIR)/mga)
Index: mga_texstate.c
===================================================================
RCS file: /cvsroot/dri/xc/xc/lib/GL/mesa/src/drv/mga/mga_texstate.c,v
retrieving revision 1.9
diff -u -r1.9 mga_texstate.c
--- mga_texstate.c      25 Jul 2003 00:24:53 -0000      1.9
+++ mga_texstate.c      3 Aug 2003 16:07:23 -0000
@@ -52,6 +52,8 @@
     [MESA_FORMAT_RGB565]   = TMC_tformat_tw16 | TMC_takey_1 | TMC_tamask_0,
     [MESA_FORMAT_ARGB4444] = TMC_tformat_tw12 | TMC_takey_1 | TMC_tamask_0,
     [MESA_FORMAT_ARGB1555] = TMC_tformat_tw15 | TMC_takey_1 | TMC_tamask_0,
+    [MESA_FORMAT_AL88]     = TMC_tformat_tw8al | TMC_takey_1 | TMC_tamask_0,
+    [MESA_FORMAT_I8]       = TMC_tformat_tw8a | TMC_takey_1 | TMC_tamask_0,
     [MESA_FORMAT_CI8]      = TMC_tformat_tw8  | TMC_takey_1 | TMC_tamask_0,
     [MESA_FORMAT_YCBCR]     = TMC_tformat_tw422uyvy | TMC_takey_1 | TMC_tamask_0,
     [MESA_FORMAT_YCBCR_REV] = TMC_tformat_tw422 | TMC_takey_1 | TMC_tamask_0,
@@ -81,6 +83,8 @@
        case MESA_FORMAT_RGB565:   txformat = TMC_tformat_tw16; break;
        case MESA_FORMAT_ARGB4444: txformat = TMC_tformat_tw12; break;
        case MESA_FORMAT_ARGB1555: txformat = TMC_tformat_tw15; break;
+       case MESA_FORMAT_AL88:     txformat = TMC_tformat_tw8al; break;
+       case MESA_FORMAT_I8:       txformat = TMC_tformat_tw8a; break;
        case MESA_FORMAT_CI8:      txformat = TMC_tformat_tw8;  break;
         case MESA_FORMAT_YCBCR:    txformat  = TMC_tformat_tw422uyvy; break;
         case MESA_FORMAT_YCBCR_REV: txformat = TMC_tformat_tw422; break;
@@ -251,29 +255,160 @@
       (0),
 
       /* GL_REPLACE
+       * Cv = Cs
+       * Av = Af
        */
       (TD0_color_sel_arg1 |
        TD0_alpha_arg2_diffuse |
-       TD0_alpha_sel_arg2 ),
+       TD0_alpha_sel_arg2),
       
       /* GL_MODULATE
+       * Cv = Cf Cs
+       * Av = Af
        */
       (TD0_color_arg2_diffuse |
        TD0_color_sel_mul |
        TD0_alpha_arg2_diffuse |
-       TD0_alpha_sel_mul),
+       TD0_alpha_sel_arg2),
       
       /* GL_DECAL
+       * Cv = Cs
+       * Av = Af
        */
       (TD0_color_sel_arg1 |
        TD0_alpha_arg2_diffuse |
        TD0_alpha_sel_arg2),
       
-      /* GL_BLEND
+      /* GL_BLEND (Cc=0.0)
+       * Cv = Cf ( 1 - Cs )
+       * Av = Af
+       */
+      (TD0_color_arg1_inv_enable |
+       TD0_color_arg2_diffuse |
+       TD0_color_sel_mul |
+       TD0_alpha_arg2_diffuse |
+       TD0_alpha_sel_arg2),
+      
+      /* GL_ADD
+       * Cv = Cf + Cs
+       * Av = Af
+       */
+      (TD0_color_arg2_diffuse |
+       TD0_color_add_add |
+       TD0_color_sel_add |
+       TD0_alpha_arg2_diffuse |
+       TD0_alpha_sel_arg2),
+   },
+   
+   /* Unit 1:
+    */
+   {
+      /* Disable combiner stage
+       */
+      (0),
+       
+      /* GL_REPLACE
+       * Cv = Cs
+       * Av = Ap
+       */
+      (TD0_color_sel_arg1 |
+       TD0_alpha_arg2_prevstage |
+       TD0_alpha_sel_arg2),
+      
+      /* GL_MODULATE
+       * Cv = Cp Cs
+       * Av = Ap
+       */
+      (TD0_color_arg2_prevstage |
+       TD0_color_sel_mul |
+       TD0_alpha_arg2_prevstage |
+       TD0_alpha_sel_arg2),
+
+      /* GL_DECAL
+       * Cv = Cs
+       * Av = Ap
+       */
+      (TD0_color_sel_arg1 |
+       TD0_alpha_arg2_prevstage |
+       TD0_alpha_sel_arg2),
+      
+      /* GL_BLEND (Cc=0.0)
+       * Cv = Cp ( 1 - Cs )
+       * Av = Ap
+       */
+      (TD0_color_arg1_inv_enable |
+       TD0_color_arg2_prevstage |
+       TD0_color_sel_mul |
+       TD0_alpha_arg2_prevstage |
+       TD0_alpha_sel_arg2),
+      
+      /* GL_ADD
+       * Cv = Cp + Cs
+       * Av = Ap
+       */
+      (TD0_color_arg2_prevstage |
+       TD0_color_add_add |
+       TD0_color_sel_add |
+       TD0_alpha_arg2_prevstage |
+       TD0_alpha_sel_arg2),
+   },
+};
+
+static const GLuint g400_color_alpha_combine[][MGA_MAX_COMBFUNC] =
+{
+   /* Unit 0:
+    */
+   {
+      /* Disable combiner stage
        */
       (0),
+
+      /* GL_REPLACE
+       * Cv = Cs
+       * Av = As
+       */
+      (TD0_color_sel_arg1 |
+       TD0_alpha_sel_arg1),
+      
+      /* GL_MODULATE
+       * Cv = Cf Cs
+       * Av = Af As
+       */
+      (TD0_color_arg2_diffuse |
+       TD0_color_sel_mul |
+       TD0_alpha_arg2_diffuse |
+       TD0_alpha_sel_mul),
+      
+      /* GL_DECAL
+       * tmp = Cf ( 1 - As )
+       * Cv = tmp + Cs As
+       * Av = Af
+       */
+      (TD0_color_arg2_diffuse |
+       TD0_color_alpha_currtex |
+       TD0_color_alpha1inv_enable |
+       TD0_color_arg1mul_alpha1 |
+       TD0_color_blend_enable |
+       TD0_color_arg1add_mulout |
+       TD0_color_arg2add_mulout |
+       TD0_color_add_add |
+       TD0_color_sel_add |
+       TD0_alpha_arg2_diffuse |
+       TD0_alpha_sel_arg2),
+
+      /* GL_BLEND (Cc=0.0)
+       * Cv = Cf ( 1 - Cs )
+       * Av = Af As
+       */
+      (TD0_color_arg1_inv_enable |
+       TD0_color_arg2_diffuse |
+       TD0_color_sel_mul |
+       TD0_alpha_arg2_diffuse |
+       TD0_alpha_sel_mul),
       
       /* GL_ADD
+       * Cv = Cf + Cs
+       * Av = Af As
        */
       (TD0_color_arg2_diffuse |
        TD0_color_add_add |
@@ -290,33 +425,53 @@
       (0),
        
       /* GL_REPLACE
+       * Cv = Cs
+       * Av = As
        */
       (TD0_color_sel_arg1 |
-       TD0_alpha_arg2_diffuse |
-       TD0_alpha_sel_arg2 ),
+       TD0_alpha_sel_arg1),
       
       /* GL_MODULATE
+       * Cv = Cp Cs
+       * Av = Ap As
        */
       (TD0_color_arg2_prevstage |
-       TD0_color_alpha_prevstage |
        TD0_color_sel_mul |
        TD0_alpha_arg2_prevstage |
        TD0_alpha_sel_mul),
 
       /* GL_DECAL
+       * tmp = Cp ( 1 - As )
+       * Cv = tmp + Cs As
+       * Av = Ap
        */
-      (TD0_color_sel_arg1 |
+      (TD0_color_arg2_prevstage |
+       TD0_color_alpha_currtex |
+       TD0_color_alpha1inv_enable |
+       TD0_color_arg1mul_alpha1 |
+       TD0_color_blend_enable |
+       TD0_color_arg1add_mulout |
+       TD0_color_arg2add_mulout |
+       TD0_color_add_add |
+       TD0_color_sel_add |
        TD0_alpha_arg2_prevstage |
-       TD0_alpha_sel_arg2 ),
+       TD0_alpha_sel_arg2),
       
-      /* GL_BLEND
+      /* GL_BLEND (Cc=0.0)
+       * Cv = Cp ( 1 - Cs )
+       * Av = Ap As
        */
-      (0),
+      (TD0_color_arg1_inv_enable |
+       TD0_color_arg2_prevstage |
+       TD0_color_sel_mul |
+       TD0_alpha_arg2_prevstage |
+       TD0_alpha_sel_mul),
       
       /* GL_ADD
+       * Cv = Cp + Cs
+       * Av = Ap As
        */
       (TD0_color_arg2_prevstage |
-       TD0_color_alpha_prevstage |
        TD0_color_add_add |
        TD0_color_sel_add |
        TD0_alpha_arg2_prevstage |
@@ -334,20 +489,25 @@
       (0),
 
       /* GL_REPLACE
+       * Cv = Cf
+       * Av = As
        */
-      (TD0_color_sel_arg2 |
-       TD0_color_arg2_diffuse |
-       TD0_alpha_sel_arg1 ),
+      (TD0_color_arg2_diffuse |
+       TD0_color_sel_arg2 |
+       TD0_alpha_sel_arg1),
       
       /* GL_MODULATE
-       * FIXME: Is this correct?
+       * Cv = Cf
+       * Av = Af As
        */
       (TD0_color_arg2_diffuse |
-       TD0_color_sel_mul |
+       TD0_color_sel_arg2 |
        TD0_alpha_arg2_diffuse |
        TD0_alpha_sel_mul),
 
-      /* GL_DECAL
+      /* GL_DECAL (undefined)
+       * Cv = Cf
+       * Av = Af
        */
       (TD0_color_arg2_diffuse |
        TD0_color_sel_arg2 |
@@ -355,16 +515,20 @@
        TD0_alpha_sel_arg2),
 
       /* GL_BLEND
+       * Cv = Cf
+       * Av = Af As
        */
       (TD0_color_arg2_diffuse |
-       TD0_color_sel_mul |
+       TD0_color_sel_arg2 |
        TD0_alpha_arg2_diffuse |
        TD0_alpha_sel_mul),
 
       /* GL_ADD
+       * Cv = Cf
+       * Av = Af As
        */
       (TD0_color_arg2_diffuse |
-       TD0_color_sel_mul |
+       TD0_color_sel_arg2 |
        TD0_alpha_arg2_diffuse |
        TD0_alpha_sel_mul),
    },
@@ -377,21 +541,25 @@
       (0),
 
       /* GL_REPLACE
+       * Cv = Cp
+       * Av = As
        */
-      (TD0_color_sel_arg2 |
-       TD0_color_arg2_diffuse |
-       TD0_alpha_sel_arg1 ),
+      (TD0_color_arg2_prevstage |
+       TD0_color_sel_arg2 |
+       TD0_alpha_sel_arg1),
       
       /* GL_MODULATE
-       * FIXME: Is this correct?
+       * Cv = Cp
+       * Av = Ap As
        */
       (TD0_color_arg2_prevstage |
-       TD0_color_alpha_prevstage |
-       TD0_color_sel_mul |
+       TD0_color_sel_arg2 |
        TD0_alpha_arg2_prevstage |
        TD0_alpha_sel_mul),
 
-      /* GL_DECAL
+      /* GL_DECAL (undefined)
+       * Cv = Cp
+       * Av = Ap
        */
       (TD0_color_arg2_prevstage |
        TD0_color_sel_arg2 |
@@ -399,16 +567,20 @@
        TD0_alpha_sel_arg2),
 
       /* GL_BLEND
+       * Cv = Cp
+       * Av = Ap As
        */
-      (TD0_color_arg2_diffuse |
-       TD0_color_sel_mul |
-       TD0_alpha_arg2_diffuse |
+      (TD0_color_arg2_prevstage |
+       TD0_color_sel_arg2 |
+       TD0_alpha_arg2_prevstage |
        TD0_alpha_sel_mul),
 
       /* GL_ADD
+       * Cv = Cp
+       * Av = Ap As
        */
       (TD0_color_arg2_prevstage |
-       TD0_color_sel_mul |
+       TD0_color_sel_arg2 |
        TD0_alpha_arg2_prevstage |
        TD0_alpha_sel_mul),
    },
@@ -421,6 +593,7 @@
    const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
    const struct gl_texture_object *tObj = texUnit->_Current;
    GLuint *reg = ((GLuint *)&mmesa->setup.tdualstage0 + unit);
+   mgaTextureObjectPtr t;
    GLenum format;
 
    if ( tObj != ctx->Texture.Unit[source].Current2D || !tObj ) 
@@ -428,136 +601,226 @@
 
    format = tObj->Image[tObj->BaseLevel]->Format;
 
+   t = (mgaTextureObjectPtr) tObj->DriverData;
+
    switch (ctx->Texture.Unit[source].EnvMode) {
    case GL_REPLACE:
-      if (format == GL_RGB || format == GL_LUMINANCE) {
-        *reg = g400_color_combine[unit][MGA_REPLACE];
-      }
-      else if (format == GL_ALPHA) {
+      if (format == GL_ALPHA) {
          *reg = g400_alpha_combine[unit][MGA_REPLACE];
-      }
-      else {
-         *reg = (TD0_color_sel_arg1 |
-                 TD0_alpha_sel_arg1 );
+      } else if (format == GL_RGB || format == GL_LUMINANCE) {
+         *reg = g400_color_combine[unit][MGA_REPLACE];
+      } else {
+         *reg = g400_color_alpha_combine[unit][MGA_REPLACE];
       }
       break;
 
    case GL_MODULATE:
-      *reg = g400_color_combine[unit][MGA_MODULATE];
+      if (format == GL_ALPHA) {
+         *reg = g400_alpha_combine[unit][MGA_MODULATE];
+      } else if (format == GL_RGB || format == GL_LUMINANCE) {
+         *reg = g400_color_combine[unit][MGA_MODULATE];
+      } else {
+         *reg = g400_color_alpha_combine[unit][MGA_MODULATE];
+      }
       break;
+
    case GL_DECAL:
       if (format == GL_RGB) {
-        *reg = g400_color_combine[unit][MGA_DECAL];
+         *reg = g400_color_combine[unit][MGA_DECAL];
+      } else if (format == GL_RGBA) {
+         *reg = g400_color_alpha_combine[unit][MGA_DECAL];
+         if (ctx->Texture._EnabledUnits != 0x03) {
+            /* Linear blending mode needs dual texturing enabled */
+            *(reg+1) = (TD0_color_arg2_prevstage |
+                        TD0_color_sel_arg2 |
+                        TD0_alpha_arg2_prevstage |
+                        TD0_alpha_sel_arg2);
+            mmesa->dualtex_env = GL_TRUE;
+         }
+      } else {
+         /* Undefined */
+         *reg = g400_alpha_combine[unit][MGA_DECAL];
       }
-      else if ( format == GL_RGBA ) {
-#if 0
+      break;
+
+   case GL_ADD:
+      if (format == GL_ALPHA) {
+         *reg = g400_alpha_combine[unit][MGA_ADD];
+      } else if (format == GL_RGB || format == GL_LUMINANCE) {
+         *reg = g400_color_combine[unit][MGA_ADD];
+      } else if (format == GL_RGBA || format == GL_LUMINANCE_ALPHA) {
+         *reg = g400_color_alpha_combine[unit][MGA_ADD];
+      } else if (format == GL_INTENSITY) {
+         /* Cv = Cf + Cs
+          * Av = Af + As
+          */
          if (unit == 0) {
-            /* this doesn't work */
             *reg = (TD0_color_arg2_diffuse |
-                    TD0_color_alpha_currtex |
-                    TD0_color_alpha2inv_enable |
-                    TD0_color_arg2mul_alpha2 |
-                    TD0_color_arg1mul_alpha1 |
-                    TD0_color_blend_enable |
-                    TD0_color_arg1add_mulout |
-                    TD0_color_arg2add_mulout |
                     TD0_color_add_add |
-                    TD0_color_sel_mul |
+                    TD0_color_sel_add |
                     TD0_alpha_arg2_diffuse |
-                    TD0_alpha_sel_arg2 );
-         }
-         else {
+                    TD0_alpha_add_enable |
+                    TD0_alpha_sel_add);
+         } else {
             *reg = (TD0_color_arg2_prevstage |
-                    TD0_color_alpha_currtex |
-                    TD0_color_alpha2inv_enable |
-                    TD0_color_arg2mul_alpha2 |
-                    TD0_color_arg1mul_alpha1 |
                     TD0_color_add_add |
                     TD0_color_sel_add |
                     TD0_alpha_arg2_prevstage |
-                    TD0_alpha_sel_arg2 );
+                    TD0_alpha_add_enable |
+                    TD0_alpha_sel_add);
          }
-#else
-         /* s/w fallback, pretty sure we can't do in h/w */
-        FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
-        if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK )
-           fprintf( stderr, "FALLBACK: GL_DECAL RGBA texture, unit=%d\n",
-                    unit );
-#endif
-      }
-      else {
-       *reg = g400_alpha_combine[unit][MGA_DECAL];
       }
       break;
 
-   case GL_ADD:
-     if (format == GL_INTENSITY) {
-       if (unit == 0) {
-          *reg = ( TD0_color_arg2_diffuse |
-                  TD0_color_add_add |
-                  TD0_color_sel_add |
-                  TD0_alpha_arg2_diffuse |
-                  TD0_alpha_add_enable |
-                  TD0_alpha_sel_add);
-       }
-       else {
-          *reg = ( TD0_color_arg2_prevstage |
-                  TD0_color_add_add |
-                  TD0_color_sel_add |
-                  TD0_alpha_arg2_prevstage |
-                  TD0_alpha_add_enable |
-                  TD0_alpha_sel_add);
-       }
-     }      
-     else if (format == GL_ALPHA) {
-       *reg = g400_alpha_combine[unit][MGA_ADD];
-     }
-     else {
-       *reg = g400_color_combine[unit][MGA_ADD];
-     }
-     break;
-
    case GL_BLEND:
       if (format == GL_ALPHA) {
-        *reg = g400_alpha_combine[unit][MGA_BLEND];
-      }
-      else {
-        FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
-        if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK )
-           fprintf( stderr, "FALLBACK: GL_BLEND envcolor=0x%08x\n",
-                    mmesa->envcolor );
-
-         /* Do singletexture GL_BLEND with 'all ones' env-color
-          * by using both texture units.  Multitexture gl_blend
-          * is a fallback.
-          */
-         if (unit == 0) {
-            /* Part 1: R1 = Rf ( 1 - Rt )
-             *         A1 = Af At
-             */
-            *reg = ( TD0_color_arg2_diffuse |
-                     TD0_color_arg1_inv_enable |
-                     TD0_color_sel_mul |
-                     TD0_alpha_arg2_diffuse |
-                     TD0_alpha_sel_arg1);
+         *reg = g400_alpha_combine[unit][MGA_BLEND];
+      } else {
+         if (mmesa->blend_flags & MGA_BLEND_RGB_ZERO) {
+            if (format == GL_RGB || format == GL_LUMINANCE) {
+               *reg = g400_color_combine[unit][MGA_BLEND];
+            } else if (format == GL_RGBA || format == GL_LUMINANCE_ALPHA) {
+               *reg = g400_color_alpha_combine[unit][MGA_BLEND];
+            } else if (format == GL_INTENSITY) {
+               if (mmesa->blend_flags & MGA_BLEND_ALPHA_ZERO) {
+                  /* Cv = Cf ( 1 - Cs )
+                   * Av = Af ( 1 - As )
+                   */
+                  if (unit == 0) {
+                     *reg = (TD0_color_arg1_inv_enable |
+                             TD0_color_arg2_diffuse |
+                             TD0_color_sel_mul |
+                             TD0_alpha_arg1_inv_enable |
+                             TD0_alpha_arg2_diffuse |
+                             TD0_alpha_sel_mul);
+                  } else {
+                     *reg = (TD0_color_arg1_inv_enable |
+                             TD0_color_arg2_prevstage |
+                             TD0_color_sel_mul |
+                             TD0_alpha_arg1_inv_enable |
+                             TD0_alpha_arg2_prevstage |
+                             TD0_alpha_sel_mul);
+                  }
+               } else if (mmesa->blend_flags & MGA_BLEND_ALPHA_ONE &&
+                          ctx->Texture._EnabledUnits != 0x03) {
+                  /* C1 = Cf ( 1 - Cs )
+                   * A1 = Af ( 1 - As )
+                   */
+                  *reg = (TD0_color_arg1_inv_enable |
+                          TD0_color_arg2_diffuse |
+                          TD0_color_sel_mul |
+                          TD0_alpha_arg1_inv_enable |
+                          TD0_alpha_arg2_diffuse |
+                          TD0_alpha_sel_mul);
+                  /* Cv = C1
+                   * Av = A1 + As
+                   */
+                  *(reg+1) = (TD0_color_arg2_prevstage |
+                              TD0_color_sel_arg2 |
+                              TD0_alpha_arg2_prevstage |
+                              TD0_alpha_add_enable |
+                              TD0_alpha_sel_add);
+                  mmesa->dualtex_env = GL_TRUE;
+               } else {
+                  t->texenv_fallback = GL_TRUE;
+               }
+            }
+         } else if (mmesa->blend_flags & MGA_BLEND_RGB_ONE &&
+                    ctx->Texture._EnabledUnits != 0x03) {
+            if (format == GL_RGB || format == GL_LUMINANCE) {
+                  /* C1 = Cf ( 1 - Cs )
+                   * A1 = Af
+                   */
+                  *reg = (TD0_color_arg1_inv_enable |
+                          TD0_color_arg2_diffuse |
+                          TD0_color_sel_mul |
+                          TD0_alpha_arg2_diffuse |
+                          TD0_alpha_sel_arg2);
+                  /* Cv = C1 + Cs
+                   * Av = A1
+                   */
+                  *(reg+1) = (TD0_color_arg2_prevstage |
+                              TD0_color_add_add |
+                              TD0_color_sel_add |
+                              TD0_alpha_arg2_prevstage |
+                              TD0_alpha_sel_arg2);
+                  mmesa->dualtex_env = GL_TRUE;
+            } else if (format == GL_RGBA || format == GL_LUMINANCE_ALPHA) {
+                  /* C1 = Cf ( 1 - Cs )
+                   * A1 = Af As
+                   */
+                  *reg = (TD0_color_arg1_inv_enable |
+                          TD0_color_arg2_diffuse |
+                          TD0_color_sel_mul |
+                          TD0_alpha_arg2_diffuse |
+                          TD0_alpha_sel_mul);
+                  /* Cv = C1 + Cs
+                   * Av = A1
+                   */
+                  *(reg+1) = (TD0_color_arg2_prevstage |
+                              TD0_color_add_add |
+                              TD0_color_sel_add |
+                              TD0_alpha_arg2_prevstage |
+                              TD0_alpha_sel_arg2);
+                  mmesa->dualtex_env = GL_TRUE;
+            } else if (format == GL_INTENSITY) {
+               if (mmesa->blend_flags & MGA_BLEND_ALPHA_ZERO) {
+                  /* C1 = Cf ( 1 - Cs )
+                   * A1 = Af ( 1 - As )
+                   */
+                  *reg = (TD0_color_arg1_inv_enable |
+                          TD0_color_arg2_diffuse |
+                          TD0_color_sel_mul |
+                          TD0_alpha_arg1_inv_enable |
+                          TD0_alpha_arg2_diffuse |
+                          TD0_alpha_sel_mul);
+                  /* Cv = C1 + Cs
+                   * Av = A1
+                   */
+                  *(reg+1) = (TD0_color_arg2_prevstage |
+                              TD0_color_add_add |
+                              TD0_color_sel_add |
+                              TD0_alpha_arg2_prevstage |
+                              TD0_alpha_sel_arg2);
+                  mmesa->dualtex_env = GL_TRUE;
+               } else if (mmesa->blend_flags & MGA_BLEND_ALPHA_ONE) {
+                  /* C1 = Cf ( 1 - Cs )
+                   * A1 = Af ( 1 - As )
+                   */
+                  *reg = (TD0_color_arg1_inv_enable |
+                          TD0_color_arg2_diffuse |
+                          TD0_color_sel_mul |
+                          TD0_alpha_arg1_inv_enable |
+                          TD0_alpha_arg2_diffuse |
+                          TD0_alpha_sel_mul);
+                  /* Cv = C1 + Cs
+                   * Av = A1 + As
+                   */
+                  *(reg+1) = (TD0_color_arg2_prevstage |
+                              TD0_color_add_add |
+                              TD0_color_sel_add |
+                              TD0_alpha_arg2_prevstage |
+                              TD0_alpha_add_enable |
+                              TD0_alpha_sel_add);
+                  mmesa->dualtex_env = GL_TRUE;
+               } else {
+                  t->texenv_fallback = GL_TRUE;
+               }
+            }
          } else {
-            /* Part 2: R2 = R1 + Rt
-             *         A2 = A1
-             */
-            *reg = ( TD0_color_arg2_prevstage |
-                     TD0_color_add_add |
-                     TD0_color_sel_add |
-                     TD0_alpha_arg2_prevstage |
-                     TD0_alpha_sel_arg2);
+            t->texenv_fallback = GL_TRUE;
          }
       }
       break;
+   case GL_COMBINE_EXT:
+      if (!mgaUpdateTextureEnvCombine(ctx, unit))
+         t->texenv_fallback = GL_TRUE;
+      break;
    default:
       break;
    }
 }
 
-
 static void disable_tex( GLcontext *ctx, int unit )
 {
    mgaContextPtr mmesa = MGA_CONTEXT( ctx );
@@ -573,7 +836,7 @@
       mmesa->CurrentTexObj[unit] = NULL;
    }
 
-   if ( unit != 0 ) {
+   if ( unit != 0 && !mmesa->dualtex_env ) {
       mmesa->setup.tdualstage1 = mmesa->setup.tdualstage0;
    }
 
@@ -649,6 +912,14 @@
       t->setup.texctl2 |= TMC_dualtex_enable;
    }
 
+   t->texenv_fallback = GL_FALSE;
+
+   /* Set this before mgaUpdateTextureEnvG400() since
+    * GL_ARB_texture_env_crossbar may have to disable texturing.
+    */
+   mmesa->setup.dwgctl &= DC_opcod_MASK;
+   mmesa->setup.dwgctl |= DC_opcod_texture_trap;
+
    /* FIXME: The Radeon has some cached state so that it can avoid calling
     * FIXME: UpdateTextureEnv in some cases.  Is that possible here?
     */
@@ -680,13 +951,10 @@
 
       mgaUpdateTextureEnvG200( ctx, unit );
    }
-
-   mmesa->setup.dwgctl &= DC_opcod_MASK;
-   mmesa->setup.dwgctl |= DC_opcod_texture_trap;
    mmesa->dirty |= MGA_UPLOAD_CONTEXT | (MGA_UPLOAD_TEX0 << unit);
 
    FALLBACK( ctx, MGA_FALLBACK_BORDER_MODE, t->border_fallback );
-   return !t->border_fallback;
+   return !t->border_fallback && !t->texenv_fallback;
 }
 
 
@@ -718,6 +986,7 @@
    GLboolean ok;
    unsigned  i;
 
+   mmesa->dualtex_env = GL_FALSE;
 
    /* This works around a quirk with the MGA hardware.  If only OpenGL 
     * TEXTURE1 is enabled, then the hardware TEXTURE0 must be used.  The
Index: mga_xmesa.c
===================================================================
RCS file: /cvsroot/dri/xc/xc/lib/GL/mesa/src/drv/mga/mga_xmesa.c,v
retrieving revision 1.54
diff -u -r1.54 mga_xmesa.c
--- mga_xmesa.c 25 Jun 2003 17:13:46 -0000      1.54
+++ mga_xmesa.c 3 Aug 2003 16:07:25 -0000
@@ -259,6 +259,9 @@
    "GL_ARB_multitexture",
    "GL_ARB_texture_env_add",
    "GL_EXT_texture_env_add",
+   "GL_ARB_texture_env_combine",
+   "GL_EXT_texture_env_combine",
+   "GL_ARB_texture_env_crossbar",
    "GL_EXT_texture_edge_clamp",
    "GL_SGIS_texture_edge_clamp",
 #if defined (MESA_packed_depth_stencil)
Index: mgacontext.h
===================================================================
RCS file: /cvsroot/dri/xc/xc/lib/GL/mesa/src/drv/mga/mgacontext.h,v
retrieving revision 1.26
diff -u -r1.26 mgacontext.h
--- mgacontext.h        22 Jul 2003 04:54:31 -0000      1.26
+++ mgacontext.h        3 Aug 2003 16:07:25 -0000
@@ -78,10 +78,12 @@
 
 
 
-/* Reasons why the GL_BLEND fallback mightn't work:
+/* GL_BLEND has some limitations
  */
-#define MGA_BLEND_ENV_COLOR 0x1
-#define MGA_BLEND_MULTITEX  0x2
+#define MGA_BLEND_RGB_ZERO   0x1
+#define MGA_BLEND_RGB_ONE    0x2
+#define MGA_BLEND_ALPHA_ZERO 0x4
+#define MGA_BLEND_ALPHA_ONE  0x8
 
 struct mga_texture_object_s;
 struct mga_screen_private_s;
@@ -148,6 +150,10 @@
     * to fallback for GL_CLAMP_TO_BORDER.
     */
    GLboolean          border_fallback;
+   /* Depending on multitxturing and environment color
+    * GL_BLEND may have to be a software fallback.
+    */
+   GLboolean texenv_fallback;
 } mgaTextureObject_t;
 
 struct mga_hw_state {
@@ -201,10 +207,11 @@
    struct gl_client_array UbyteColor;
    struct gl_client_array UbyteSecondaryColor;
 
-   /* Support for limited GL_BLEND fallback
+   /* Support for GL_DECAL and GL_BLEND
     */
    unsigned int blend_flags;
    unsigned int envcolor;
+   GLboolean dualtex_env;
 
    /* Rasterization state 
     */
Index: mgastate.c
===================================================================
RCS file: /cvsroot/dri/xc/xc/lib/GL/mesa/src/drv/mga/mgastate.c,v
retrieving revision 1.41
diff -u -r1.41 mgastate.c
--- mgastate.c  23 Jul 2003 13:40:07 -0000      1.41
+++ mgastate.c  3 Aug 2003 16:07:26 -0000
@@ -1053,8 +1053,13 @@
             sizeof(sarea->TexState[1]));
    }
 
-   if ( (sarea->TexState[0].texctl2 & TMC_borderen_MASK) !=
-       (sarea->TexState[1].texctl2 & TMC_borderen_MASK) ) {
+   if (mmesa->dualtex_env) {
+      sarea->TexState[0].texctl2 |= TMC_dualtex_enable;
+      memcpy( &sarea->TexState[1], &sarea->TexState[0],
+             sizeof(sarea->TexState[0]) );
+      mmesa->dirty |= MGA_UPLOAD_TEX1|MGA_UPLOAD_TEX0;
+   } else if ( (sarea->TexState[0].texctl2 & TMC_borderen_MASK) !=
+               (sarea->TexState[1].texctl2 & TMC_borderen_MASK) ) {
       const int borderen = sarea->TexState[1].texctl2 & ~TMC_borderen_MASK;
 
       memcpy( &sarea->TexState[1], &sarea->TexState[0],
@@ -1229,6 +1234,10 @@
    mmesa->setup.tdualstage1 = 0;
    mmesa->setup.fcol = 0;
    mmesa->dirty |= MGA_UPLOAD_CONTEXT;
+
+   mmesa->envcolor = 0;
+   mmesa->blend_flags = MGA_BLEND_RGB_ZERO | MGA_BLEND_ALPHA_ZERO;
+   mmesa->dualtex_env = GL_FALSE;
 }
 
 
Index: mgatex.c
===================================================================
RCS file: /cvsroot/dri/xc/xc/lib/GL/mesa/src/drv/mga/mgatex.c,v
retrieving revision 1.49
diff -u -r1.49 mgatex.c
--- mgatex.c    25 Jul 2003 07:42:21 -0000      1.49
+++ mgatex.c    3 Aug 2003 16:07:27 -0000
@@ -220,7 +220,7 @@
    case GL_ALPHA16:
    case GL_COMPRESSED_ALPHA:
       /* FIXME: This will report incorrect component sizes... */
-      return &_mesa_texformat_argb4444;
+      return MGA_IS_G400(mmesa) ? &_mesa_texformat_al88 : &_mesa_texformat_argb4444;
 
    case 1:
    case GL_LUMINANCE:
@@ -230,7 +230,8 @@
    case GL_LUMINANCE16:
    case GL_COMPRESSED_LUMINANCE:
       /* FIXME: This will report incorrect component sizes... */
-      return &_mesa_texformat_rgb565;
+      return 
+      return MGA_IS_G400(mmesa) ? &_mesa_texformat_al88 : &_mesa_texformat_rgb565;
 
    case 2:
    case GL_LUMINANCE_ALPHA:
@@ -242,7 +243,7 @@
    case GL_LUMINANCE16_ALPHA16:
    case GL_COMPRESSED_LUMINANCE_ALPHA:
       /* FIXME: This will report incorrect component sizes... */
-      return &_mesa_texformat_argb4444;
+      return MGA_IS_G400(mmesa) ? &_mesa_texformat_al88 : &_mesa_texformat_argb4444;
 
    case GL_INTENSITY:
    case GL_INTENSITY4:
@@ -251,7 +252,7 @@
    case GL_INTENSITY16:
    case GL_COMPRESSED_INTENSITY:
       /* FIXME: This will report incorrect component sizes... */
-      return &_mesa_texformat_argb4444;
+      return MGA_IS_G400(mmesa) ? &_mesa_texformat_i8 : &_mesa_texformat_argb4444;
 
    case GL_YCBCR_MESA:
       if (MGA_IS_G400(mmesa) &&
@@ -331,27 +332,28 @@
    switch( pname ) {
    case GL_TEXTURE_ENV_COLOR: {
       GLubyte c[4];
-      GLuint envColor;
 
       UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
-      envColor = mgaPackColor( mmesa->mgaScreen->cpp, c[0], c[1], c[2], c[3] );
       mmesa->envcolor = PACK_COLOR_8888( c[3], c[0], c[1], c[2] );
 
-      if (mmesa->setup.fcol != envColor) {
+      if (mmesa->setup.fcol != mmesa->envcolor) {
         FLUSH_BATCH(mmesa);
-        mmesa->setup.fcol = envColor;
+        mmesa->setup.fcol = mmesa->envcolor;
         mmesa->dirty |= MGA_UPLOAD_CONTEXT;
 
-        mmesa->blend_flags &= ~MGA_BLEND_ENV_COLOR;
+        mmesa->blend_flags = 0;
 
-        /* Actually just require all four components to be
-         * equal.  This permits a single-pass GL_BLEND.
-         *
-         * More complex multitexture/multipass fallbacks
-         * for blend can be done later.
-         */
-        if (mmesa->envcolor != 0x0 && mmesa->envcolor != 0xffffffff)
-           mmesa->blend_flags |= MGA_BLEND_ENV_COLOR;
+         if ((mmesa->envcolor & 0xffffff) == 0x0) {
+            mmesa->blend_flags |= MGA_BLEND_RGB_ZERO;
+         } else if ((mmesa->envcolor & 0xffffff) == 0xffffff) {
+            mmesa->blend_flags |= MGA_BLEND_RGB_ONE;
+         }
+
+        if ((mmesa->envcolor >> 24) == 0x0) {
+            mmesa->blend_flags |= MGA_BLEND_ALPHA_ZERO;
+         } else if ((mmesa->envcolor >> 24) == 0xff) {
+            mmesa->blend_flags |= MGA_BLEND_ALPHA_ONE;
+         }
       }
       break;
    }
Index: mgatex.h
===================================================================
RCS file: /cvsroot/dri/xc/xc/lib/GL/mesa/src/drv/mga/mgatex.h,v
retrieving revision 1.13
diff -u -r1.13 mgatex.h
--- mgatex.h    30 Apr 2003 01:50:43 -0000      1.13
+++ mgatex.h    3 Aug 2003 16:07:27 -0000
@@ -46,4 +46,6 @@
 
 void mgaDDInitTextureFuncs( GLcontext *ctx );
 
+GLboolean mgaUpdateTextureEnvCombine( GLcontext *ctx, int unit );
+
 #endif
#include "glheader.h"
#include "imports.h"
#include "colormac.h"
#include "context.h"
#include "enums.h"
#include "macros.h"
#include "mmath.h"
#include "texformat.h"

#include "mga_xmesa.h"
#include "mgastate.h"
#include "mgaioctl.h"
#include "mgatex.h"
#include "mgaregs.h"

/* GL_EXT_texture_env_combine support
 */

#define ARG_DISABLE 0xffffffff
#define MGA_ARG1  0
#define MGA_ARG2  1
#define MGA_ALPHA 2

GLboolean mgaUpdateTextureEnvCombine( GLcontext *ctx, int unit )
{
   mgaContextPtr mmesa = MGA_CONTEXT(ctx);
   const int source = mmesa->tmu_source[unit];
   const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
   GLuint *reg = ((GLuint *)&mmesa->setup.tdualstage0 + unit);
   GLuint numColorArgs = 0, numAlphaArgs = 0;
   GLuint arg1[3], arg2[3], alpha[3];
   int args[3];
   int i;

   switch (texUnit->CombineModeRGB) {
   case GL_REPLACE:
      numColorArgs = 1;
      break;
   case GL_MODULATE:
   case GL_ADD:
   case GL_ADD_SIGNED:
   case GL_SUBTRACT:
      numColorArgs = 2;
      break;
   case GL_INTERPOLATE:
      numColorArgs = 3;
      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;
   default:
      return GL_FALSE;
   }

   /* Start fresh :) */
   *reg = 0;

   /* COLOR */
   for (i = 0; i < 3; i++) {
      arg1[i] = 0;
      arg2[i] = 0;
      alpha[i] = 0;
   }

   for (i = 0;i < numColorArgs; i++) {
      switch (texUnit->CombineSourceRGB[i]) {
      case GL_TEXTURE:
         arg1[i] |= 0;
         arg2[i] |= ARG_DISABLE;
         alpha[i] |= TD0_color_alpha_currtex;
         break;
      case GL_TEXTURE0:
         if (source == 0) {
            arg1[i] |= 0;
            arg2[i] |= ARG_DISABLE;
            alpha[i] |= TD0_color_alpha_currtex;
         } else {
            if (ctx->Texture._EnabledUnits != 0x03) {
               /* disable texturing */
               mmesa->setup.dwgctl &= DC_opcod_MASK;
               mmesa->setup.dwgctl |= DC_opcod_trap;
               mmesa->hw.alpha_sel = AC_alphasel_diffused;
               /* return GL_TRUE since we don't need a fallback */
               return GL_TRUE;
            }
            arg1[i] |= ARG_DISABLE;
            arg2[i] |= ARG_DISABLE;
            alpha[i] |= TD0_color_alpha_prevtex;
         }
         break;
      case GL_TEXTURE1:
         if (source == 0) {
            if (ctx->Texture._EnabledUnits != 0x03) {
               /* disable texturing */
               mmesa->setup.dwgctl &= DC_opcod_MASK;
               mmesa->setup.dwgctl |= DC_opcod_trap;
               mmesa->hw.alpha_sel = AC_alphasel_diffused;
               /* return GL_TRUE since we don't need a fallback */
               return GL_TRUE;
            }
            arg1[i] |= ARG_DISABLE;
            /* G400 specs.(TDUALSTAGE0) */
            arg2[i] |= TD0_color_arg2_prevstage;
            alpha[i] |= TD0_color_alpha_prevstage;
         } else {
            arg1[i] |= 0;
            arg2[i] |= ARG_DISABLE;
            alpha[i] |= TD0_color_alpha_currtex;
         }
         break;
      case GL_CONSTANT:
         arg1[i] |= ARG_DISABLE;
         arg2[i] |= TD0_color_arg2_fcol;
         alpha[i] |= TD0_color_alpha_fcol;
         break;
      case GL_PRIMARY_COLOR:
         arg1[i] |= ARG_DISABLE;
         /* G400 specs.(TDUALSTAGE1) */
         if (unit == 0 || (mmesa->setup.tdualstage0 &
                           ((TD0_color_sel_mul & TD0_color_sel_add) |
                            (TD0_alpha_sel_mul & TD0_alpha_sel_add)))) {
            arg2[i] |= TD0_color_arg2_diffuse;
            alpha[i] |= TD0_color_alpha_diffuse;
         } else {
            arg2[i] |= ARG_DISABLE;
            alpha[i] |= ARG_DISABLE;
         }
         break;
      case GL_PREVIOUS:
         arg1[i] |= ARG_DISABLE;
         if (unit == 0) {
            arg2[i] |= TD0_color_arg2_diffuse;
            alpha[i] |= TD0_color_alpha_diffuse;
         } else {
            arg2[i] |= TD0_color_arg2_prevstage;
            alpha[i] |= TD0_color_alpha_prevstage;
         }
         break;
      }

      switch (texUnit->CombineOperandRGB[i]) {
      case GL_SRC_COLOR:
         arg1[i] |= 0;
         arg2[i] |= 0;
         alpha[i] |= ARG_DISABLE;
         break;
      case GL_ONE_MINUS_SRC_COLOR:
         arg1[i] |= TD0_color_arg1_inv_enable;
         arg2[i] |= TD0_color_arg2_inv_enable;
         alpha[i] |= ARG_DISABLE;
         break;
      case GL_SRC_ALPHA:
         arg1[i] |= TD0_color_arg1_replicatealpha_enable;
         arg2[i] |= TD0_color_arg2_replicatealpha_enable;
         alpha[i] |= 0;
         break;
      case GL_ONE_MINUS_SRC_ALPHA:
         arg1[i] |= (TD0_color_arg1_replicatealpha_enable |
                     TD0_color_arg1_inv_enable);
         arg2[i] |= (TD0_color_arg2_replicatealpha_enable |
                     TD0_color_arg2_inv_enable);
         alpha[i] |= (TD0_color_alpha1inv_enable |
                      TD0_color_alpha2inv_enable);
         break;
      }
   }

   /* Find working combo of arg1, arg2 and alpha.
    *
    * Keep the Arg0 == alpha cases last since there's
    * no way to get alpha out by itself (GL_REPLACE).
    *
    * Keep the Arg2 == alpha cases first because only alpha has the
    * capabilities to function as Arg2 (GL_INTERPOLATE).
    * Also we can't get alpha to the adder so keep it away from Arg0 and Arg1
    * for as long as possible (GL_ADD,GL_ADD_SIGNED,GL_SUBTRACT).
    */
   if ((arg1[0] | arg2[1] | alpha[2]) != ARG_DISABLE) {
      *reg |= arg1[0] | arg2[1] | alpha[2];
      args[0] = MGA_ARG1; args[1] = MGA_ARG2; args[2] = MGA_ALPHA;
   } else
   if ((arg1[1] | arg2[0] | alpha[2]) != ARG_DISABLE) {
      *reg |= arg1[1] | arg2[0] | alpha[2];
      args[0] = MGA_ARG2; args[1] = MGA_ARG1; args[2] = MGA_ALPHA;
   } else
   if (!(arg1[0] | arg2[2] | alpha[1]) != ARG_DISABLE) {
      *reg |= arg1[0] | arg2[2] | alpha[1];
      args[0] = MGA_ARG1; args[1] = MGA_ALPHA; args[2] = MGA_ARG2;
   } else
   if (!(arg1[2] | arg2[0] | alpha[1]) != ARG_DISABLE) {
      *reg |= arg1[2] | arg2[0] | alpha[1];
      args[0] = MGA_ARG2; args[1] = MGA_ALPHA; args[2] = MGA_ARG1;
   } else
   if (!(arg1[1] | arg2[2] | alpha[0]) != ARG_DISABLE) {
      *reg |= arg1[1] | arg2[2] | alpha[0];
      args[0] = MGA_ALPHA; args[1] = MGA_ARG1; args[2] = MGA_ARG2;
   } else
   if (!(arg1[2] | arg2[1] | alpha[0]) != ARG_DISABLE) {
      *reg |= arg1[2] | arg2[1] | alpha[0];
      args[0] = MGA_ALPHA; args[1] = MGA_ARG2; args[2] = MGA_ARG1;
   } else {
      /* nothing suitable */
      return GL_FALSE;
   }

   switch (texUnit->CombineModeRGB) {
   case GL_REPLACE:
      if (texUnit->CombineScaleShiftRGB) {
         return GL_FALSE;
      }

      if (args[0] == MGA_ARG1) {
         *reg |= TD0_color_sel_arg1;
      } else if (args[0] == MGA_ARG2) {
         *reg |= TD0_color_sel_arg2;
      } else if (args[0] == MGA_ALPHA) {
         /* Can't get alpha out by itself */
         return GL_FALSE;
      }
      break;
   case GL_MODULATE:
      if (texUnit->CombineScaleShiftRGB == 1) {
         *reg |= TD0_color_modbright_2x;
      } else if (texUnit->CombineScaleShiftRGB == 2) {
         *reg |= TD0_color_modbright_4x;
      }

      *reg |= TD0_color_sel_mul;

      if (args[0] == MGA_ALPHA || args[1] == MGA_ALPHA) {
         if (args[0] == MGA_ARG1 || args[1] == MGA_ARG1) {
            *reg |= TD0_color_arg2mul_alpha2;
         } else if (args[0] == MGA_ARG2 || args[1] == MGA_ARG2) {
            *reg |= TD0_color_arg1mul_alpha1;
         }
      }
      break;
   case GL_ADD:
      if (args[0] == MGA_ALPHA || args[1] == MGA_ALPHA){
         /* Can't get alpha to the adder */
         return GL_FALSE;
      }
      if (texUnit->CombineScaleShiftRGB == 1) {
         *reg |= TD0_color_add2x_enable;
      } else if (texUnit->CombineScaleShiftRGB == 2) {
         return GL_FALSE;
      }

      *reg |= (TD0_color_add_add |
               TD0_color_sel_add);
      break;
   case GL_ADD_SIGNED:
      if (args[0] == MGA_ALPHA || args[1] == MGA_ALPHA){
         /* Can't get alpha to the adder */
         return GL_FALSE;
      }
      if (texUnit->CombineScaleShiftRGB == 1) {
         *reg |= TD0_color_add2x_enable;
      } else if (texUnit->CombineScaleShiftRGB == 2) {
         return GL_FALSE;
      }

      *reg |= (TD0_color_addbias_enable |
               TD0_color_add_add |
               TD0_color_sel_add);
      break;
   case GL_INTERPOLATE:
      if (args[2] != MGA_ALPHA) {
         /* Only alpha can function as Arg2 */
         return GL_FALSE;
      }
      if (texUnit->CombineScaleShiftRGB == 1) {
         *reg |= TD0_color_add2x_enable;
      } else if (texUnit->CombineScaleShiftRGB == 2) {
         return GL_FALSE;
      }

      *reg |= (TD0_color_arg1mul_alpha1 |
               TD0_color_blend_enable |
               TD0_color_arg1add_mulout |
               TD0_color_arg2add_mulout |
               TD0_color_add_add |
               TD0_color_sel_add);

      /* Have to do this with xor since GL_ONE_MINUS_SRC_ALPHA may have
       * already touched these bits.
       */
      *reg ^= TD0_color_alpha1inv_enable;

      if (args[0] == MGA_ARG2) {
         /* Swap arguments */
         *reg ^= (TD0_color_arg1mul_alpha1 |
                  TD0_color_arg2mul_alpha2 |
                  TD0_color_alpha1inv_enable |
                  TD0_color_alpha2inv_enable);
      }

      if (ctx->Texture._EnabledUnits != 0x03) {
         /* Linear blending mode needs dualtex enabled */
         mmesa->dualtex_env = GL_TRUE;
      }
      break;
   case GL_SUBTRACT:
      if (args[0] == MGA_ALPHA || args[1] == MGA_ALPHA) {
         /* Can't get alpha to the adder */
         return GL_FALSE;
      }
      if (texUnit->CombineScaleShiftRGB == 1) {
         *reg |= TD0_color_add2x_enable;
      } else if (texUnit->CombineScaleShiftRGB == 2) {
         return GL_FALSE;
      }

      *reg |= (TD0_color_add_sub |
               TD0_color_sel_add);

      if (args[0] == MGA_ARG2) {
         /* Swap arguments */
         *reg ^= (TD0_color_arg1_inv_enable |
                  TD0_color_arg2_inv_enable);
      }
      break;
   }


   /* ALPHA */
   for (i = 0; i < 2; i++) {
      arg1[i] = 0;
      arg2[i] = 0;
   }

   for (i = 0; i < numAlphaArgs; i++) {
      switch (texUnit->CombineSourceA[i]) {
      case GL_TEXTURE:
         arg1[i] |= 0;
         arg2[i] |= ARG_DISABLE;
         break;
      case GL_TEXTURE0:
         if (source == 0) {
            arg1[i] |= 0;
            arg2[i] |= ARG_DISABLE;
         } else {
            if (ctx->Texture._EnabledUnits != 0x03) {
               /* disable texturing */
               mmesa->setup.dwgctl &= DC_opcod_MASK;
               mmesa->setup.dwgctl |= DC_opcod_trap;
               mmesa->hw.alpha_sel = AC_alphasel_diffused;
               /* return GL_TRUE since we don't need a fallback */
               return GL_TRUE;
            }
            arg1[i] |= ARG_DISABLE;
            arg2[i] |= TD0_alpha_arg2_prevtex;
         }
         break;
      case GL_TEXTURE1:
         if (source == 0) {
            if (ctx->Texture._EnabledUnits != 0x03) {
               /* disable texturing */
               mmesa->setup.dwgctl &= DC_opcod_MASK;
               mmesa->setup.dwgctl |= DC_opcod_trap;
               mmesa->hw.alpha_sel = AC_alphasel_diffused;
               /* return GL_TRUE since we don't need a fallback */
               return GL_TRUE;
            }
            arg1[i] |= ARG_DISABLE;
            /* G400 specs.(TDUALSTAGE0) */
            arg2[i] |= TD0_alpha_arg2_prevstage;
         } else {
            arg1[i] |= 0;
            arg2[i] |= ARG_DISABLE;
         }
         break;
      case GL_CONSTANT:
         arg1[i] |= ARG_DISABLE;
         arg2[i] |= TD0_alpha_arg2_fcol;
         break;
      case GL_PRIMARY_COLOR:
         arg1[i] |= ARG_DISABLE;
         /* G400 specs.(TDUALSTAGE1) */
         if (unit == 0 || (mmesa->setup.tdualstage0 &
                           ((TD0_color_sel_mul & TD0_color_sel_add) |
                            (TD0_alpha_sel_mul & TD0_alpha_sel_add)))) {
            arg2[i] |= TD0_alpha_arg2_diffuse;
         } else {
            arg2[i] |= ARG_DISABLE;
         }
         break;
      case GL_PREVIOUS:
         arg1[i] |= ARG_DISABLE;
         if (unit == 0) {
            arg2[i] |= TD0_alpha_arg2_diffuse;
         } else {
            arg2[i] |= TD0_alpha_arg2_prevstage;
         }
         break;
      }

      switch (texUnit->CombineOperandA[i]) {
      case GL_SRC_ALPHA:
         arg1[i] |= 0;
         arg2[i] |= 0;
         break;
      case GL_ONE_MINUS_SRC_ALPHA:
         arg1[i] |= TD0_alpha_arg1_inv_enable;
         arg2[i] |= TD0_alpha_arg2_inv_enable;
         break;
      }
   }

   /* Find a working combo of arg1 and arg2 */
   if ((arg1[0] | arg2[1]) != ARG_DISABLE) {
      *reg |= arg1[0] | arg2[1];
      args[0] = MGA_ARG1; args[1] = MGA_ARG2;
   } else
   if ((arg1[1] | arg2[0]) != ARG_DISABLE) {
      *reg |= arg1[1] | arg2[0];
      args[0] = MGA_ARG2; args[1] = MGA_ARG1;
   } else {
      /* nothing suitable */
      return GL_FALSE;
   }

   switch (texUnit->CombineModeA) {
   case GL_REPLACE:
      if (texUnit->CombineScaleShiftA) {
         return GL_FALSE;
      }

      if (args[0] == MGA_ARG1){
         *reg |= TD0_alpha_sel_arg1;
      } else if (args[0] == MGA_ARG2) {
         *reg |= TD0_alpha_sel_arg2;
      }
      break;
   case GL_MODULATE:
      if (texUnit->CombineScaleShiftA == 1) {
         *reg |= TD0_alpha_modbright_2x;
      } else if (texUnit->CombineScaleShiftA == 2) {
         *reg |= TD0_alpha_modbright_4x;
      }

      *reg |= TD0_alpha_sel_mul;
      break;
   case GL_ADD:
      if (texUnit->CombineScaleShiftA == 1) {
         *reg |= TD0_alpha_add2x_enable;
      } else if (texUnit->CombineScaleShiftA == 2) {
         return GL_FALSE;
      }

      *reg |= (TD0_alpha_add_enable |
               TD0_alpha_sel_add);
      break;
   case GL_ADD_SIGNED:
      if (texUnit->CombineScaleShiftA == 1) {
         *reg |= TD0_alpha_add2x_enable;
      } else if (texUnit->CombineScaleShiftA == 2) {
         return GL_FALSE;
      }

      *reg |= (TD0_alpha_addbias_enable |
               TD0_alpha_add_enable |
               TD0_alpha_sel_add);
      break;
   case GL_INTERPOLATE:
      /* fallback */
      return GL_FALSE;
   case GL_SUBTRACT:
      if (texUnit->CombineScaleShiftA == 1) {
         *reg |= TD0_alpha_add2x_enable;
      } else if (texUnit->CombineScaleShiftA == 2) {
         return GL_FALSE;
      }

      *reg |= (TD0_alpha_add_disable |
               TD0_alpha_sel_add);

      if (args[0] == MGA_ARG2) {
         /* Swap arguments */
         *reg ^= (TD0_alpha_arg1_inv_enable |
                  TD0_alpha_arg2_inv_enable);
      }
      break;
   }

   return GL_TRUE;
}
   
   

Reply via email to