diff options
Diffstat (limited to 'src/mesa/main')
-rw-r--r-- | src/mesa/main/texenvprogram.c | 86 |
1 files changed, 53 insertions, 33 deletions
diff --git a/src/mesa/main/texenvprogram.c b/src/mesa/main/texenvprogram.c index 0c2caa0169e..73681b1a6b2 100644 --- a/src/mesa/main/texenvprogram.c +++ b/src/mesa/main/texenvprogram.c @@ -82,9 +82,8 @@ struct texenv_fragment_program { struct fragment_program *program; GLcontext *ctx; - GLuint temp_used_for_txp; /* Temps which have been the result of a texture - * operation. - */ + GLuint alu_temps; /* Track texture indirections, see spec. */ + GLuint temps_output; /* Track texture indirections, see spec. */ GLuint temp_in_use; /* Tracks temporary regs which are in * use. @@ -144,10 +143,9 @@ static struct ureg get_temp( struct texenv_fragment_program *p ) { int bit; - /* First try and reuse temps which have been used for texture - * results: + /* First try and reuse temps which have been used already: */ - bit = ffs( ~p->temp_in_use & p->temp_used_for_txp ); + bit = ffs( ~p->temp_in_use & p->alu_temps ); /* Then any unused temporary: */ @@ -167,17 +165,17 @@ static struct ureg get_tex_temp( struct texenv_fragment_program *p ) { int bit; - /* First try to find availble temp not previously used as a texture - * result: + /* First try to find availble temp not previously used (to avoid + * starting a new texture indirection). According to the spec, the + * ~p->temps_output isn't necessary, but will keep it there for + * now: */ - bit = ffs( ~p->temp_in_use & ~p->temp_used_for_txp ); + bit = ffs( ~p->temp_in_use & ~p->alu_temps & ~p->temps_output ); /* Then any unused temporary: */ - if (!bit) { + if (!bit) bit = ffs( ~p->temp_in_use ); - p->program->NumTexIndirections++; - } if (!bit) { fprintf(stderr, "%s: out of temporaries\n", __FILE__); @@ -185,7 +183,6 @@ static struct ureg get_tex_temp( struct texenv_fragment_program *p ) } p->temp_in_use |= 1<<(bit-1); - p->temp_used_for_txp |= 1<<(bit-1); return make_ureg(PROGRAM_TEMPORARY, (bit-1)); } @@ -280,6 +277,11 @@ emit_op(struct texenv_fragment_program *p, emit_dst( &inst->DstReg, dest, mask ); + /* Accounting for indirection tracking: + */ + if (dest.file == PROGRAM_TEMPORARY) + p->temps_output |= 1 << dest.idx; + return inst; } @@ -295,6 +297,20 @@ static struct ureg emit_arith( struct texenv_fragment_program *p, { emit_op(p, op, dest, mask, saturate, src0, src1, src2); + /* Accounting for indirection tracking: + */ + if (src0.file == PROGRAM_TEMPORARY) + p->alu_temps |= 1 << src0.idx; + + if (!is_undef(src1) && src1.file == PROGRAM_TEMPORARY) + p->alu_temps |= 1 << src1.idx; + + if (!is_undef(src2) && src2.file == PROGRAM_TEMPORARY) + p->alu_temps |= 1 << src2.idx; + + if (dest.file == PROGRAM_TEMPORARY) + p->alu_temps |= 1 << dest.idx; + p->program->NumAluInstructions++; return dest; } @@ -319,10 +335,15 @@ static struct ureg emit_texld( struct texenv_fragment_program *p, p->program->NumTexInstructions++; - if (coord.file != PROGRAM_INPUT && - (coord.idx < FRAG_ATTRIB_TEX0 || - coord.idx > FRAG_ATTRIB_TEX7)) { + /* Is this a texture indirection? + */ + if ((coord.file == PROGRAM_TEMPORARY && + (p->temps_output & (1<<coord.idx))) || + (dest.file == PROGRAM_TEMPORARY && + (p->alu_temps & (1<<dest.idx)))) { p->program->NumTexIndirections++; + p->temps_output = 0; + p->alu_temps = 0; } return dest; @@ -529,7 +550,7 @@ static struct ureg emit_combine( struct texenv_fragment_program *p, { int nr = nr_args(mode); struct ureg src[3]; - struct ureg tmp; + struct ureg tmp, half; int i; for (i = 0; i < nr; i++) @@ -549,11 +570,11 @@ static struct ureg emit_combine( struct texenv_fragment_program *p, src[0], src[1], undef ); case GL_ADD_SIGNED: /* tmp = arg0 + arg1 - * result = tmp + -.5 + * result = tmp - .5 */ - tmp = register_scalar_const(p, .5); - emit_arith( p, FP_OPCODE_ADD, dest, mask, 0, src[0], src[1], undef ); - emit_arith( p, FP_OPCODE_SUB, dest, mask, saturate, dest, tmp, undef ); + half = register_scalar_const(p, .5); + emit_arith( p, FP_OPCODE_ADD, tmp, mask, 0, src[0], src[1], undef ); + emit_arith( p, FP_OPCODE_SUB, dest, mask, saturate, tmp, half, undef ); return dest; case GL_INTERPOLATE: /* Arg0 * (Arg2) + Arg1 * (1-Arg2) -- note arguments are reordered: @@ -594,16 +615,6 @@ static struct ureg emit_combine( struct texenv_fragment_program *p, } } -static struct ureg get_dest( struct texenv_fragment_program *p, int unit ) -{ - if (p->ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) - return get_temp( p ); - else if (unit != p->last_tex_stage) - return get_temp( p ); - else - return make_ureg(PROGRAM_OUTPUT, FRAG_OUTPUT_COLR); -} - static struct ureg emit_texenv( struct texenv_fragment_program *p, int unit ) @@ -612,7 +623,7 @@ static struct ureg emit_texenv( struct texenv_fragment_program *p, int unit ) GLuint saturate = (unit < p->last_tex_stage); GLuint rgb_shift, alpha_shift; struct ureg out, shift; - struct ureg dest = get_dest(p, unit); + struct ureg dest; if (!texUnit->_ReallyEnabled) { return get_source(p, GL_PREVIOUS, 0); @@ -635,6 +646,15 @@ static struct ureg emit_texenv( struct texenv_fragment_program *p, int unit ) break; } + /* If this is the very last calculation, emit direct to output reg: + */ + if ((p->ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) || + unit != p->last_tex_stage || + alpha_shift || + rgb_shift) + dest = get_temp( p ); + else + dest = make_ureg(PROGRAM_OUTPUT, FRAG_OUTPUT_COLR); /* Emit the RGB and A combine ops */ @@ -734,7 +754,7 @@ void _mesa_UpdateTexEnvProgram( GLcontext *ctx ) p.program->Parameters = _mesa_new_parameter_list(); p.program->InputsRead = 0; - p.program->OutputsWritten = 0; + p.program->OutputsWritten = 1 << FRAG_OUTPUT_COLR; p.src_texture = undef; p.src_previous = undef; |