From d8b82147c3cb17a06bf41e97141b8427b4580459 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Sun, 18 Apr 2004 20:11:52 +0000 Subject: [PATCH] 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. --- src/mesa/shader/nvfragparse.c | 2 +- src/mesa/shader/nvfragprog.h | 3 +- src/mesa/swrast/s_nvfragprog.c | 37 +++++--- src/mesa/swrast/s_span.c | 159 ++++++++++++++++++++++++++------- 4 files changed, 157 insertions(+), 44 deletions(-) diff --git a/src/mesa/shader/nvfragparse.c b/src/mesa/shader/nvfragparse.c index bdc2c7ef94a..264c1705fc4 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 53f4bf9905c..ae26a7b5743 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 f7510bf3ddf..6529022fe93 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 d164ad961ad..b74f62b6c68 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; } -- 2.30.2