switch to using driFillInModes fix depthbuffer = 0
[mesa.git] / src / mesa / swrast / s_span.c
index b134890a3b28f00e2da5610de4f0927c2bb83e9c..41db42e2b80726689fe1b1fdf39acdb224fab2f3 100644 (file)
@@ -1,10 +1,8 @@
-/* $Id: s_span.c,v 1.48 2002/10/02 23:24:04 brianp Exp $ */
-
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  6.1
  *
- * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -36,8 +34,7 @@
 #include "colormac.h"
 #include "context.h"
 #include "macros.h"
-#include "mmath.h"
-#include "mem.h"
+#include "imports.h"
 
 #include "s_alpha.h"
 #include "s_alphabuf.h"
@@ -47,6 +44,7 @@
 #include "s_fog.h"
 #include "s_logic.h"
 #include "s_masking.h"
+#include "s_nvfragprog.h"
 #include "s_span.h"
 #include "s_stencil.h"
 #include "s_texture.h"
  * Used during setup for glDraw/CopyPixels.
  */
 void
-_mesa_span_default_z( GLcontext *ctx, struct sw_span *span )
+_swrast_span_default_z( GLcontext *ctx, struct sw_span *span )
 {
    if (ctx->Visual.depthBits <= 16)
-      span->z = FloatToFixed(ctx->Current.RasterPos[2] * ctx->DepthMax);
+      span->z = FloatToFixed(ctx->Current.RasterPos[2] * ctx->DepthMax + 0.5F);
    else
-      span->z = (GLint) (ctx->Current.RasterPos[2] * ctx->DepthMax);
+      span->z = (GLint) (ctx->Current.RasterPos[2] * ctx->DepthMax + 0.5F);
    span->zStep = 0;
    span->interpMask |= SPAN_Z;
 }
@@ -73,10 +71,10 @@ _mesa_span_default_z( GLcontext *ctx, struct sw_span *span )
  * Used during setup for glDraw/CopyPixels.
  */
 void
-_mesa_span_default_fog( GLcontext *ctx, struct sw_span *span )
+_swrast_span_default_fog( GLcontext *ctx, struct sw_span *span )
 {
-   span->fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
-   span->fogStep = 0;
+   span->fog = _swrast_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
+   span->fogStep = span->dfogdx = span->dfogdy = 0.0F;
    span->interpMask |= SPAN_FOG;
 }
 
@@ -86,7 +84,7 @@ _mesa_span_default_fog( GLcontext *ctx, struct sw_span *span )
  * Used during setup for glDraw/CopyPixels.
  */
 void
