All elements of pre-DRI_NEW_INTERFACE_ONLY are removed. This allows
[mesa.git] / src / mesa / drivers / dri / mga / mgastate.c
index 02b98fdb7661476011b7a5616acbe306020db084..72d5c9fb0829675e0d689f13815e380f87151e03 100644 (file)
  */
 /* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgastate.c,v 1.13 2002/10/30 12:51:36 alanh Exp $ */
 
-#include <stdio.h>
 
 #include "mtypes.h"
+#include "buffers.h"
+#include "colormac.h"
 #include "dd.h"
 
 #include "mm.h"
 #include "mgatris.h"
 #include "mgaioctl.h"
 #include "mgaregs.h"
-#include "mgabuffers.h"
 
 #include "swrast/swrast.h"
 #include "array_cache/acache.h"
 #include "tnl/tnl.h"
+#include "tnl/t_context.h"
+#include "tnl/t_pipeline.h"
 #include "swrast_setup/swrast_setup.h"
 
+#include "xmlpool.h"
 
+static void updateSpecularLighting( GLcontext *ctx );
 
-/* Some outstanding problems with accelerating logic ops...
- */
-#if defined(ACCEL_ROP)
-static GLuint mgarop_NoBLK[16] = {
+static const GLuint mgarop_NoBLK[16] = {
    DC_atype_rpl  | 0x00000000, DC_atype_rstr | 0x00080000,
    DC_atype_rstr | 0x00040000, DC_atype_rpl  | 0x000c0000,
    DC_atype_rstr | 0x00020000, DC_atype_rstr | 0x000a0000,
@@ -62,476 +63,234 @@ static GLuint mgarop_NoBLK[16] = {
    DC_atype_rpl  | 0x00030000, DC_atype_rstr | 0x000b0000,
    DC_atype_rstr | 0x00070000, DC_atype_rpl  | 0x000f0000
 };
-#endif
 
+/* =============================================================
+ * Alpha blending
+ */
 
-static void mgaUpdateStencil(const GLcontext *ctx)
+static void mgaDDAlphaFunc(GLcontext *ctx, GLenum func, GLfloat ref)
 {
    mgaContextPtr mmesa = MGA_CONTEXT(ctx);
-   GLuint stencil = 0, stencilctl = 0;
-
-   if (ctx->Stencil.Enabled)
-   {
-      stencil = ctx->Stencil.Ref[0] |
-        ( ctx->Stencil.ValueMask[0] << 8 ) |
-        ( ctx->Stencil.WriteMask[0] << 16 );
-
-      switch (ctx->Stencil.Function[0])
-      {
-      case GL_NEVER:
-        MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_snever);
-        break;
-      case GL_LESS:
-        MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_slt);
-        break;
-      case GL_LEQUAL:
-        MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_slte);
-        break;
-      case GL_GREATER:
-        MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_sgt);
-        break;
-      case GL_GEQUAL:
-        MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_sgte);
-        break;
-      case GL_NOTEQUAL:
-        MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_sne);
-        break;
-      case GL_EQUAL:
-        MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_se);
-        break;
-      case GL_ALWAYS:
-        MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_salways);
-      default:
-        break;
-      }
+   GLubyte refByte;
+   GLuint  a;
 
-      switch (ctx->Stencil.FailFunc[0])
-      {
-      case GL_KEEP:
-        MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_keep);
-        break;
-      case GL_ZERO:
-        MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_zero);
-        break;
-      case GL_REPLACE:
-        MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_replace);
-        break;
-      case GL_INCR:
-        MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_incrsat);
-        break;
-      case GL_DECR:
-        MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_decrsat);
-        break;
-      case GL_INVERT:
-        MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_invert);
-        break;
-      default:
-        break;
-      }
+   CLAMPED_FLOAT_TO_UBYTE(refByte, ref);
 
-      switch (ctx->Stencil.ZFailFunc[0])
-      {
-      case GL_KEEP:
-        MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_keep);
-        break;
-      case GL_ZERO:
-        MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_zero);
-        break;
-      case GL_REPLACE:
-        MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_replace);
-        break;
-      case GL_INCR:
-        MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_incrsat);
-        break;
-      case GL_DECR:
-        MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_decrsat);
-        break;
-      case GL_INVERT:
-        MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_invert);
-        break;
-      default:
-        break;
-      }
-
-      switch (ctx->Stencil.ZPassFunc[0])
-      {
-      case GL_KEEP:
-        MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_keep);
-        break;
-      case GL_ZERO:
-        MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_zero);
-        break;
-      case GL_REPLACE:
-        MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_replace);
-        break;
-      case GL_INCR:
-        MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_incrsat);
-        break;
-      case GL_DECR:
-        MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_decrsat);
-        break;
-      case GL_INVERT:
-        MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_invert);
-        break;
-      default:
-        break;
-      }
+   switch ( func ) {
+   case GL_NEVER:
+      a = AC_atmode_alt;
+      refByte = 0;
+      break;
+   case GL_LESS:
+      a = AC_atmode_alt;
+      break;
+   case GL_GEQUAL:
+      a = AC_atmode_agte;
+      break;
+   case GL_LEQUAL:
+      a = AC_atmode_alte;
+      break;
+   case GL_GREATER:
+      a = AC_atmode_agt;
+      break;
+   case GL_NOTEQUAL:
+      a = AC_atmode_ane;
+      break;
+   case GL_EQUAL:
+      a = AC_atmode_ae;
+      break;
+   case GL_ALWAYS:
+      a = AC_atmode_noacmp;
+      break;
+   default:
+      a = 0;
+      break;
    }
 
-   mmesa->setup.stencil = stencil;
-   mmesa->setup.stencilctl = stencilctl;
-   mmesa->dirty |= MGA_UPLOAD_CONTEXT;
+   MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
+   mmesa->hw.alpha_func = a | MGA_FIELD( AC_atref, refByte );
 }
 
-static void mgaDDStencilFunc(GLcontext *ctx, GLenum func, GLint ref,
-                            GLuint mask)
-{
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   MGA_CONTEXT(ctx)->new_state |= MGA_NEW_STENCIL;
-}
-
-static void mgaDDStencilMask(GLcontext *ctx, GLuint mask)
-{
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   MGA_CONTEXT(ctx)->new_state |= MGA_NEW_STENCIL;
-}
-
-static void mgaDDStencilOp(GLcontext *ctx, GLenum fail, GLenum zfail,
-                          GLenum zpass)
-{
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   MGA_CONTEXT(ctx)->new_state |= MGA_NEW_STENCIL;
-}
-
-static void mgaDDClearDepth(GLcontext *ctx, GLclampd d)
+static void updateBlendLogicOp(GLcontext *ctx)
 {
    mgaContextPtr mmesa = MGA_CONTEXT(ctx);
 
-   /* KW: should the ~ be there? */
-   switch (mmesa->setup.maccess & ~MA_zwidth_MASK) {
-   case MA_zwidth_16: mmesa->ClearDepth = d * 0x0000ffff; break;
-   case MA_zwidth_24: mmesa->ClearDepth = d * 0xffffff00; break;
-   case MA_zwidth_32: mmesa->ClearDepth = d * 0xffffffff; break;
-   default: return;
-   }
-}
-
-static void mgaUpdateZMode(const GLcontext *ctx)
-{
-   mgaContextPtr mmesa = MGA_CONTEXT( ctx );
-   int zmode = 0;
-
-   if (ctx->Depth.Test) {
-      switch(ctx->Depth.Func)  {
-      case GL_NEVER:
-         /* can't do this in h/w, we'll use a s/w fallback */
-        zmode = DC_zmode_nozcmp;
-         break;
-      case GL_ALWAYS:
-        zmode = DC_zmode_nozcmp; break;
-      case GL_LESS:
-        zmode = DC_zmode_zlt; break;
-      case GL_LEQUAL:
-        zmode = DC_zmode_zlte; break;
-      case GL_EQUAL:
-        zmode = DC_zmode_ze; break;
-      case GL_GREATER:
-        zmode = DC_zmode_zgt; break;
-      case GL_GEQUAL:
-        zmode = DC_zmode_zgte; break;
-      case GL_NOTEQUAL:
-        zmode = DC_zmode_zne; break;
-      default:
-        break;
-      }
-
-      if (ctx->Depth.Mask)
-         zmode |= DC_atype_zi;
-      else
-         zmode |= DC_atype_i;
-   }
-   else {
-      zmode |= DC_zmode_nozcmp;
-      zmode |= DC_atype_i;  /* don't write to zbuffer */
-   }
-
-#if defined(ACCEL_ROP)
-   mmesa->setup.dwgctl &= DC_bop_MASK;
-   if (ctx->Color.ColorLogicOpEnabled)
-      zmode |= mgarop_NoBLK[(ctx->Color.LogicOp)&0xf];
-   else
-      zmode |= mgarop_NoBLK[GL_COPY & 0xf];
-#endif
-
-   mmesa->setup.dwgctl &= DC_zmode_MASK & DC_atype_MASK;
-   mmesa->setup.dwgctl |= zmode;
-   mmesa->dirty |= MGA_UPLOAD_CONTEXT;
-}
-
-
-static void mgaDDAlphaFunc(GLcontext *ctx, GLenum func, GLfloat ref)
-{
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   MGA_CONTEXT(ctx)->new_state |= MGA_NEW_ALPHA;
-}
-
+   MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
 
