Audit/fixes for NV/ARB TEX, TXP, TXB, TXD instructions.
authorBrian Paul <brian.paul@tungstengraphics.com>
Sun, 18 Apr 2004 20:11:52 +0000 (20:11 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Sun, 18 Apr 2004 20:11:52 +0000 (20:11 +0000)
Some texture instructions were using wrong LOD.
Fixed interpolate_texcoords() so it doesn't do texcoord projective division
when using a fragment program.  The TXP instruction does that.

src/mesa/shader/nvfragparse.c
src/mesa/shader/nvfragprog.h
src/mesa/swrast/s_nvfragprog.c
src/mesa/swrast/s_span.c

index bdc2c7ef94ac7b10a69523f0917777b15b33d2ba..264c1705fc41d7cc1f097d56763517511de5c269 100644 (file)
@@ -124,7 +124,7 @@ static const struct instruction_pattern Instructions[] = {
    { "SUB", FP_OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
    { "TEX", FP_OPCODE_TEX, INPUT_1V_T, OUTPUT_V,              _C | _S },
    { "TXD", FP_OPCODE_TXD, INPUT_3V_T, OUTPUT_V,              _C | _S },
-   { "TXP", FP_OPCODE_TXP, INPUT_1V_T, OUTPUT_V,              _C | _S },
+   { "TXP", FP_OPCODE_TXP_NV, INPUT_1V_T, OUTPUT_V,              _C | _S },
    { "UP2H",  FP_OPCODE_UP2H,  INPUT_1S, OUTPUT_V,            _C | _S },
    { "UP2US", FP_OPCODE_UP2US, INPUT_1S, OUTPUT_V,            _C | _S },
    { "UP4B",  FP_OPCODE_UP4B,  INPUT_1S, OUTPUT_V,            _C | _S },
index 53f4bf9905cd25c65219c15e8846a85e42100710..ae26a7b5743c2ee254915ded0ea5207e5dc7ff85 100644 (file)
@@ -108,7 +108,8 @@ enum fp_opcode {
    FP_OPCODE_TEX,
    FP_OPCODE_TXB,            /* ARB_f_p only */
    FP_OPCODE_TXD,            /* NV_f_p only */
-   FP_OPCODE_TXP,
+   FP_OPCODE_TXP,            /* ARB_f_p only */
+   FP_OPCODE_TXP_NV,         /* NV_f_p only */
    FP_OPCODE_UP2H,           /* NV_f_p only */
    FP_OPCODE_UP2US,          /* NV_f_p only */
    FP_OPCODE_UP4B,           /* NV_f_p only */
index f7510bf3ddfe7ed4c2624787ebaaf65715f77d0d..6529022fe935cdbe398c71d26f3a9f1209d9f289 100644 (file)
@@ -1140,19 +1140,19 @@ execute_program( GLcontext *ctx,
                store_vector4( inst, machine, result );
             }
             break;
-         case FP_OPCODE_TEX:
+         case FP_OPCODE_TEX: /* Both ARB and NV frag prog */
             /* Texel lookup */
             {
                GLfloat texcoord[4], color[4];
                fetch_vector4( ctx, &inst->SrcReg[0], machine, program, texcoord );
-               /* XXX: Undo perspective divide from interpolate_texcoords() */
-               fetch_texel( ctx, texcoord,
-                            span->array->lambda[inst->TexSrcUnit][column],
-                            inst->TexSrcUnit, color );
+               /* Note: we pass 0 for LOD.  The ARB extension requires it
+                * while the NV extension says it's implementation dependant.
+                */
+               fetch_texel( ctx, texcoord, 0.0F, inst->TexSrcUnit, color );
                store_vector4( inst, machine, color );
             }
             break;
-         case FP_OPCODE_TXB:
+         case FP_OPCODE_TXB: /* GL_ARB_fragment_program only */
             /* Texel lookup with LOD bias */
             {
                GLfloat texcoord[4], color[4], bias, lambda;
@@ -1168,7 +1168,7 @@ execute_program( GLcontext *ctx,
                store_vector4( inst, machine, color );
             }
             break;
-         case FP_OPCODE_TXD:
+         case FP_OPCODE_TXD: /* GL_NV_fragment_program only */
             /* Texture lookup w/ partial derivatives for LOD */
             {
                GLfloat texcoord[4], dtdx[4], dtdy[4], color[4];
@@ -1180,12 +1180,29 @@ execute_program( GLcontext *ctx,
                store_vector4( inst, machine, color );
             }
             break;
-         case FP_OPCODE_TXP:
-            /* Texture lookup w/ perspective divide */
+         case FP_OPCODE_TXP: /* GL_ARB_fragment_program only */
+            /* Texture lookup w/ projective divide */
+            {
+               GLfloat texcoord[4], color[4];
+               fetch_vector4( ctx, &inst->SrcReg[0], machine, program, texcoord );
+               texcoord[0] /= texcoord[3];
+               texcoord[1] /= texcoord[3];
+               texcoord[2] /= texcoord[3];
+               /* Note: LOD=0 */
+               fetch_texel( ctx, texcoord, 0.0F, inst->TexSrcUnit, color );
+               store_vector4( inst, machine, color );
+            }
+            break;
+         case FP_OPCODE_TXP_NV: /* GL_NV_fragment_program only */
+            /* Texture lookup w/ projective divide */
             {
                GLfloat texcoord[4], color[4];
                fetch_vector4( ctx, &inst->SrcReg[0], machine, program, texcoord );
-               /* Already did perspective divide in interpolate_texcoords() */
+               if (inst->TexSrcBit != TEXTURE_CUBE_BIT) {
+                  texcoord[0] /= texcoord[3];
+                  texcoord[1] /= texcoord[3];
+                  texcoord[2] /= texcoord[3];
+               }
                fetch_texel( ctx, texcoord,
                             span->array->lambda[inst->TexSrcUnit][column],
                             inst->TexSrcUnit, color );
index d164ad961adc50b50b1978efd73aa320f21e9551..b74f62b6c6860cd15315e93dcbc99346afbc4120 100644 (file)
@@ -340,10 +340,16 @@ _swrast_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)
@@ -368,6 +374,7 @@ interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
                texH = img->HeightScale;
             }
             else {
+               /* using a fragment program */
                texW = 1.0;
                texH = 1.0;
                needLambda = GL_FALSE;
@@ -387,19 +394,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;
-                  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;
+               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;
             }
@@ -415,7 +445,25 @@ 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++) {
@@ -480,19 +528,46 @@ 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] = _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;
+         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 */
+            GLfloat w = span->w;
+            GLfloat dwdx = span->dwdx;
+            assert(span->interpMask & SPAN_W);
+            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;
+               w += dwdx;
+            }
          }
          span->arrayMask |= SPAN_LAMBDA;
       }
@@ -508,7 +583,24 @@ 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++) {
@@ -1007,7 +1099,7 @@ _swrast_write_rgba_span( GLcontext *ctx, struct sw_span *span)
 
    /* Fragment program */
    if (ctx->FragmentProgram.Enabled) {
-      /* Now we may need to interpolate the colors */
+      /* Now we may need to interpolate the colors and texcoords */
       if ((span->interpMask & SPAN_RGBA) &&
           (span->arrayMask & SPAN_RGBA) == 0) {
          interpolate_colors(ctx, span);
@@ -1016,6 +1108,9 @@ _swrast_write_rgba_span( GLcontext *ctx, struct sw_span *span)
       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;
    }