-_mesa_span_default_color( GLcontext *ctx, struct sw_span *span )
+_swrast_span_default_color( GLcontext *ctx, struct sw_span *span )
 {
    if (ctx->Visual.rgbMode) {
       GLchan r, g, b, a;
@@ -112,7 +110,7 @@ _mesa_span_default_color( GLcontext *ctx, struct sw_span *span )
       span->interpMask |= SPAN_RGBA;
    }
    else {
-      span->index = IntToFixed(ctx->Current.RasterIndex);
+      span->index = FloatToFixed(ctx->Current.RasterIndex);
       span->indexStep = 0;
       span->interpMask |= SPAN_INDEX;
    }
@@ -124,11 +122,21 @@ _mesa_span_default_color( GLcontext *ctx, struct sw_span *span )
  * Used during setup for glDraw/CopyPixels.
  */
 void
-_mesa_span_default_texcoords( GLcontext *ctx, struct sw_span *span )
+_swrast_span_default_texcoords( GLcontext *ctx, struct sw_span *span )
 {
    GLuint i;
    for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
-      COPY_4V(span->tex[i], ctx->Current.RasterTexCoords[i]);
+      const GLfloat *tc = ctx->Current.RasterTexCoords[i];
+      if (tc[3] > 0.0F) {
+         /* use (s/q, t/q, r/q, 1) */
+         span->tex[i][0] = tc[0] / tc[3];
+         span->tex[i][1] = tc[1] / tc[3];
+         span->tex[i][2] = tc[2] / tc[3];
+         span->tex[i][3] = 1.0;
+      }
+      else {
+         ASSIGN_4V(span->tex[i], 0.0F, 0.0F, 0.0F, 1.0F);
+      }
       ASSIGN_4V(span->texStepX[i], 0.0F, 0.0F, 0.0F, 0.0F);
       ASSIGN_4V(span->texStepY[i], 0.0F, 0.0F, 0.0F, 0.0F);
    }
@@ -140,14 +148,6 @@ _mesa_span_default_texcoords( GLcontext *ctx, struct sw_span *span )
 static void
 interpolate_colors(GLcontext *ctx, struct sw_span *span)
 {
-   GLfixed r = span->red;
-   GLfixed g = span->green;
-   GLfixed b = span->blue;
-   GLfixed a = span->alpha;
-   const GLint dr = span->redStep;
-   const GLint dg = span->greenStep;
-   const GLint db = span->blueStep;
-   const GLint da = span->alphaStep;
    const GLuint n = span->end;
    GLchan (*rgba)[4] = span->array->rgba;
    GLuint i;
@@ -158,16 +158,35 @@ interpolate_colors(GLcontext *ctx, struct sw_span *span)
    if (span->interpMask & SPAN_FLAT) {
       /* constant color */
       GLchan color[4];
-      color[RCOMP] = FixedToChan(r);
-      color[GCOMP] = FixedToChan(g);
-      color[BCOMP] = FixedToChan(b);
-      color[ACOMP] = FixedToChan(a);
+      color[RCOMP] = FixedToChan(span->red);
+      color[GCOMP] = FixedToChan(span->green);
+      color[BCOMP] = FixedToChan(span->blue);
+      color[ACOMP] = FixedToChan(span->alpha);
       for (i = 0; i < n; i++) {
          COPY_CHAN4(span->array->rgba[i], color);
       }
    }
    else {
       /* interpolate */
+#if CHAN_TYPE == GL_FLOAT
+      GLfloat r = span->red;
+      GLfloat g = span->green;
+      GLfloat b = span->blue;
+      GLfloat a = span->alpha;
+      const GLfloat dr = span->redStep;
+      const GLfloat dg = span->greenStep;
+      const GLfloat db = span->blueStep;
+      const GLfloat da = span->alphaStep;
+#else
+      GLfixed r = span->red;
+      GLfixed g = span->green;
+      GLfixed b = span->blue;
+      GLfixed a = span->alpha;
+      const GLint dr = span->redStep;
+      const GLint dg = span->greenStep;
+      const GLint db = span->blueStep;
+      const GLint da = span->alphaStep;
+#endif
       for (i = 0; i < n; i++) {
          rgba[i][RCOMP] = FixedToChan(r);
          rgba[i][GCOMP] = FixedToChan(g);
@@ -256,7 +275,7 @@ interpolate_specular(GLcontext *ctx, struct sw_span *span)
 
 /* Fill in the span.zArray array from the interpolation values */
 void
-_mesa_span_interpolate_z( const GLcontext *ctx, struct sw_span *span )
+_swrast_span_interpolate_z( const GLcontext *ctx, struct sw_span *span )
 {
    const GLuint n = span->end;
    GLuint i;
@@ -267,7 +286,7 @@ _mesa_span_interpolate_z( const GLcontext *ctx, struct sw_span *span )
    if (ctx->Visual.depthBits <= 16) {
       GLfixed zval = span->z;
       GLdepth *z = span->array->z; 
-     for (i = 0; i < n; i++) {
+      for (i = 0; i < n; i++) {
          z[i] = FixedToInt(zval);
          zval += span->zStep;
       }
@@ -298,8 +317,8 @@ compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
    GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
    GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
    GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
-   GLfloat x = sqrt(dudx * dudx + dvdx * dvdx);
-   GLfloat y = sqrt(dudy * dudy + dvdy * dvdy);
+   GLfloat x = SQRTF(dudx * dudx + dvdx * dvdx);
+   GLfloat y = SQRTF(dudy * dudy + dvdy * dvdy);
    GLfloat rho = MAX2(x, y);
    GLfloat lambda = LOG2(rho);
    return lambda;
@@ -310,10 +329,10 @@ compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
 /*
  * This is a faster approximation
  */
-static GLfloat
-compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
-               GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
-               GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
+GLfloat
+_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
+                     GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
+                     GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
 {
    GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ;
    GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ;
@@ -331,10 +350,16 @@ compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
    return lambda;
 }
 
-/*
+
+/**
  * Fill in the span.texcoords array from the interpolation values.
- * XXX We could optimize here for the case when dq = 0.  That would
- * usually be the case when using an orthographic projection.
+ * Note: in the places where we divide by Q (or mult by invQ) we're
+ * really doing two things: perspective correction and texcoord
+ * projection.  Remember, for texcoord (s,t,r,q) we need to index
+ * texels with (s/q, t/q, r/q).
+ * If we're using a fragment program, we never do the division
+ * for texcoord projection.  That's done by the TXP instruction
+ * or user-written code.
  */
 static void
 interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
@@ -342,20 +367,31 @@ interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
    ASSERT(span->interpMask & SPAN_TEXTURE);
    ASSERT(!(span->arrayMask & SPAN_TEXTURE));
 
-   if (ctx->Texture._EnabledUnits > 1) {
+   if (ctx->Texture._EnabledCoordUnits > 1) {
       /* multitexture */
       GLuint u;
       span->arrayMask |= SPAN_TEXTURE;
       for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
-         if (ctx->Texture.Unit[u]._ReallyEnabled) {
+         if (ctx->Texture._EnabledCoordUnits & (1 << u)) {
             const struct gl_texture_object *obj =ctx->Texture.Unit[u]._Current;
-            const struct gl_texture_image *img = obj->Image[obj->BaseLevel];
-            GLboolean needLambda = (obj->MinFilter != obj->MagFilter);
+            GLfloat texW, texH;
+            GLboolean needLambda;
+            if (obj) {
+               const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
+               needLambda = (obj->MinFilter != obj->MagFilter)
+                  || ctx->FragmentProgram._Enabled;
+               texW = img->WidthScale;
+               texH = img->HeightScale;
+            }
+            else {
+               /* using a fragment program */
+               texW = 1.0;
+               texH = 1.0;
+               needLambda = GL_FALSE;
+            }
             if (needLambda) {
                GLfloat (*texcoord)[4] = span->array->texcoords[u];
                GLfloat *lambda = span->array->lambda[u];
-               const GLfloat texW = (GLfloat) img->WidthScale;
-               const GLfloat texH = (GLfloat) img->HeightScale;
                const GLfloat dsdx = span->texStepX[u][0];
                const GLfloat dsdy = span->texStepY[u][0];
                const GLfloat dtdx = span->texStepX[u][1];
@@ -368,18 +404,42 @@ interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
                GLfloat r = span->tex[u][2];
                GLfloat q = span->tex[u][3];
                GLuint i;
-               for (i = 0; i < span->end; i++) {
-                  const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
-                  texcoord[i][0] = s * invQ;
-                  texcoord[i][1] = t * invQ;
-                  texcoord[i][2] = r * invQ;
-                  lambda[i] = compute_lambda(dsdx, dsdy, dtdx, dtdy,
-                                             dqdx, dqdy, texW, texH,
-                                             s, t, q, invQ);
-                  s += dsdx;
-                  t += dtdx;
-                  r += drdx;
-                  q += dqdx;
+               if (ctx->FragmentProgram._Enabled) {
+                  /* do perspective correction but don't divide s, t, r by q */
+                  const GLfloat dwdx = span->dwdx;
+                  GLfloat w = span->w;
+                  for (i = 0; i < span->end; i++) {
+                     const GLfloat invW = 1.0F / w;
+                     texcoord[i][0] = s * invW;
+                     texcoord[i][1] = t * invW;
+                     texcoord[i][2] = r * invW;
+                     texcoord[i][3] = q * invW;
+                     lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
+                                                        dqdx, dqdy, texW, texH,
+                                                        s, t, q, invW);
+                     s += dsdx;
+                     t += dtdx;
+                     r += drdx;
+                     q += dqdx;
+                     w += dwdx;
+                  }
+
+               }
+               else {
+                  for (i = 0; i < span->end; i++) {
+                     const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
+                     texcoord[i][0] = s * invQ;
+                     texcoord[i][1] = t * invQ;
+                     texcoord[i][2] = r * invQ;
+                     texcoord[i][3] = q;
+                     lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
+                                                        dqdx, dqdy, texW, texH,
+                                                        s, t, q, invQ);
+                     s += dsdx;
+                     t += dtdx;
+                     r += drdx;
+                     q += dqdx;
+                  }
                }
                span->arrayMask |= SPAN_LAMBDA;
             }
@@ -395,13 +455,32 @@ interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
                GLfloat r = span->tex[u][2];
                GLfloat q = span->tex[u][3];
                GLuint i;
-               if (dqdx == 0.0) {
+               if (ctx->FragmentProgram._Enabled) {
+                  /* do perspective correction but don't divide s, t, r by q */
+                  const GLfloat dwdx = span->dwdx;
+                  GLfloat w = span->w;
+                  for (i = 0; i < span->end; i++) {
+                     const GLfloat invW = 1.0F / w;
+                     texcoord[i][0] = s * invW;
+                     texcoord[i][1] = t * invW;
+                     texcoord[i][2] = r * invW;
+                     texcoord[i][3] = q * invW;
+                     lambda[i] = 0.0;
+                     s += dsdx;
+                     t += dtdx;
+                     r += drdx;
+                     q += dqdx;
+                     w += dwdx;
+                  }
+               }
+               else if (dqdx == 0.0F) {
                   /* Ortho projection or polygon's parallel to window X axis */
                   const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
                   for (i = 0; i < span->end; i++) {
                      texcoord[i][0] = s * invQ;
                      texcoord[i][1] = t * invQ;
                      texcoord[i][2] = r * invQ;
+                     texcoord[i][3] = q;
                      lambda[i] = 0.0;
                      s += dsdx;
                      t += dtdx;
@@ -414,6 +493,7 @@ interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
                      texcoord[i][0] = s * invQ;
                      texcoord[i][1] = t * invQ;
                      texcoord[i][2] = r * invQ;
+                     texcoord[i][3] = q;
                      lambda[i] = 0.0;
                      s += dsdx;
                      t += dtdx;
@@ -428,15 +508,24 @@ interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
    else {
       /* single texture */
       const struct gl_texture_object *obj = ctx->Texture.Unit[0]._Current;
-      const struct gl_texture_image *img = obj->Image[obj->BaseLevel];
-      GLboolean needLambda = (obj->MinFilter != obj->MagFilter);
+      GLfloat texW, texH;
+      GLboolean needLambda;
+      if (obj) {
+         const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
+         needLambda = (obj->MinFilter != obj->MagFilter)
+            || ctx->FragmentProgram._Enabled;
+         texW = (GLfloat) img->WidthScale;
+         texH = (GLfloat) img->HeightScale;
+      }
+      else {
+         needLambda = GL_FALSE;
+         texW = texH = 1.0;
+      }
       span->arrayMask |= SPAN_TEXTURE;
       if (needLambda) {
          /* just texture unit 0, with lambda */
          GLfloat (*texcoord)[4] = span->array->texcoords[0];
          GLfloat *lambda = span->array->lambda[0];
-         const GLfloat texW = (GLfloat) img->WidthScale;
-         const GLfloat texH = (GLfloat) img->HeightScale;
          const GLfloat dsdx = span->texStepX[0][0];
          const GLfloat dsdy = span->texStepY[0][0];
          const GLfloat dtdx = span->texStepX[0][1];
@@ -449,18 +538,42 @@ interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
          GLfloat r = span->tex[0][2];
          GLfloat q = span->tex[0][3];
          GLuint i;
-         for (i = 0; i < span->end; i++) {
-            const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
-            lambda[i] = compute_lambda(dsdx, dsdy, dtdx, dtdy,
-                                       dqdx, dqdy, texW, texH,
-                                       s, t, q, invQ);
-            texcoord[i][0] = s * invQ;
-            texcoord[i][1] = t * invQ;
-            texcoord[i][2] = r * invQ;
-            s += dsdx;
-            t += dtdx;
-            r += drdx;
-            q += dqdx;
+         if (ctx->FragmentProgram._Enabled) {
+            /* do perspective correction but don't divide s, t, r by q */
+            const GLfloat dwdx = span->dwdx;
+            GLfloat w = span->w;
+            for (i = 0; i < span->end; i++) {
+               const GLfloat invW = 1.0F / w;
+               texcoord[i][0] = s * invW;
+               texcoord[i][1] = t * invW;
+               texcoord[i][2] = r * invW;
+               texcoord[i][3] = q * invW;
+               lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
+                                                  dqdx, dqdy, texW, texH,
+                                                  s, t, q, invW);
+               s += dsdx;
+               t += dtdx;
+               r += drdx;
+               q += dqdx;
+               w += dwdx;
+            }
+         }
+         else {
+            /* tex.c */
+            for (i = 0; i < span->end; i++) {
+               const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
+               lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
+                                                dqdx, dqdy, texW, texH,
+                                                s, t, q, invQ);
+               texcoord[i][0] = s * invQ;
+               texcoord[i][1] = t * invQ;
+               texcoord[i][2] = r * invQ;
+               texcoord[i][3] = q;
+               s += dsdx;
+               t += dtdx;
+               r += drdx;
+               q += dqdx;
+            }
          }
          span->arrayMask |= SPAN_LAMBDA;
       }
@@ -476,13 +589,31 @@ interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
          GLfloat r = span->tex[0][2];
          GLfloat q = span->tex[0][3];
          GLuint i;
-         if (dqdx == 0.0) {
+         if (ctx->FragmentProgram._Enabled) {
+            /* do perspective correction but don't divide s, t, r by q */
+            const GLfloat dwdx = span->dwdx;
+            GLfloat w = span->w;
+            for (i = 0; i < span->end; i++) {
+               const GLfloat invW = 1.0F / w;
+               texcoord[i][0] = s * invW;
+               texcoord[i][1] = t * invW;
+               texcoord[i][2] = r * invW;
+               texcoord[i][3] = q * invW;
+               s += dsdx;
+               t += dtdx;
+               r += drdx;
+               q += dqdx;
+               w += dwdx;
+            }
+         }
+         else if (dqdx == 0.0F) {
             /* Ortho projection or polygon's parallel to window X axis */
             const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
             for (i = 0; i < span->end; i++) {
                texcoord[i][0] = s * invQ;
                texcoord[i][1] = t * invQ;
                texcoord[i][2] = r * invQ;
+               texcoord[i][3] = q;
                s += dsdx;
                t += dtdx;
                r += drdx;
@@ -494,6 +625,7 @@ interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
                texcoord[i][0] = s * invQ;
                texcoord[i][1] = t * invQ;
                texcoord[i][2] = r * invQ;
+               texcoord[i][3] = q;
                s += dsdx;
                t += dtdx;
                r += drdx;
@@ -588,7 +720,7 @@ clip_span( GLcontext *ctx, struct sw_span *span )
       if (x < xmin) {
          ASSERT(x + n > xmin);
          span->writeAll = GL_FALSE;
-         BZERO(span->array->mask, (xmin - x) * sizeof(GLubyte));
+         _mesa_bzero(span->array->mask, (xmin - x) * sizeof(GLubyte));
       }
 
       /* Clip to right */
@@ -618,24 +750,19 @@ multi_write_index_span( GLcontext *ctx, struct sw_span *span )
          GLuint indexTmp[MAX_WIDTH];
          ASSERT(span->end < MAX_WIDTH);
 
-         if (bufferBit == FRONT_LEFT_BIT)
-            (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_FRONT_LEFT);
-         else if (bufferBit == FRONT_RIGHT_BIT)
-            (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_FRONT_RIGHT);
-         else if (bufferBit == BACK_LEFT_BIT)
-            (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_BACK_LEFT);
-         else
-            (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_BACK_RIGHT);
+         /* Set the current read/draw buffer */
+         swrast->CurrentBufferBit = bufferBit;
+         (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, bufferBit);
 
          /* make copy of incoming indexes */
          MEMCPY( indexTmp, span->array->index, span->end * sizeof(GLuint) );
 
          if (ctx->Color.IndexLogicOpEnabled) {
-            _mesa_logicop_ci_span(ctx, span, indexTmp);
+            _swrast_logicop_ci_span(ctx, span, indexTmp);
          }
 
          if (ctx->Color.IndexMask != 0xffffffff) {
-            _mesa_mask_index_span(ctx, span, indexTmp);
+            _swrast_mask_index_span(ctx, span, indexTmp);
          }
 
          if (span->arrayMask & SPAN_XY) {
@@ -680,35 +807,22 @@ multi_write_rgba_span( GLcontext *ctx, struct sw_span *span )
          GLchan rgbaTmp[MAX_WIDTH][4];
          ASSERT(span->end < MAX_WIDTH);
 
-         if (bufferBit == FRONT_LEFT_BIT) {
-            ctx->Color._DriverDrawBuffer = GL_FRONT_LEFT;
-            (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_FRONT_LEFT);
-         }
-         else if (bufferBit == FRONT_RIGHT_BIT) {
-            ctx->Color._DriverDrawBuffer = GL_FRONT_RIGHT;
-            (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_FRONT_RIGHT);
-         }
-         else if (bufferBit == BACK_LEFT_BIT) {
-            ctx->Color._DriverDrawBuffer = GL_BACK_LEFT;
-            (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_BACK_LEFT);
-         }
-         else {
-            ctx->Color._DriverDrawBuffer = GL_BACK_RIGHT;
-            (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_BACK_RIGHT);
-         }
+         /* Set the current read/draw buffer */
+         swrast->CurrentBufferBit = bufferBit;
+         (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, bufferBit);
 
          /* make copy of incoming colors */
          MEMCPY( rgbaTmp, span->array->rgba, 4 * span->end * sizeof(GLchan) );
 
-         if (ctx->Color.ColorLogicOpEnabled) {
-            _mesa_logicop_rgba_span(ctx, span, rgbaTmp);
+         if (ctx->Color._LogicOpEnabled) {
+            _swrast_logicop_rgba_span(ctx, span, rgbaTmp);
          }
          else if (ctx->Color.BlendEnabled) {
-            _mesa_blend_span(ctx, span, rgbaTmp);
+            _swrast_blend_span(ctx, span, rgbaTmp);
          }
 
          if (colorMask != 0xffffffff) {
-            _mesa_mask_rgba_span(ctx, span, rgbaTmp);
+            _swrast_mask_rgba_span(ctx, span, rgbaTmp);
          }
 
          if (span->arrayMask & SPAN_XY) {
@@ -718,7 +832,7 @@ multi_write_rgba_span( GLcontext *ctx, struct sw_span *span )
                                               (const GLchan (*)[4]) rgbaTmp,
                                               span->array->mask);
             if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
-               _mesa_write_alpha_pixels(ctx, span->end,
+               _swrast_write_alpha_pixels(ctx, span->end,
                                         span->array->x, span->array->y,
                                         (const GLchan (*)[4]) rgbaTmp,
                                         span->array->mask);
@@ -730,7 +844,7 @@ multi_write_rgba_span( GLcontext *ctx, struct sw_span *span )
                                             (const GLchan (*)[4]) rgbaTmp,
                                             span->array->mask);
             if (swrast->_RasterMask & ALPHABUF_BIT) {
-               _mesa_write_alpha_span(ctx, span->end, span->x, span->y,
+               _swrast_write_alpha_span(ctx, span->end, span->x, span->y,
                                       (const GLchan (*)[4]) rgbaTmp,
                                       span->array->mask);
             }
@@ -750,7 +864,7 @@ multi_write_rgba_span( GLcontext *ctx, struct sw_span *span )
  * to their original values before returning.
  */
 void
-_mesa_write_index_span( GLcontext *ctx, struct sw_span *span)
+_swrast_write_index_span( GLcontext *ctx, struct sw_span *span)
 {
    SWcontext *swrast = SWRAST_CONTEXT(ctx);
    const GLuint origInterpMask = span->interpMask;
@@ -778,6 +892,13 @@ _mesa_write_index_span( GLcontext *ctx, struct sw_span *span)
       }
    }
 
+   /* Depth bounds test */
+   if (ctx->Depth.BoundsTest && ctx->Visual.depthBits > 0) {
+      if (!_swrast_depth_bounds_test(ctx, span)) {
+         return;
+      }
+   }
+
 #ifdef DEBUG
    if (span->arrayMask & SPAN_XY) {
       GLuint i;
@@ -800,17 +921,17 @@ _mesa_write_index_span( GLcontext *ctx, struct sw_span *span)
    /* Depth test and stencil */
    if (ctx->Depth.Test || ctx->Stencil.Enabled) {
       if (span->interpMask & SPAN_Z)
-         _mesa_span_interpolate_z(ctx, span);
+         _swrast_span_interpolate_z(ctx, span);
 
       if (ctx->Stencil.Enabled) {
-         if (!_mesa_stencil_and_ztest_span(ctx, span)) {
+         if (!_swrast_stencil_and_ztest_span(ctx, span)) {
             span->arrayMask = origArrayMask;
             return;
          }
       }
       else {
          ASSERT(ctx->Depth.Test);
-         if (!_mesa_depth_test_span(ctx, span)) {
+         if (!_swrast_depth_test_span(ctx, span)) {
             span->arrayMask = origArrayMask;
             return;
          }
@@ -820,6 +941,14 @@ _mesa_write_index_span( GLcontext *ctx, struct sw_span *span)
    /* if we get here, something passed the depth test */
    ctx->OcclusionResult = GL_TRUE;
 
+#if FEATURE_ARB_occlusion_query
+   if (ctx->Occlusion.Active) {
+      GLuint i;
+      for (i = 0; i < span->end; i++)
+         ctx->Occlusion.PassedCounter += span->array->mask[i];
+   }
+#endif
+
    /* we have to wait until after occlusion to do this test */
    if (ctx->Color.DrawBuffer == GL_NONE || ctx->Color.IndexMask == 0) {
       /* write no pixels */
@@ -836,7 +965,7 @@ _mesa_write_index_span( GLcontext *ctx, struct sw_span *span)
 
    /* Fog */
    if (ctx->Fog.Enabled) {
-      _mesa_fog_ci_span(ctx, span);
+      _swrast_fog_ci_span(ctx, span);
    }
 
    /* Antialias coverage application */
@@ -857,11 +986,11 @@ _mesa_write_index_span( GLcontext *ctx, struct sw_span *span)
    else {
       /* normal situation: draw to exactly one buffer */
       if (ctx->Color.IndexLogicOpEnabled) {
-         _mesa_logicop_ci_span(ctx, span, span->array->index);
+         _swrast_logicop_ci_span(ctx, span, span->array->index);
       }
 
       if (ctx->Color.IndexMask != 0xffffffff) {
-         _mesa_mask_index_span(ctx, span, span->array->index);
+         _swrast_mask_index_span(ctx, span, span->array->index);
       }
 
       /* write pixels */
@@ -907,7 +1036,7 @@ _mesa_write_index_span( GLcontext *ctx, struct sw_span *span)
  * to their original values before returning.
  */
 void
-_mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span)
+_swrast_write_rgba_span( GLcontext *ctx, struct sw_span *span)
 {
    SWcontext *swrast = SWRAST_CONTEXT(ctx);
    const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
@@ -948,6 +1077,13 @@ _mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span)
       }
    }
 
+   /* Depth bounds test */
+   if (ctx->Depth.BoundsTest && ctx->Visual.depthBits > 0) {
+      if (!_swrast_depth_bounds_test(ctx, span)) {
+         return;
+      }
+   }
+
 #ifdef DEBUG
    if (span->arrayMask & SPAN_XY) {
       GLuint i;
@@ -967,9 +1103,27 @@ _mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span)
       stipple_polygon_span(ctx, span);
    }
 
+   /* Fragment program */
+   if (ctx->FragmentProgram._Enabled) {
+      /* Now we may need to interpolate the colors and texcoords */
+      if ((span->interpMask & SPAN_RGBA) &&
+          (span->arrayMask & SPAN_RGBA) == 0) {
+         interpolate_colors(ctx, span);
+         span->interpMask &= ~SPAN_RGBA;
+      }
+      if (span->interpMask & SPAN_SPEC) {
+         interpolate_specular(ctx, span);
+      }
+      if ((span->interpMask & SPAN_TEXTURE)
+          && (span->arrayMask & SPAN_TEXTURE) == 0)
+         interpolate_texcoords(ctx, span);
+      _swrast_exec_fragment_program(ctx, span);
+      monoColor = GL_FALSE;
+   }
+
    /* Do the alpha test */
    if (ctx->Color.AlphaEnabled) {
-      if (!_mesa_alpha_test(ctx, span)) {
+      if (!_swrast_alpha_test(ctx, span)) {
          span->interpMask = origInterpMask;
          span->arrayMask = origArrayMask;
         return;
@@ -979,10 +1133,10 @@ _mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span)
    /* Stencil and Z testing */
    if (ctx->Stencil.Enabled || ctx->Depth.Test) {
       if (span->interpMask & SPAN_Z)
-         _mesa_span_interpolate_z(ctx, span);
+         _swrast_span_interpolate_z(ctx, span);
 
       if (ctx->Stencil.Enabled) {
-         if (!_mesa_stencil_and_ztest_span(ctx, span)) {
+         if (!_swrast_stencil_and_ztest_span(ctx, span)) {
             span->interpMask = origInterpMask;
             span->arrayMask = origArrayMask;
             return;
@@ -992,7 +1146,7 @@ _mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span)
          ASSERT(ctx->Depth.Test);
          ASSERT(span->arrayMask & SPAN_Z);
          /* regular depth testing */
-         if (!_mesa_depth_test_span(ctx, span)) {
+         if (!_swrast_depth_test_span(ctx, span)) {
             span->interpMask = origInterpMask;
             span->arrayMask = origArrayMask;
             return;
@@ -1003,6 +1157,14 @@ _mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span)
    /* if we get here, something passed the depth test */
    ctx->OcclusionResult = GL_TRUE;
 
+#if FEATURE_ARB_occlusion_query
+   if (ctx->Occlusion.Active) {
+      GLuint i;
+      for (i = 0; i < span->end; i++)
+         ctx->Occlusion.PassedCounter += span->array->mask[i];
+   }
+#endif
+
    /* can't abort span-writing until after occlusion testing */
    if (colorMask == 0x0) {
       span->interpMask = origInterpMask;
@@ -1018,8 +1180,8 @@ _mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span)
    }
 
    /* Fog */
-   if (ctx->Fog.Enabled) {
-      _mesa_fog_rgba_span(ctx, span);
+   if (swrast->_FogEnabled) {
+      _swrast_fog_rgba_span(ctx, span);
       monoColor = GL_FALSE;
    }
 
@@ -1039,32 +1201,50 @@ _mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span)
    }
    else {
       /* normal: write to exactly one buffer */
-      if (ctx->Color.ColorLogicOpEnabled) {
-         _mesa_logicop_rgba_span(ctx, span, span->array->rgba);
+      if (ctx->Color._LogicOpEnabled) {
+         _swrast_logicop_rgba_span(ctx, span, span->array->rgba);
          monoColor = GL_FALSE;
       }
       else if (ctx->Color.BlendEnabled) {
-         _mesa_blend_span(ctx, span, span->array->rgba);
+         _swrast_blend_span(ctx, span, span->array->rgba);
          monoColor = GL_FALSE;
       }
 
       /* Color component masking */
       if (colorMask != 0xffffffff) {
-         _mesa_mask_rgba_span(ctx, span, span->array->rgba);
+         _swrast_mask_rgba_span(ctx, span, span->array->rgba);
          monoColor = GL_FALSE;
       }
 
       /* write pixels */
       if (span->arrayMask & SPAN_XY) {
          /* array of pixel coords */
-         /* XXX test for mono color */
-         (*swrast->Driver.WriteRGBAPixels)(ctx, span->end, span->array->x,
-             span->array->y, (const GLchan (*)[4]) span->array->rgba, span->array->mask);
-         if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
-            _mesa_write_alpha_pixels(ctx, span->end,
-                                     span->array->x, span->array->y,
-                                     (const GLchan (*)[4]) span->array->rgba,
-                                     span->array->mask);
+         if (monoColor) {
+            /* all pixels have same color */
+            GLchan color[4];
+            color[RCOMP] = FixedToChan(span->red);
+            color[GCOMP] = FixedToChan(span->green);
+            color[BCOMP] = FixedToChan(span->blue);
+            color[ACOMP] = FixedToChan(span->alpha);
+            (*swrast->Driver.WriteMonoRGBAPixels)(ctx, span->end,
+                     span->array->x, span->array->y, color, span->array->mask);
+            if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
+               _swrast_write_mono_alpha_pixels(ctx, span->end,
+                                              span->array->x, span->array->y,
+                                              color[ACOMP], span->array->mask);
+            }
+         }
+         else {
+            (*swrast->Driver.WriteRGBAPixels)(ctx, span->end,
+                                       span->array->x, span->array->y,
+                                       (const GLchan (*)[4]) span->array->rgba,
+                                       span->array->mask);
+            if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
+               _swrast_write_alpha_pixels(ctx, span->end,
+                                       span->array->x, span->array->y,
+                                       (const GLchan (*)[4]) span->array->rgba,
+                                       span->array->mask);
+            }
          }
       }
       else {
@@ -1077,8 +1257,12 @@ _mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span)
             color[BCOMP] = FixedToChan(span->blue);
             color[ACOMP] = FixedToChan(span->alpha);
             (*swrast->Driver.WriteMonoRGBASpan)(ctx, span->end, span->x,
-                                                span->y, color, span->array->mask);
-            /* XXX software alpha buffer writes! */
+                                           span->y, color, span->array->mask);
+            if (swrast->_RasterMask & ALPHABUF_BIT) {
+               _swrast_write_mono_alpha_span(ctx, span->end, span->x, span->y,
+                      color[ACOMP],
+                      span->writeAll ? ((const GLubyte *) NULL) : span->array->mask);
+            }
          }
          else {
             /* each pixel is a different color */
@@ -1086,7 +1270,7 @@ _mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span)
                       (const GLchan (*)[4]) span->array->rgba,
                       span->writeAll ? ((const GLubyte *) NULL) : span->array->mask);
             if (swrast->_RasterMask & ALPHABUF_BIT) {
-               _mesa_write_alpha_span(ctx, span->end, span->x, span->y,
+               _swrast_write_alpha_span(ctx, span->end, span->x, span->y,
                       (const GLchan (*)[4]) span->array->rgba,
                       span->writeAll ? ((const GLubyte *) NULL) : span->array->mask);
             }
@@ -1131,17 +1315,18 @@ add_colors(GLuint n, GLchan rgba[][4], GLchan specular[][4] )
  * to their original values before returning.
  */
 void
-_mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
+_swrast_write_texture_span( GLcontext *ctx, struct sw_span *span)
 {
    const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
    SWcontext *swrast = SWRAST_CONTEXT(ctx);
+   const GLuint origInterpMask = span->interpMask;
    const GLuint origArrayMask = span->arrayMask;
 
    ASSERT(span->primitive == GL_POINT  ||  span->primitive == GL_LINE ||
          span->primitive == GL_POLYGON  ||  span->primitive == GL_BITMAP);
    ASSERT(span->end <= MAX_WIDTH);
    ASSERT((span->interpMask & span->arrayMask) == 0);
-   ASSERT(ctx->Texture._EnabledUnits);
+   ASSERT(ctx->Texture._EnabledCoordUnits || ctx->FragmentProgram._Enabled);
 
    /*
    printf("%s()  interp 0x%x  array 0x%x\n", __FUNCTION__, span->interpMask, span->arrayMask);
@@ -1194,13 +1379,20 @@ _mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
       if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
          interpolate_colors(ctx, span);
 
+      if (span->interpMask & SPAN_SPEC) {
+         interpolate_specular(ctx, span);
+      }
+
       /* Texturing without alpha is done after depth-testing which
        * gives a potential speed-up.
        */
-      _swrast_texture_span( ctx, span );
+      if (ctx->FragmentProgram._Enabled)
+         _swrast_exec_fragment_program( ctx, span );
+      else
+         _swrast_texture_span( ctx, span );
 
       /* Do the alpha test */
-      if (!_mesa_alpha_test(ctx, span)) {
+      if (!_swrast_alpha_test(ctx, span)) {
          span->arrayMask = origArrayMask;
         return;
       }
@@ -1209,10 +1401,11 @@ _mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
    /* Stencil and Z testing */
    if (ctx->Stencil.Enabled || ctx->Depth.Test) {
       if (span->interpMask & SPAN_Z)
-         _mesa_span_interpolate_z(ctx, span);
+         _swrast_span_interpolate_z(ctx, span);
 
       if (ctx->Stencil.Enabled) {
-         if (!_mesa_stencil_and_ztest_span(ctx, span)) {
+         if (!_swrast_stencil_and_ztest_span(ctx, span)) {
+            span->interpMask = origInterpMask;
             span->arrayMask = origArrayMask;
             return;
          }
@@ -1221,7 +1414,8 @@ _mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
          ASSERT(ctx->Depth.Test);
          ASSERT(span->arrayMask & SPAN_Z);
          /* regular depth testing */
-         if (!_mesa_depth_test_span(ctx, span)) {
+         if (!_swrast_depth_test_span(ctx, span)) {
+            span->interpMask = origInterpMask;
             span->arrayMask = origArrayMask;
             return;
          }
@@ -1231,10 +1425,19 @@ _mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
    /* if we get here, some fragments passed the depth test */
    ctx->OcclusionResult = GL_TRUE;
 
+#if FEATURE_ARB_occlusion_query
+   if (ctx->Occlusion.Active) {
+      GLuint i;
+      for (i = 0; i < span->end; i++)
+         ctx->Occlusion.PassedCounter += span->array->mask[i];
+   }
+#endif
+
    /* We had to wait until now to check for glColorMask(F,F,F,F) because of
     * the occlusion test.
     */
    if (colorMask == 0x0) {
+      span->interpMask = origInterpMask;
       span->arrayMask = origArrayMask;
       return;
    }
@@ -1246,7 +1449,14 @@ _mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
       if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
          interpolate_colors(ctx, span);
 
-      _swrast_texture_span( ctx, span );
+      if (span->interpMask & SPAN_SPEC) {
+         interpolate_specular(ctx, span);
+      }
+
+      if (ctx->FragmentProgram._Enabled)
+         _swrast_exec_fragment_program( ctx, span );
+      else
+         _swrast_texture_span( ctx, span );
    }
 
    ASSERT(span->arrayMask & SPAN_RGBA);
@@ -1263,8 +1473,8 @@ _mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
    }
 
    /* Fog */
-   if (ctx->Fog.Enabled) {
-      _mesa_fog_rgba_span(ctx, span);
+   if (swrast->_FogEnabled) {
+      _swrast_fog_rgba_span(ctx, span);
    }
 
    /* Antialias coverage application */
@@ -1282,24 +1492,25 @@ _mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
    }
    else {
       /* normal: write to exactly one buffer */
-      if (ctx->Color.ColorLogicOpEnabled) {
-         _mesa_logicop_rgba_span(ctx, span, span->array->rgba);
+      if (ctx->Color._LogicOpEnabled) {
+         _swrast_logicop_rgba_span(ctx, span, span->array->rgba);
       }
       else if (ctx->Color.BlendEnabled) {
-         _mesa_blend_span(ctx, span, span->array->rgba);
+         _swrast_blend_span(ctx, span, span->array->rgba);
       }
 
+      /* Color component masking */
       if (colorMask != 0xffffffff) {
-         _mesa_mask_rgba_span(ctx, span, span->array->rgba);
+         _swrast_mask_rgba_span(ctx, span, span->array->rgba);
       }
 
+      /* write pixels */
       if (span->arrayMask & SPAN_XY) {
          /* array of pixel coords */
          (*swrast->Driver.WriteRGBAPixels)(ctx, span->end, span->array->x,
              span->array->y, (const GLchan (*)[4]) span->array->rgba, span->array->mask);
          if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
-            _mesa_write_alpha_pixels(ctx, span->end,
+            _swrast_write_alpha_pixels(ctx, span->end,
                                      span->array->x, span->array->y,
                                      (const GLchan (*)[4]) span->array->rgba,
                                      span->array->mask);
@@ -1311,13 +1522,14 @@ _mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
                                        (const GLchan (*)[4]) span->array->rgba,
                                        span->writeAll ? NULL : span->array->mask);
          if (swrast->_RasterMask & ALPHABUF_BIT) {
-            _mesa_write_alpha_span(ctx, span->end, span->x, span->y,
+            _swrast_write_alpha_span(ctx, span->end, span->x, span->y,
                                    (const GLchan (*)[4]) span->array->rgba,
                                    span->writeAll ? NULL : span->array->mask);
          }
       }
    }
 
+   span->interpMask = origInterpMask;
    span->arrayMask = origArrayMask;
 }
 
@@ -1328,7 +1540,7 @@ _mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
  * reading ouside the buffer's boundaries.
  */
 void
-_mesa_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
+_swrast_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
                       GLuint n, GLint x, GLint y, GLchan rgba[][4] )
 {
    SWcontext *swrast = SWRAST_CONTEXT(ctx);
@@ -1338,7 +1550,7 @@ _mesa_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
    if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
       /* completely above, below, or right */
       /* XXX maybe leave undefined? */
-      BZERO(rgba, 4 * n * sizeof(GLchan));
+      _mesa_bzero(rgba, 4 * n * sizeof(GLchan));
    }
    else {
       GLint skip, length;
@@ -1371,7 +1583,7 @@ _mesa_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
 
       (*swrast->Driver.ReadRGBASpan)( ctx, length, x + skip, y, rgba + skip );
       if (buffer->UseSoftwareAlphaBuffers) {
-         _mesa_read_alpha_span(ctx, length, x + skip, y, rgba + skip);
+         _swrast_read_alpha_span(ctx, length, x + skip, y, rgba + skip);
       }
    }
 }
@@ -1382,7 +1594,7 @@ _mesa_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
  * reading ouside the buffer's boundaries.
  */
 void
-_mesa_read_index_span( GLcontext *ctx, GLframebuffer *buffer,
+_swrast_read_index_span( GLcontext *ctx, GLframebuffer *buffer,
                        GLuint n, GLint x, GLint y, GLuint indx[] )
 {
    SWcontext *swrast = SWRAST_CONTEXT(ctx);
@@ -1391,7 +1603,7 @@ _mesa_read_index_span( GLcontext *ctx, GLframebuffer *buffer,
 
    if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
       /* completely above, below, or right */
-      BZERO(indx, n * sizeof(GLuint));
+      _mesa_bzero(indx, n * sizeof(GLuint));
    }
    else {
       GLint skip, length;