-static void mgaDDBlendEquation(GLcontext *ctx, GLenum mode)
-{
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   MGA_CONTEXT(ctx)->new_state |= MGA_NEW_ALPHA;
+   mmesa->hw.blend_func_enable =
+      (ctx->Color.BlendEnabled && !ctx->Color._LogicOpEnabled) ? ~0 : 0;
 
-   /* BlendEquation sets ColorLogicOpEnabled in an unexpected 
-    * manner.  
-    */
-   FALLBACK( ctx, MGA_FALLBACK_LOGICOP,
-            (ctx->Color.ColorLogicOpEnabled && 
-             ctx->Color.LogicOp != GL_COPY));
+   FALLBACK( ctx, MGA_FALLBACK_BLEND,
+             ctx->Color.BlendEnabled && !ctx->Color._LogicOpEnabled &&
+             mmesa->hw.blend_func == (AC_src_src_alpha_sat | AC_dst_zero) );
 }
 
-static void mgaDDBlendFunc(GLcontext *ctx, GLenum sfactor, GLenum dfactor)
+static void mgaDDBlendEquationSeparate(GLcontext *ctx, 
+                                      GLenum modeRGB, GLenum modeA)
 {
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   MGA_CONTEXT(ctx)->new_state |= MGA_NEW_ALPHA;
+   assert( modeRGB == modeA );
+   updateBlendLogicOp( ctx );
 }
 
 static void mgaDDBlendFuncSeparate( GLcontext *ctx, GLenum sfactorRGB,
                                    GLenum dfactorRGB, GLenum sfactorA,
                                    GLenum dfactorA )
 {
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   MGA_CONTEXT(ctx)->new_state |= MGA_NEW_ALPHA;
-}
-
-
+   mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+   GLuint   src;
+   GLuint   dst;
+
+   switch (ctx->Color.BlendSrcRGB) {
+   case GL_ZERO:
+      src = AC_src_zero; break;
+   case GL_SRC_ALPHA:
+      src = AC_src_src_alpha; break;
+   case GL_ONE:
+   default:            /* never happens */
+      src = AC_src_one; break;
+   case GL_DST_COLOR:
+      src = AC_src_dst_color; break;
+   case GL_ONE_MINUS_DST_COLOR:
+      src = AC_src_om_dst_color; break;
+   case GL_ONE_MINUS_SRC_ALPHA:
+      src = AC_src_om_src_alpha; break;
+   case GL_DST_ALPHA:
+      src = (ctx->Visual.alphaBits > 0)
+         ? AC_src_dst_alpha : AC_src_one;
+      break;
+   case GL_ONE_MINUS_DST_ALPHA:
+      src = (ctx->Visual.alphaBits > 0)
+         ? AC_src_om_dst_alpha : AC_src_zero;
+      break;
+   case GL_SRC_ALPHA_SATURATE:
+      src = (ctx->Visual.alphaBits > 0)
+         ? AC_src_src_alpha_sat : AC_src_zero;
+      break;
+   }
 
