summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Paul <brian.paul@tungstengraphics.com>2004-04-18 20:11:52 +0000
committerBrian Paul <brian.paul@tungstengraphics.com>2004-04-18 20:11:52 +0000
commitd8b82147c3cb17a06bf41e97141b8427b4580459 (patch)
tree6d8363f5d5fba37f1c128f21f2003778cbad986e
parentc83d09e3b09b0b7a48eb0e025c220e95453c2033 (diff)
Audit/fixes for NV/ARB TEX, TXP, TXB, TXD instructions.
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.
-rw-r--r--src/mesa/shader/nvfragparse.c2
-rw-r--r--src/mesa/shader/nvfragprog.h3
-rw-r--r--src/mesa/swrast/s_nvfragprog.c37
-rw-r--r--src/mesa/swrast/s_span.c159
4 files changed, 157 insertions, 44 deletions
diff --git a/src/mesa/shader/nvfragparse.c b/src/mesa/shader/nvfragparse.c
index bdc2c7ef94..264c1705fc 100644
--- a/src/mesa/shader/nvfragparse.c
+++ b/src/mesa/shader/nvfragparse.c
@@ -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 },
diff --git a/src/mesa/shader/nvfragprog.h b/src/mesa/shader/nvfragprog.h
index 53f4bf9905..ae26a7b574 100644
--- a/src/mesa/shader/nvfragprog.h
+++ b/src/mesa/shader/nvfragprog.h
@@ -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 */
diff --git a/src/mesa/swrast/s_nvfragprog.c b/src/mesa/swrast/s_nvfragprog.c
index f7510bf3dd..6529022fe9 100644
--- a/src/mesa/swrast/s_nvfragprog.c
+++ b/src/mesa/swrast/s_nvfragprog.c
@@ -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 );
diff --git a/src/mesa/swrast/s_span.c b/src/mesa/swrast/s_span.c
index d164ad961a..b74f62b6c6 100644
--- a/src/mesa/swrast/s_span.c
+++ b/src/mesa/swrast/s_span.c
@@ -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;
}