-static void mgaDDLightModelfv(GLcontext *ctx, GLenum pname,
-                             const GLfloat *param)
-{
-   if (pname == GL_LIGHT_MODEL_COLOR_CONTROL) {
-      FLUSH_BATCH( MGA_CONTEXT(ctx) );
-      MGA_CONTEXT(ctx)->new_state |= MGA_NEW_TEXTURE;
+   switch (ctx->Color.BlendDstRGB) {
+   case GL_SRC_ALPHA:
+      dst = AC_dst_src_alpha; break;
+   case GL_ONE_MINUS_SRC_ALPHA:
+      dst = AC_dst_om_src_alpha; break;
+   default:            /* never happens */
+   case GL_ZERO:
+      dst = AC_dst_zero; break;
+   case GL_ONE:
+      dst = AC_dst_one; break;
+   case GL_SRC_COLOR:
+      dst = AC_dst_src_color; break;
+   case GL_ONE_MINUS_SRC_COLOR:
+      dst = AC_dst_om_src_color; break;
+   case GL_DST_ALPHA:
+      dst = (ctx->Visual.alphaBits > 0)
+         ? AC_dst_dst_alpha : AC_dst_one;
+      break;
+   case GL_ONE_MINUS_DST_ALPHA:
+      dst = (ctx->Visual.alphaBits > 0)
+         ? AC_dst_om_dst_alpha : AC_dst_zero;
+      break;
    }
-}
 
+   MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
+   mmesa->hw.blend_func = (src | dst);
 
-static void mgaDDShadeModel(GLcontext *ctx, GLenum mode)
-{
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   MGA_CONTEXT(ctx)->new_state |= MGA_NEW_TEXTURE;
+   FALLBACK( ctx, MGA_FALLBACK_BLEND,
+             ctx->Color.BlendEnabled && !ctx->Color._LogicOpEnabled &&
+             mmesa->hw.blend_func == (AC_src_src_alpha_sat | AC_dst_zero) );
 }
 
+/* =============================================================
+ * Depth testing
+ */
 
 static void mgaDDDepthFunc(GLcontext *ctx, GLenum func)
 {
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   MGA_CONTEXT(ctx)->new_state |= MGA_NEW_DEPTH;
+   mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+   int zmode;
+
+   switch (func) {
+   case GL_NEVER:
+      /* can't do this in h/w, we'll use a s/w fallback */
+      FALLBACK (ctx, MGA_FALLBACK_DEPTH, ctx->Depth.Test);
+
+      /* FALLTHROUGH */
+   case GL_ALWAYS:
+      zmode = DC_zmode_nozcmp; break;
+   case GL_LESS:
+      zmode = DC_zmode_zlt; break;
+   case GL_LEQUAL:
+      zmode = DC_zmode_zlte; break;
+   case GL_EQUAL:
+      zmode = DC_zmode_ze; break;
+   case GL_GREATER:
+      zmode = DC_zmode_zgt; break;
+   case GL_GEQUAL:
+      zmode = DC_zmode_zgte; break;
+   case GL_NOTEQUAL:
+      zmode = DC_zmode_zne; break;
+   default:
+      zmode = 0; break;
+   }
+
+   MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
+   mmesa->hw.zmode &= DC_zmode_MASK;
+   mmesa->hw.zmode |= zmode;
 }
 
 static void mgaDDDepthMask(GLcontext *ctx, GLboolean flag)
 {
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   MGA_CONTEXT(ctx)->new_state |= MGA_NEW_DEPTH;
-}
+   mgaContextPtr mmesa = MGA_CONTEXT( ctx );
 
-#if defined(ACCEL_ROP)
-static void mgaDDLogicOp( GLcontext *ctx, GLenum opcode )
-{
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   MGA_CONTEXT(ctx)->new_state |= MGA_NEW_DEPTH;
-}
-#else
-static void mgaDDLogicOp( GLcontext *ctx, GLenum opcode )
-{
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   FALLBACK( ctx, MGA_FALLBACK_LOGICOP, 
-            (ctx->Color.ColorLogicOpEnabled && opcode != GL_COPY) );
-}
-#endif
 
+   MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
+   mmesa->hw.zmode &= DC_atype_MASK;
+   mmesa->hw.zmode |= (flag) ? DC_atype_zi : DC_atype_i;
+}
 
 
-static void mgaDDFogfv(GLcontext *ctx, GLenum pname, const GLfloat *param)
+static void mgaDDClearDepth(GLcontext *ctx, GLclampd d)
 {
    mgaContextPtr mmesa = MGA_CONTEXT(ctx);
 
-   if (pname == GL_FOG_COLOR) {
-      GLuint color = MGAPACKCOLOR888((GLubyte)(ctx->Fog.Color[0]*255.0F), 
-                                    (GLubyte)(ctx->Fog.Color[1]*255.0F), 
-                                    (GLubyte)(ctx->Fog.Color[2]*255.0F));
-
-      MGA_STATECHANGE(mmesa, MGA_UPLOAD_CONTEXT);   
-      mmesa->setup.fogcolor = color;
+   /* Select the Z depth.  The ~ is used because the _MASK values in the
+    * MGA driver are used to mask OFF the selected bits.  In this case,
+    * we want to mask off everything except the MA_zwidth bits.
+    */
+   switch (mmesa->setup.maccess & ~MA_zwidth_MASK) {
+   case MA_zwidth_16: mmesa->ClearDepth = d * 0x0000ffff; break;
+   case MA_zwidth_24: mmesa->ClearDepth = d * 0xffffff00; break;
+   case MA_zwidth_32: mmesa->ClearDepth = d * 0xffffffff; break;
+   default: return;
    }
 }
 
 
-
-
 /* =============================================================
- * Alpha blending
+ * Fog
  */
 
 
-static void mgaUpdateAlphaMode(GLcontext *ctx)
+static void mgaDDFogfv(GLcontext *ctx, GLenum pname, const GLfloat *param)
 {
-   mgaContextPtr mmesa = MGA_CONTEXT( ctx );
-   mgaScreenPrivate *mgaScreen = mmesa->mgaScreen;
-   int a = 0;
-
-   /* determine source of alpha for blending and testing */
-   if ( !ctx->Texture.Unit[0]._ReallyEnabled ) {
-      a |= AC_alphasel_diffused;
-   }
-   else {
-      /* G400: Regardless of texture env mode, we use the alpha from the
-       * texture unit (AC_alphasel_fromtex) since it will have already
-       * been modulated by the incoming fragment color, if needed.
-       * We don't want (AC_alphasel_modulate) since that'll effectively
-       * do the modulation twice.
-       */
-      if (MGA_IS_G400(mmesa)) {
-         a |= AC_alphasel_fromtex;
-      }
-      else {
-         /* G200 */
-         switch (ctx->Texture.Unit[0].EnvMode) {
-         case GL_DECAL:
-            a |= AC_alphasel_diffused;
-         case GL_REPLACE:
-            a |= AC_alphasel_fromtex;
-            break;
-         case GL_BLEND:
-         case GL_MODULATE:
-            a |= AC_alphasel_modulated;
-            break;
-         default:
-            break;
-         }
-      }
-   }
-
-
-   /* alpha test control.
-    */
-   if (ctx->Color.AlphaEnabled) {
-      GLubyte ref = ctx->Color.AlphaRef;
-      switch (ctx->Color.AlphaFunc) {
-      case GL_NEVER:
-        a |= AC_atmode_alt;
-        ref = 0;
-        break;
-      case GL_LESS:
-        a |= AC_atmode_alt;
-        break;
-      case GL_GEQUAL:
-        a |= AC_atmode_agte;
-        break;
-      case GL_LEQUAL:
-        a |= AC_atmode_alte;
-        break;
-      case GL_GREATER:
-        a |= AC_atmode_agt;
-        break;
-      case GL_NOTEQUAL:
-        a |= AC_atmode_ane;
-        break;
-      case GL_EQUAL:
-        a |= AC_atmode_ae;
-        break;
-      case GL_ALWAYS:
-        a |= AC_atmode_noacmp;
-        break;
-      default:
-        break;
-      }
-      a |= MGA_FIELD(AC_atref,ref);
-   }
+   mgaContextPtr mmesa = MGA_CONTEXT(ctx);
 
-   /* blending control */
-   if (ctx->Color.BlendEnabled) {
-      switch (ctx->Color.BlendSrcRGB) {
-      case GL_ZERO:
-        a |= AC_src_zero; break;
-      case GL_SRC_ALPHA:
-        a |= AC_src_src_alpha; break;
-      case GL_ONE:
-        a |= AC_src_one; break;
-      case GL_DST_COLOR:
-        a |= AC_src_dst_color; break;
-      case GL_ONE_MINUS_DST_COLOR:
-        a |= AC_src_om_dst_color; break;
-      case GL_ONE_MINUS_SRC_ALPHA:
-        a |= AC_src_om_src_alpha; break;
-      case GL_DST_ALPHA:
-        if (mgaScreen->cpp == 4)
-           a |= AC_src_dst_alpha;
-        else
-           a |= AC_src_one;
-        break;
-      case GL_ONE_MINUS_DST_ALPHA:
-        if (mgaScreen->cpp == 4)
-           a |= AC_src_om_dst_alpha;
-        else
-           a |= AC_src_zero;
-        break;
-      case GL_SRC_ALPHA_SATURATE:
-         if (ctx->Visual.alphaBits > 0)
-            a |= AC_src_src_alpha_sat;
-         else
-            a |= AC_src_zero;
-        break;
-      default:         /* never happens */
-        break;
-      }
+   if (pname == GL_FOG_COLOR) {
+      GLuint color = PACK_COLOR_888((GLubyte)(ctx->Fog.Color[0]*255.0F), 
+                                   (GLubyte)(ctx->Fog.Color[1]*255.0F), 
+                                   (GLubyte)(ctx->Fog.Color[2]*255.0F));
 
-      switch (ctx->Color.BlendDstRGB) {
-      case GL_SRC_ALPHA:
-        a |= AC_dst_src_alpha; break;
-      case GL_ONE_MINUS_SRC_ALPHA:
-        a |= AC_dst_om_src_alpha; break;
-      case GL_ZERO:
-        a |= AC_dst_zero; break;
-      case GL_ONE:
-        a |= AC_dst_one; break;
-      case GL_SRC_COLOR:
-        a |= AC_dst_src_color; break;
-      case GL_ONE_MINUS_SRC_COLOR:
-        a |= AC_dst_om_src_color; break;
-      case GL_DST_ALPHA:
-        if (mgaScreen->cpp == 4)
-           a |= AC_dst_dst_alpha;
-        else
-           a |= AC_dst_one;
-        break;
-      case GL_ONE_MINUS_DST_ALPHA:
-        if (mgaScreen->cpp == 4)
-           a |= AC_dst_om_dst_alpha;
-        else
-           a |= AC_dst_zero;
-        break;
-      default:         /* never happens */
-        break;
-      }
-   } else {
-      a |= AC_src_one|AC_dst_zero;
+      MGA_STATECHANGE(mmesa, MGA_UPLOAD_CONTEXT);   
+      mmesa->setup.fogcolor = color;
    }
-
-   mmesa->setup.alphactrl = (AC_amode_alpha_channel |
-                            AC_astipple_disable |
-                            AC_aten_disable |
-                            AC_atmode_noacmp |
-                            a);
-
-   mmesa->dirty |= MGA_UPLOAD_CONTEXT;
 }
 
 
-
 /* =============================================================
- * Hardware clipping
+ * Scissoring
  */
 
+
 void mgaUpdateClipping(const GLcontext *ctx)
 {
    mgaContextPtr mmesa = MGA_CONTEXT(ctx);
@@ -541,8 +300,8 @@ void mgaUpdateClipping(const GLcontext *ctx)
       int x1 = mmesa->driDrawable->x + ctx->Scissor.X;
       int y1 = mmesa->driDrawable->y + mmesa->driDrawable->h
         - (ctx->Scissor.Y + ctx->Scissor.Height);
-      int x2 = x1 + ctx->Scissor.Width - 1;
-      int y2 = y1 + ctx->Scissor.Height - 1;
+      int x2 = x1 + ctx->Scissor.Width;
+      int y2 = y1 + ctx->Scissor.Height;
 
       if (x1 < 0) x1 = 0;
       if (y1 < 0) y1 = 0;
@@ -554,13 +313,6 @@ void mgaUpdateClipping(const GLcontext *ctx)
       mmesa->scissor_rect.x2 = x2;
       mmesa->scissor_rect.y2 = y2;
 
-      if (MGA_DEBUG&DEBUG_VERBOSE_2D)
-        fprintf(stderr, "SET SCISSOR %d,%d-%d,%d\n",
-                mmesa->scissor_rect.x1,
-                mmesa->scissor_rect.y1,
-                mmesa->scissor_rect.x2,
-                mmesa->scissor_rect.y2);
-
       mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
    }
 }
@@ -569,19 +321,10 @@ void mgaUpdateClipping(const GLcontext *ctx)
 static void mgaDDScissor( GLcontext *ctx, GLint x, GLint y,
                          GLsizei w, GLsizei h )
 {
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   MGA_CONTEXT(ctx)->new_state |= MGA_NEW_CLIP;
-}
-
-
-static void mgaDDClearColor(GLcontext *ctx, 
-                           const GLfloat color[4] )
-{
-   mgaContextPtr mmesa = MGA_CONTEXT(ctx);
-
-   mmesa->ClearColor = mgaPackColor( mmesa->mgaScreen->cpp,
-                                    color[0], color[1], 
-                                    color[2], color[3]);
+   if ( ctx->Scissor.Enabled ) {
+      FLUSH_BATCH( MGA_CONTEXT(ctx) ); /* don't pipeline cliprect changes */
+      mgaUpdateClipping( ctx );
+   }
 }
 
 
@@ -589,46 +332,39 @@ static void mgaDDClearColor(GLcontext *ctx,
  * Culling
  */
 
+
 #define _CULL_DISABLE 0
 #define _CULL_NEGATIVE ((1<<11)|(1<<5)|(1<<16))
 #define _CULL_POSITIVE (1<<11)
 
-
-void mgaUpdateCull( GLcontext *ctx )
+static void mgaDDCullFaceFrontFace(GLcontext *ctx, GLenum unused)
 {
    mgaContextPtr mmesa = MGA_CONTEXT(ctx);
-   GLuint mode = _CULL_DISABLE;
 
+   MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
    if (ctx->Polygon.CullFlag && 
-       mmesa->raster_primitive == GL_TRIANGLES &&       
        ctx->Polygon.CullFaceMode != GL_FRONT_AND_BACK) 
    {
-      mode = _CULL_NEGATIVE;
-      if (ctx->Polygon.CullFaceMode == GL_FRONT)
-        mode ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE);
-      if (ctx->Polygon.FrontFace != GL_CCW)
-        mode ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE);
-      if ((ctx->Texture.Unit[0]._ReallyEnabled & TEXTURE_2D_BIT) &&
-          (ctx->Texture.Unit[1]._ReallyEnabled & TEXTURE_2D_BIT))
-        mode ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE); /* warp bug? */
-   }
+      mmesa->hw.cull = _CULL_NEGATIVE;
 
-   mmesa->setup.wflag = mode;
-   mmesa->dirty |= MGA_UPLOAD_CONTEXT;
-}
+      if (ctx->Polygon.CullFaceMode == GL_FRONT)
+        mmesa->hw.cull ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE);
 
+      if (ctx->Polygon.FrontFace != GL_CCW)
+        mmesa->hw.cull ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE);
 
-static void mgaDDCullFaceFrontFace(GLcontext *ctx, GLenum mode)
-{
-   FLUSH_BATCH( MGA_CONTEXT(ctx) );
-   MGA_CONTEXT(ctx)->new_state |= MGA_NEW_CULL;
+      mmesa->hw.cull_dualtex = mmesa->hw.cull ^
+         (_CULL_POSITIVE ^ _CULL_NEGATIVE); /* warp bug? */
+   }
+   else {
+      mmesa->hw.cull = _CULL_DISABLE;
+      mmesa->hw.cull_dualtex = _CULL_DISABLE;
+   }
 }
 
 
-
-
 /* =============================================================
- * Color masks
+ * Masks
  */
 
 static void mgaDDColorMask(GLcontext *ctx, 
@@ -654,17 +390,13 @@ static void mgaDDColorMask(GLcontext *ctx,
    }
 }
 
+
 /* =============================================================
- * Polygon stipple
- *
- * The mga supports a subset of possible 4x4 stipples natively, GL
- * wants 32x32.  Fortunately stipple is usually a repeating pattern.
- *
- * Note: the fully opaque pattern (0xffff) has been disabled in order
- * to work around a conformance issue.
+ * Polygon state
  */
+
 static int mgaStipples[16] = {
-   0xffff1,  /* See above note */
+   0xffff,
    0xa5a5,
    0x5a5a,
    0xa0a0,
@@ -682,6 +414,14 @@ static int mgaStipples[16] = {
    0x0000
 };
 
+/**
+ * The MGA supports a subset of possible 4x4 stipples natively, GL
+ * wants 32x32.  Fortunately stipple is usually a repeating pattern.
+ *
+ * \param ctx GL rendering context to be affected
+ * \param mask Pointer to the 32x32 stipple mask
+ */
+
 static void mgaDDPolygonStipple( GLcontext *ctx, const GLubyte *mask )
 {
    mgaContextPtr mmesa = MGA_CONTEXT(ctx);
@@ -730,93 +470,208 @@ static void mgaDDPolygonStipple( GLcontext *ctx, const GLubyte *mask )
    }
 }
 
+
 /* =============================================================
+ * Rendering attributes
+ *
+ * We really don't want to recalculate all this every time we bind a
+ * texture.  These things shouldn't change all that often, so it makes
+ * sense to break them out of the core texture state update routines.
  */
 
-static void mgaDDPrintDirty( const char *msg, GLuint state )
+static void updateSpecularLighting( GLcontext *ctx )
 {
-   fprintf(stderr, "%s (0x%x): %s%s%s%s%s%s%s\n",
-          msg,
-          (unsigned int) state,
-          (state & MGA_WAIT_AGE) ? "wait-age, " : "",
-          (state & MGA_UPLOAD_TEX0IMAGE)  ? "upload-tex0-img, " : "",
-          (state & MGA_UPLOAD_TEX1IMAGE)  ? "upload-tex1-img, " : "",
-          (state & MGA_UPLOAD_CONTEXT)        ? "upload-ctx, " : "",
-          (state & MGA_UPLOAD_TEX0)       ? "upload-tex0, " : "",
-          (state & MGA_UPLOAD_TEX1)       ? "upload-tex1, " : "",
-          (state & MGA_UPLOAD_PIPE)       ? "upload-pipe, " : ""
-      );
+   mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+   unsigned int specen;
+
+   specen = NEED_SECONDARY_COLOR(ctx) ? TMC_specen_enable : 0;
+
+   if ( specen != mmesa->hw.specen ) {
+      mmesa->hw.specen = specen;
+      mmesa->dirty |= MGA_UPLOAD_TEX0 | MGA_UPLOAD_TEX1;
+   }
 }
 
-/* Push the state into the sarea and/or texture memory.
+
+/* =============================================================
+ * Materials
  */
-void mgaEmitHwStateLocked( mgaContextPtr mmesa )
+
+
+static void mgaDDLightModelfv(GLcontext *ctx, GLenum pname,
+                             const GLfloat *param)
 {
-   MGASAREAPrivPtr sarea = mmesa->sarea;
+   if (pname == GL_LIGHT_MODEL_COLOR_CONTROL) {
+      FLUSH_BATCH( MGA_CONTEXT(ctx) );
+      updateSpecularLighting( ctx );
+   }
+}
 
-   if (MGA_DEBUG & DEBUG_VERBOSE_MSG)
-      mgaDDPrintDirty( "mgaEmitHwStateLocked", mmesa->dirty );
 
-   if ((mmesa->dirty & MGA_UPLOAD_TEX0IMAGE) && mmesa->CurrentTexObj[0])
-      mgaUploadTexImages(mmesa, mmesa->CurrentTexObj[0]);
+/* =============================================================
+ * Stencil
+ */
+
 
-   if ((mmesa->dirty & MGA_UPLOAD_TEX1IMAGE) && mmesa->CurrentTexObj[1])
-      mgaUploadTexImages(mmesa, mmesa->CurrentTexObj[1]);
+static void mgaDDStencilFunc(GLcontext *ctx, GLenum func, GLint ref,
+                            GLuint mask)
+{
+   mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+   GLuint  stencil;
+   GLuint  stencilctl;
 
-   if (mmesa->dirty & MGA_UPLOAD_CONTEXT) {
-      memcpy( &sarea->ContextState, &mmesa->setup, sizeof(mmesa->setup));
+   stencil = MGA_FIELD( S_sref, ref ) | MGA_FIELD( S_smsk, mask );
+   switch (func)
+   {
+   case GL_NEVER:
+      stencilctl = SC_smode_snever;
+      break;
+   case GL_LESS:
+      stencilctl = SC_smode_slt;
+      break;
+   case GL_LEQUAL:
+      stencilctl = SC_smode_slte;
+      break;
+   case GL_GREATER:
+      stencilctl = SC_smode_sgt;
+      break;
+   case GL_GEQUAL:
+      stencilctl = SC_smode_sgte;
+      break;
+   case GL_NOTEQUAL:
+      stencilctl = SC_smode_sne;
+      break;
+   case GL_EQUAL:
+      stencilctl = SC_smode_se;
+      break;
+   case GL_ALWAYS:
+   default:
+      stencilctl = SC_smode_salways;
+      break;
    }
 
-   if ((mmesa->dirty & MGA_UPLOAD_TEX0) && mmesa->CurrentTexObj[0]) {
-      memcpy(&sarea->TexState[0],
-            &mmesa->CurrentTexObj[0]->setup,
-            sizeof(sarea->TexState[0]));
-   }
+   MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
+   mmesa->hw.stencil &= (S_sref_MASK & S_smsk_MASK);
+   mmesa->hw.stencil |= stencil;
+   mmesa->hw.stencilctl &= SC_smode_MASK;
+   mmesa->hw.stencilctl |= stencilctl;
+}
 
-   if ((mmesa->dirty & MGA_UPLOAD_TEX1) && mmesa->CurrentTexObj[1]) {
-      memcpy(&sarea->TexState[1],
-            &mmesa->CurrentTexObj[1]->setup,
-            sizeof(sarea->TexState[1]));
-   }
+static void mgaDDStencilMask(GLcontext *ctx, GLuint mask)
+{
+   mgaContextPtr mmesa = MGA_CONTEXT(ctx);
 
-   if (sarea->TexState[0].texctl2 !=
-       sarea->TexState[1].texctl2) {
-      memcpy(&sarea->TexState[1],
-            &sarea->TexState[0],
-            sizeof(sarea->TexState[0]));
-      mmesa->dirty |= MGA_UPLOAD_TEX1|MGA_UPLOAD_TEX0;
-   }
+   MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
+   mmesa->hw.stencil &= S_swtmsk_MASK;
+   mmesa->hw.stencil |= MGA_FIELD( S_swtmsk, mask );
+}
 
-   if (mmesa->dirty & MGA_UPLOAD_PIPE) {
-/*        mmesa->sarea->wacceptseq = mmesa->hw_primitive; */
-      mmesa->sarea->WarpPipe = mmesa->vertex_format;
-      mmesa->sarea->vertsize = mmesa->vertex_size;
-   }
+static void mgaDDStencilOp(GLcontext *ctx, GLenum fail, GLenum zfail,
+                          GLenum zpass)
+{
+   mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+   GLuint  stencilctl;
 
-   mmesa->sarea->dirty |= mmesa->dirty;
+   stencilctl = 0;
+   switch (ctx->Stencil.FailFunc[0])
+   {
+   case GL_KEEP:
+      stencilctl |= SC_sfailop_keep;
+      break;
+   case GL_ZERO:
+      stencilctl |= SC_sfailop_zero;
+      break;
+   case GL_REPLACE:
+      stencilctl |= SC_sfailop_replace;
+      break;
+   case GL_INCR:
+      stencilctl |= SC_sfailop_incrsat;
+      break;
+   case GL_DECR:
+      stencilctl |= SC_sfailop_decrsat;
+      break;
+   case GL_INCR_WRAP:
+      stencilctl |= SC_sfailop_incr;
+      break;
+   case GL_DECR_WRAP:
+      stencilctl |= SC_sfailop_decr;
+      break;
+   case GL_INVERT:
+      stencilctl |= SC_sfailop_invert;
+      break;
+   default:
+      break;
+   }
 
-   mmesa->dirty &= (MGA_UPLOAD_CLIPRECTS|MGA_WAIT_AGE);
+   switch (ctx->Stencil.ZFailFunc[0])
+   {
+   case GL_KEEP:
+      stencilctl |= SC_szfailop_keep;
+      break;
+   case GL_ZERO:
+      stencilctl |= SC_szfailop_zero;
+      break;
+   case GL_REPLACE:
+      stencilctl |= SC_szfailop_replace;
+      break;
+   case GL_INCR:
+      stencilctl |= SC_szfailop_incrsat;
+      break;
+   case GL_DECR:
+      stencilctl |= SC_szfailop_decrsat;
+      break;
+   case GL_INCR_WRAP:
+      stencilctl |= SC_szfailop_incr;
+      break;
+   case GL_DECR_WRAP:
+      stencilctl |= SC_szfailop_decr;
+      break;
+   case GL_INVERT:
+      stencilctl |= SC_szfailop_invert;
+      break;
+   default:
+      break;
+   }
 
-   /* This is a bit of a hack but seems to be the best place to ensure
-    * that separate specular is disabled when not needed.
-    */
-   if (mmesa->glCtx->Texture.Unit[0]._ReallyEnabled == 0 ||
-       !mmesa->glCtx->Light.Enabled ||
-       mmesa->glCtx->Light.Model.ColorControl == GL_SINGLE_COLOR) {
-      sarea->TexState[0].texctl2 &= ~TMC_specen_enable;
-      sarea->TexState[1].texctl2 &= ~TMC_specen_enable;
+   switch (ctx->Stencil.ZPassFunc[0])
+   {
+   case GL_KEEP:
+      stencilctl |= SC_szpassop_keep;
+      break;
+   case GL_ZERO:
+      stencilctl |= SC_szpassop_zero;
+      break;
+   case GL_REPLACE:
+      stencilctl |= SC_szpassop_replace;
+      break;
+   case GL_INCR:
+      stencilctl |= SC_szpassop_incrsat;
+      break;
+   case GL_DECR:
+      stencilctl |= SC_szpassop_decrsat;
+      break;
+   case GL_INCR_WRAP:
+      stencilctl |= SC_szpassop_incr;
+      break;
+   case GL_DECR_WRAP:
+      stencilctl |= SC_szpassop_decr;
+      break;
+   case GL_INVERT:
+      stencilctl |= SC_szpassop_invert;
+      break;
+   default:
+      break;
    }
-}
 
-/* Fallback to swrast for select and feedback.
- */
-static void mgaRenderMode( GLcontext *ctx, GLenum mode )
-{
-   FALLBACK( ctx, MGA_FALLBACK_RENDERMODE, (mode != GL_RENDER) );
+   MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
+   mmesa->hw.stencilctl &= (SC_sfailop_MASK & SC_szfailop_MASK 
+                           & SC_szpassop_MASK);
+   mmesa->hw.stencilctl |= stencilctl;
 }
 
 
 /* =============================================================
+ * Window position and viewport transformation
  */
 
 void mgaCalcViewport( GLcontext *ctx )
@@ -841,6 +696,8 @@ static void mgaViewport( GLcontext *ctx,
                          GLint x, GLint y, 
                          GLsizei width, GLsizei height )
 {
+   /* update size of Mesa/software ancillary buffers */
+   _mesa_ResizeBuffersMESA();
    mgaCalcViewport( ctx );
 }
 
@@ -850,39 +707,196 @@ static void mgaDepthRange( GLcontext *ctx,
    mgaCalcViewport( ctx );
 }
 
+
+/* =============================================================
+ * Miscellaneous
+ */
+
+static void mgaDDClearColor(GLcontext *ctx, 
+                           const GLfloat color[4] )
+{
+   mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+   GLubyte c[4];
+   CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]);
+   CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]);
+   CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]);
+   CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]);
+
+   mmesa->ClearColor = mgaPackColor( mmesa->mgaScreen->cpp,
+                                    c[0], c[1], c[2], c[3]);
+}
+
+
+/* Fallback to swrast for select and feedback.
+ */
+static void mgaRenderMode( GLcontext *ctx, GLenum mode )
+{
+   FALLBACK( ctx, MGA_FALLBACK_RENDERMODE, (mode != GL_RENDER) );
+}
+
+
+static void mgaDDLogicOp( GLcontext *ctx, GLenum opcode )
+{
+   mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+
+   MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
+   mmesa->hw.rop = mgarop_NoBLK[ opcode & 0x0f ];
+}
+
+
+static void mgaXMesaSetFrontClipRects( mgaContextPtr mmesa )
+{
+   __DRIdrawablePrivate *driDrawable = mmesa->driDrawable;
+
+   if (driDrawable->numClipRects == 0) {
+       static drm_clip_rect_t zeroareacliprect = {0,0,0,0};
+       mmesa->numClipRects = 1;
+       mmesa->pClipRects = &zeroareacliprect;
+   } else {
+       mmesa->numClipRects = driDrawable->numClipRects;
+       mmesa->pClipRects = driDrawable->pClipRects;
+   }
+   mmesa->drawX = driDrawable->x;
+   mmesa->drawY = driDrawable->y;
+
+   mmesa->setup.dstorg = mmesa->drawOffset;
+   mmesa->dirty |= MGA_UPLOAD_CONTEXT | MGA_UPLOAD_CLIPRECTS;
+}
+
+
+static void mgaXMesaSetBackClipRects( mgaContextPtr mmesa )
+{
+   __DRIdrawablePrivate *driDrawable = mmesa->driDrawable;
+
+   if (driDrawable->numBackClipRects == 0)
+   {
+      if (driDrawable->numClipRects == 0) {
+         static drm_clip_rect_t zeroareacliprect = {0,0,0,0};
+         mmesa->numClipRects = 1;
+         mmesa->pClipRects = &zeroareacliprect;
+      } else {
+         mmesa->numClipRects = driDrawable->numClipRects;
+         mmesa->pClipRects = driDrawable->pClipRects;
+      }
+      mmesa->drawX = driDrawable->x;
+      mmesa->drawY = driDrawable->y;
+   } else {
+      mmesa->numClipRects = driDrawable->numBackClipRects;
+      mmesa->pClipRects = driDrawable->pBackClipRects;
+      mmesa->drawX = driDrawable->backX;
+      mmesa->drawY = driDrawable->backY;
+   }
+
+   mmesa->setup.dstorg = mmesa->drawOffset;
+   mmesa->dirty |= MGA_UPLOAD_CONTEXT | MGA_UPLOAD_CLIPRECTS;
+}
+
+
+void mgaUpdateRects( mgaContextPtr mmesa, GLuint buffers )
+{
+   __DRIdrawablePrivate *driDrawable = mmesa->driDrawable;
+   drm_mga_sarea_t *sarea = mmesa->sarea;
+
+
+   DRI_VALIDATE_DRAWABLE_INFO(mmesa->driScreen, driDrawable); 
+   mmesa->dirty_cliprects = 0; 
+
+   if (mmesa->draw_buffer == MGA_FRONT)
+      mgaXMesaSetFrontClipRects( mmesa );
+   else
+      mgaXMesaSetBackClipRects( mmesa );
+
+   sarea->req_drawable = driDrawable->draw;
+   sarea->req_draw_buffer = mmesa->draw_buffer;
+
+   mgaUpdateClipping( mmesa->glCtx );
+   mgaCalcViewport( mmesa->glCtx );
+
+   mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
+}
+
+
+static void mgaDDDrawBuffer(GLcontext *ctx, GLenum mode )
+{
+   mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+
+   FLUSH_BATCH( mmesa );
+
+   /*
+    * _DrawDestMask is easier to cope with than <mode>.
+    */
+   switch ( ctx->DrawBuffer->_ColorDrawBufferMask[0] ) {
+   case BUFFER_BIT_FRONT_LEFT:
+      mmesa->setup.dstorg = mmesa->mgaScreen->frontOffset;
+      mmesa->dirty |= MGA_UPLOAD_CONTEXT;
+      mmesa->draw_buffer = MGA_FRONT;
+      mgaXMesaSetFrontClipRects( mmesa );
+      FALLBACK( ctx, MGA_FALLBACK_DRAW_BUFFER, GL_FALSE );
+      break;
+   case BUFFER_BIT_BACK_LEFT:
+      mmesa->setup.dstorg = mmesa->mgaScreen->backOffset;
+      mmesa->draw_buffer = MGA_BACK;
+      mmesa->dirty |= MGA_UPLOAD_CONTEXT;
+      mgaXMesaSetBackClipRects( mmesa );
+      FALLBACK( ctx, MGA_FALLBACK_DRAW_BUFFER, GL_FALSE );
+      break;
+   default:
+      /* GL_NONE or GL_FRONT_AND_BACK or stereo left&right, etc */
+      FALLBACK( ctx, MGA_FALLBACK_DRAW_BUFFER, GL_TRUE );
+      return;
+   }
+
+   /* We want to update the s/w rast state too so that r200SetBuffer()
+    * gets called.
+    */
+   _swrast_DrawBuffer(ctx, mode);
+}
+
+
+static void mgaDDReadBuffer(GLcontext *ctx, GLenum mode )
+{
+   /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */
+}
+
+
 /* =============================================================
+ * State enable/disable
  */
 
+
 static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state)
 {
    mgaContextPtr mmesa = MGA_CONTEXT( ctx );
 
    switch(cap) {
-   case GL_ALPHA_TEST:
-      FLUSH_BATCH( mmesa );
-      mmesa->new_state |= MGA_NEW_ALPHA;
+   case GL_DITHER:
+      MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
+      if (!ctx->Color.DitherFlag)
+        mmesa->setup.maccess |= MA_nodither_enable;
+      else
+        mmesa->setup.maccess &= ~MA_nodither_enable;
       break;
-   case GL_BLEND:
+   case GL_LIGHTING:
+   case GL_COLOR_SUM_EXT:
       FLUSH_BATCH( mmesa );
-      mmesa->new_state |= MGA_NEW_ALPHA;
-
-      /* For some reason enable(GL_BLEND) affects ColorLogicOpEnabled.
-       */
-      FALLBACK( ctx, MGA_FALLBACK_LOGICOP,
-               (ctx->Color.ColorLogicOpEnabled && 
-                ctx->Color.LogicOp != GL_COPY));
+      updateSpecularLighting( ctx );
+      break;
+   case GL_ALPHA_TEST:
+      MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
+      mmesa->hw.alpha_func_enable = (state) ? ~0 : 0;
       break;
    case GL_DEPTH_TEST:
-      FLUSH_BATCH( mmesa );
-      mmesa->new_state |= MGA_NEW_DEPTH;
+      MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
       FALLBACK (ctx, MGA_FALLBACK_DEPTH,
                ctx->Depth.Func == GL_NEVER && ctx->Depth.Test);
       break;
+
    case GL_SCISSOR_TEST:
       FLUSH_BATCH( mmesa );
       mmesa->scissor = state;
-      mmesa->new_state |= MGA_NEW_CLIP;
+      mgaUpdateClipping( ctx );
       break;
+
    case GL_FOG:
       MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
       if (ctx->Fog.Enabled) 
@@ -891,39 +905,34 @@ static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state)
         mmesa->setup.maccess &= ~MA_fogen_enable;
       break;
    case GL_CULL_FACE:
-      FLUSH_BATCH( mmesa );
-      mmesa->new_state |= MGA_NEW_CULL;
+      mgaDDCullFaceFrontFace( ctx, 0 );
       break;
    case GL_TEXTURE_1D:
    case GL_TEXTURE_2D:
    case GL_TEXTURE_3D:
-      FLUSH_BATCH( mmesa );
-      mmesa->new_state |= (MGA_NEW_TEXTURE|MGA_NEW_ALPHA);
       break;
    case GL_POLYGON_STIPPLE:
       if (mmesa->haveHwStipple && mmesa->raster_primitive == GL_TRIANGLES) {
-        FLUSH_BATCH(mmesa);
-        mmesa->dirty |= MGA_UPLOAD_CONTEXT;
+        MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
         mmesa->setup.dwgctl &= ~(0xf<<20);
         if (state)
            mmesa->setup.dwgctl |= mmesa->poly_stipple;
       }
       break;
+
+   case GL_BLEND:
    case GL_COLOR_LOGIC_OP:
-      FLUSH_BATCH( mmesa );
-#if !defined(ACCEL_ROP)
-      FALLBACK( ctx, MGA_FALLBACK_LOGICOP, 
-               (state && ctx->Color.LogicOp != GL_COPY));
-#else
-      mmesa->new_state |= MGA_NEW_DEPTH;
-#endif
+      updateBlendLogicOp( ctx );
       break;
+
    case GL_STENCIL_TEST:
-      FLUSH_BATCH( mmesa );
-      if (mmesa->hw_stencil)
-        mmesa->new_state |= MGA_NEW_STENCIL;
-      else
+      MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT );
+      if (mmesa->hw_stencil) {
+        mmesa->hw.stencil_enable = ( state ) ? ~0 : 0;
+      }
+      else {
         FALLBACK( ctx, MGA_FALLBACK_STENCIL, state );
+      }
    default:
       break;
    }
@@ -933,56 +942,124 @@ static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state)
 /* =============================================================
  */
 
-
-
-/* =============================================================
- */
-
-static void mgaDDPrintState( const char *msg, GLuint state )
+static void mgaDDPrintDirty( const char *msg, GLuint state )
 {
-   fprintf(stderr, "%s (0x%x): %s%s%s%s%s%s\n",
+   fprintf(stderr, "%s (0x%03x): %s%s%s%s%s%s%s\n",
           msg,
-          state,
-          (state & MGA_NEW_DEPTH)   ? "depth, " : "",
-          (state & MGA_NEW_ALPHA)   ? "alpha, " : "",
-          (state & MGA_NEW_CLIP)    ? "clip, " : "",
-          (state & MGA_NEW_CULL)    ? "cull, " : "",
-          (state & MGA_NEW_TEXTURE) ? "texture, " : "",
-          (state & MGA_NEW_CONTEXT) ? "context, " : "");
+          (unsigned int) state,
+          (state & MGA_WAIT_AGE)          ? "wait-age " : "",
+          (state & MGA_UPLOAD_TEX0IMAGE)  ? "upload-tex0-img " : "",
+          (state & MGA_UPLOAD_TEX1IMAGE)  ? "upload-tex1-img " : "",
+          (state & MGA_UPLOAD_CONTEXT)    ? "upload-ctx " : "",
+          (state & MGA_UPLOAD_TEX0)       ? "upload-tex0 " : "",
+          (state & MGA_UPLOAD_TEX1)       ? "upload-tex1 " : "",
+          (state & MGA_UPLOAD_PIPE)       ? "upload-pipe " : ""
+      );
 }
 
-void mgaDDUpdateHwState( GLcontext *ctx )
+/* Push the state into the sarea and/or texture memory.
+ */
+void mgaEmitHwStateLocked( mgaContextPtr mmesa )
 {
-   mgaContextPtr mmesa = MGA_CONTEXT( ctx );
-   int new_state = mmesa->new_state;
+   drm_mga_sarea_t *sarea = mmesa->sarea;
+   GLcontext * ctx = mmesa->glCtx;
 
-   if (new_state)
-   {
-      FLUSH_BATCH( mmesa );
+   if (MGA_DEBUG & DEBUG_VERBOSE_MSG)
+      mgaDDPrintDirty( __FUNCTION__, mmesa->dirty );
+
+   if (mmesa->dirty & MGA_UPLOAD_CONTEXT) {
+      mmesa->setup.wflag = _CULL_DISABLE;
+      if (mmesa->raster_primitive == GL_TRIANGLES) {
+        if ((ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT &&
+             ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT)) {
+           mmesa->setup.wflag = mmesa->hw.cull_dualtex;
+        }
+        else {
+           mmesa->setup.wflag = mmesa->hw.cull;
+        }
+      }
+
+      mmesa->setup.stencil = mmesa->hw.stencil 
+         & mmesa->hw.stencil_enable;
+      mmesa->setup.stencilctl = mmesa->hw.stencilctl
+         & mmesa->hw.stencil_enable;
+
+      /* If depth testing is not enabled, then use the no Z-compare / no
+       * Z-write mode.  Otherwise, use whatever is set in hw.zmode.
+       */
+      mmesa->setup.dwgctl &= (DC_zmode_MASK & DC_atype_MASK);
+      mmesa->setup.dwgctl |= (ctx->Depth.Test)
+         ? mmesa->hw.zmode : (DC_zmode_nozcmp | DC_atype_i);
+
+      mmesa->setup.dwgctl &= DC_bop_MASK;
+      mmesa->setup.dwgctl |= (ctx->Color._LogicOpEnabled)
+         ? mmesa->hw.rop : mgarop_NoBLK[ GL_COPY & 0x0f ];
+
+      mmesa->setup.alphactrl &= AC_src_MASK & AC_dst_MASK & AC_atmode_MASK
+        & AC_atref_MASK & AC_alphasel_MASK;
+      mmesa->setup.alphactrl |= 
+        (mmesa->hw.alpha_func & mmesa->hw.alpha_func_enable) |
+        (mmesa->hw.blend_func & mmesa->hw.blend_func_enable) |
+        ((AC_src_one | AC_dst_zero) & ~mmesa->hw.blend_func_enable) |
+        mmesa->hw.alpha_sel;
+
+      memcpy( &sarea->context_state, &mmesa->setup, sizeof(mmesa->setup));
+   }
+
+   if ((mmesa->dirty & MGA_UPLOAD_TEX0) && mmesa->CurrentTexObj[0]) {
+      memcpy(&sarea->tex_state[0],
+            &mmesa->CurrentTexObj[0]->setup,
+            sizeof(sarea->tex_state[0]));
+   }
+
+   if ((mmesa->dirty & MGA_UPLOAD_TEX1) && mmesa->CurrentTexObj[1]) {
+      memcpy(&sarea->tex_state[1],
+            &mmesa->CurrentTexObj[1]->setup,
+            sizeof(sarea->tex_state[1]));
+   }
+
+   if (mmesa->dirty & (MGA_UPLOAD_TEX0 | MGA_UPLOAD_TEX1)) {
+      sarea->tex_state[0].texctl2 &= ~TMC_specen_enable;
+      sarea->tex_state[1].texctl2 &= ~TMC_specen_enable;
+      sarea->tex_state[0].texctl2 |= mmesa->hw.specen;
+      sarea->tex_state[1].texctl2 |= mmesa->hw.specen;
+   }
+
+   if (mmesa->dirty & MGA_UPLOAD_PIPE) {
+/*        mmesa->sarea->wacceptseq = mmesa->hw_primitive; */
+      mmesa->sarea->warp_pipe = mmesa->vertex_format;
+      mmesa->sarea->vertsize = mmesa->vertex_size;
+   }
 
-      mmesa->new_state = 0;
+   mmesa->sarea->dirty |= mmesa->dirty;
+   mmesa->dirty &= MGA_UPLOAD_CLIPRECTS;
+}
 
-      if (MESA_VERBOSE&VERBOSE_DRIVER)
-        mgaDDPrintState("UpdateHwState", new_state);
+/* =============================================================
+ */
 
-      if (new_state & MGA_NEW_DEPTH)
-        mgaUpdateZMode(ctx);
 
-      if (new_state & MGA_NEW_ALPHA)
-        mgaUpdateAlphaMode(ctx);
+static void mgaDDValidateState( GLcontext *ctx )
+{
+   mgaContextPtr mmesa = MGA_CONTEXT( ctx );
 
-      if (new_state & MGA_NEW_CLIP)
-        mgaUpdateClipping(ctx);
+   FLUSH_BATCH( mmesa );
 
-      if (new_state & MGA_NEW_STENCIL)
-        mgaUpdateStencil(ctx);
+   if (mmesa->NewGLState & _NEW_TEXTURE) {
+      mgaUpdateTextureState(ctx);
+   }
 
-      if (new_state & (MGA_NEW_WARP|MGA_NEW_CULL))
-        mgaUpdateCull(ctx);
+   if (!mmesa->Fallback) {
+      if (mmesa->NewGLState & _MGA_NEW_RASTERSETUP) {
+         mgaChooseVertexState( ctx );
+      }
 
-      if (new_state & (MGA_NEW_WARP|MGA_NEW_TEXTURE))
-        mgaUpdateTextureState(ctx);
+      if (mmesa->NewGLState & _MGA_NEW_RENDERSTATE) {
+         mgaChooseRenderState( ctx );
+      }
    }
+
+   mmesa->NewGLState = 0;
 }
 
 
@@ -992,25 +1069,40 @@ static void mgaDDInvalidateState( GLcontext *ctx, GLuint new_state )
    _swsetup_InvalidateState( ctx, new_state );
    _ac_InvalidateState( ctx, new_state );
    _tnl_InvalidateState( ctx, new_state );
-   MGA_CONTEXT(ctx)->new_gl_state |= new_state;
+   MGA_CONTEXT(ctx)->NewGLState |= new_state;
 }
 
 
+static void mgaRunPipeline( GLcontext *ctx )
+{
+   mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+
+   if (mmesa->NewGLState) {
+      mgaDDValidateState( ctx );
+   }
+
+   if (mmesa->dirty) {
+       mgaEmitHwStateLocked( mmesa );
+   }
+
+   _tnl_run_pipeline( ctx );
+}
+
 
 void mgaInitState( mgaContextPtr mmesa )
 {
    mgaScreenPrivate *mgaScreen = mmesa->mgaScreen;
    GLcontext *ctx = mmesa->glCtx;
 
-   if (ctx->Color._DrawDestMask == BACK_LEFT_BIT) {
+   if (ctx->Visual.doubleBufferMode) {
+      /* use back buffer by default */
       mmesa->draw_buffer = MGA_BACK;
-      mmesa->read_buffer = MGA_BACK;
       mmesa->drawOffset = mmesa->mgaScreen->backOffset;
       mmesa->readOffset = mmesa->mgaScreen->backOffset;
       mmesa->setup.dstorg = mgaScreen->backOffset;
    } else {
+      /* use front buffer by default */
       mmesa->draw_buffer = MGA_FRONT;
-      mmesa->read_buffer = MGA_FRONT;
       mmesa->drawOffset = mmesa->mgaScreen->frontOffset;
       mmesa->readOffset = mmesa->mgaScreen->frontOffset;
       mmesa->setup.dstorg = mgaScreen->frontOffset;
@@ -1021,6 +1113,9 @@ void mgaInitState( mgaContextPtr mmesa )
                           MA_tlutload_disable |
                           MA_nodither_disable |
                           MA_dit555_disable);
+   if (driQueryOptioni (&mmesa->optionCache, "color_reduction") !=
+       DRI_CONF_COLOR_REDUCTION_DITHER)
+      mmesa->setup.maccess |= MA_nodither_enable;
 
    switch (mmesa->mgaScreen->cpp) {
    case 2:
@@ -1043,45 +1138,56 @@ void mgaInitState( mgaContextPtr mmesa )
       mmesa->setup.maccess |= MA_zwidth_24;
       break;
    case 32:
-      mmesa->setup.maccess |= MA_pwidth_32;
+      mmesa->setup.maccess |= MA_zwidth_32;
       break;
    }
 
+   mmesa->hw.blend_func = AC_src_one | AC_dst_zero;
+   mmesa->hw.blend_func_enable = 0;
+   mmesa->hw.alpha_func = AC_atmode_noacmp | MGA_FIELD( AC_atref, 0x00 );
+   mmesa->hw.alpha_func_enable = 0;
+   mmesa->hw.rop = mgarop_NoBLK[ GL_COPY & 0x0f ];
+   mmesa->hw.zmode = DC_zmode_zlt | DC_atype_zi;
+   mmesa->hw.stencil = MGA_FIELD( S_sref, 0x00) | MGA_FIELD( S_smsk, 0xff ) |
+      MGA_FIELD( S_swtmsk, 0xff );
+   mmesa->hw.stencilctl = SC_smode_salways | SC_sfailop_keep 
+      | SC_szfailop_keep | SC_szpassop_keep;
+   mmesa->hw.stencil_enable = 0;
+   mmesa->hw.cull = _CULL_DISABLE;
+   mmesa->hw.cull_dualtex = _CULL_DISABLE;
+   mmesa->hw.specen = 0;
+   mmesa->hw.alpha_sel = AC_alphasel_diffused;
+
    mmesa->setup.dwgctl = (DC_opcod_trap |
-                         DC_atype_i |
                          DC_linear_xy |
-                         DC_zmode_nozcmp |
                          DC_solid_disable |
                          DC_arzero_disable |
                          DC_sgnzero_disable |
                          DC_shftzero_enable |
-                         (0xC << DC_bop_SHIFT) |
-                         (0x0 << DC_trans_SHIFT) |
+                         MGA_FIELD( DC_bop, 0xC ) |
+                         MGA_FIELD( DC_trans, 0x0 ) |
                          DC_bltmod_bmonolef |
                          DC_pattern_disable |
                          DC_transc_disable |
                          DC_clipdis_disable);
 
-
    mmesa->setup.plnwt = ~0;
-   mmesa->setup.alphactrl = ( AC_src_one |
-                             AC_dst_zero |
-                             AC_amode_FCOL |
-                             AC_astipple_disable |
-                             AC_aten_disable |
-                             AC_atmode_noacmp |
-                             AC_alphasel_fromtex );
-
-   mmesa->setup.fogcolor =
-      MGAPACKCOLOR888((GLubyte)(ctx->Fog.Color[0]*255.0F),
-                     (GLubyte)(ctx->Fog.Color[1]*255.0F),
-                     (GLubyte)(ctx->Fog.Color[2]*255.0F));
+   mmesa->setup.alphactrl = (AC_amode_alpha_channel |
+                            AC_astipple_disable |
+                            AC_aten_disable);
+
+   mmesa->setup.fogcolor = PACK_COLOR_888((GLubyte)(ctx->Fog.Color[0]*255.0F),
+                                         (GLubyte)(ctx->Fog.Color[1]*255.0F),
+                                         (GLubyte)(ctx->Fog.Color[2]*255.0F));
 
    mmesa->setup.wflag = 0;
    mmesa->setup.tdualstage0 = 0;
    mmesa->setup.tdualstage1 = 0;
    mmesa->setup.fcol = 0;
-   mmesa->new_state = ~0;
+   mmesa->dirty |= MGA_UPLOAD_CONTEXT;
+
+   mmesa->envcolor[0] = 0;
+   mmesa->envcolor[1] = 0;
 }
 
 
@@ -1091,20 +1197,18 @@ void mgaDDInitStateFuncs( GLcontext *ctx )
    ctx->Driver.Enable = mgaDDEnable;
    ctx->Driver.LightModelfv = mgaDDLightModelfv;
    ctx->Driver.AlphaFunc = mgaDDAlphaFunc;
-   ctx->Driver.BlendEquation = mgaDDBlendEquation;
-   ctx->Driver.BlendFunc = mgaDDBlendFunc;
+   ctx->Driver.BlendEquationSeparate = mgaDDBlendEquationSeparate;
    ctx->Driver.BlendFuncSeparate = mgaDDBlendFuncSeparate;
    ctx->Driver.DepthFunc = mgaDDDepthFunc;
    ctx->Driver.DepthMask = mgaDDDepthMask;
    ctx->Driver.Fogfv = mgaDDFogfv;
    ctx->Driver.Scissor = mgaDDScissor;
-   ctx->Driver.ShadeModel = mgaDDShadeModel;
    ctx->Driver.CullFace = mgaDDCullFaceFrontFace;
    ctx->Driver.FrontFace = mgaDDCullFaceFrontFace;
    ctx->Driver.ColorMask = mgaDDColorMask;
 
-   ctx->Driver.DrawBuffer = mgaDDSetDrawBuffer;
-   ctx->Driver.ReadBuffer = mgaDDSetReadBuffer;
+   ctx->Driver.DrawBuffer = mgaDDDrawBuffer;
+   ctx->Driver.ReadBuffer = mgaDDReadBuffer;
    ctx->Driver.ClearColor = mgaDDClearColor;
    ctx->Driver.ClearDepth = mgaDDClearDepth;
    ctx->Driver.LogicOpcode = mgaDDLogicOp;
@@ -1128,4 +1232,6 @@ void mgaDDInitStateFuncs( GLcontext *ctx )
    ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable;
    ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D;
    ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D;
+
+   TNL_CONTEXT(ctx)->Driver.RunPipeline = mgaRunPipeline;
 }