diff options
Diffstat (limited to 'src/mesa/main/texenvprogram.c')
-rw-r--r-- | src/mesa/main/texenvprogram.c | 254 |
1 files changed, 153 insertions, 101 deletions
diff --git a/src/mesa/main/texenvprogram.c b/src/mesa/main/texenvprogram.c index 3e5d65c8755..2f3e47e69ec 100644 --- a/src/mesa/main/texenvprogram.c +++ b/src/mesa/main/texenvprogram.c @@ -27,8 +27,7 @@ **************************************************************************/ #include "glheader.h" -#include "macros.h" -#include "enums.h" +#include "imports.h" #include "shader/program.h" #include "shader/prog_parameter.h" #include "shader/prog_cache.h" @@ -83,8 +82,13 @@ texenv_doing_secondary_color(GLcontext *ctx) #define DISASSEM (MESA_VERBOSE & VERBOSE_DISASSEM) struct mode_opt { - GLuint Source:4; - GLuint Operand:3; +#ifdef __GNUC__ + __extension__ GLubyte Source:4; /**< SRC_x */ + __extension__ GLubyte Operand:3; /**< OPR_x */ +#else + GLubyte Source; /**< SRC_x */ + GLubyte Operand; /**< OPR_x */ +#endif }; struct state_key { @@ -92,24 +96,26 @@ struct state_key { GLuint enabled_units:8; GLuint separate_specular:1; GLuint fog_enabled:1; - GLuint fog_mode:2; + GLuint fog_mode:2; /**< FOG_x */ GLuint inputs_available:12; + /* NOTE: This array of structs must be last! (see "keySize" below) */ struct { GLuint enabled:1; - GLuint source_index:3; /* one of TEXTURE_1D/2D/3D/CUBE/RECT_INDEX */ + GLuint source_index:3; /**< TEXTURE_x_INDEX */ GLuint shadow:1; GLuint ScaleShiftRGB:2; GLuint ScaleShiftA:2; - GLuint NumArgsRGB:3; - GLuint ModeRGB:5; - struct mode_opt OptRGB[MAX_COMBINER_TERMS]; + GLuint NumArgsRGB:3; /**< up to MAX_COMBINER_TERMS */ + GLuint ModeRGB:5; /**< MODE_x */ - GLuint NumArgsA:3; - GLuint ModeA:5; + GLuint NumArgsA:3; /**< up to MAX_COMBINER_TERMS */ + GLuint ModeA:5; /**< MODE_x */ + + struct mode_opt OptRGB[MAX_COMBINER_TERMS]; struct mode_opt OptA[MAX_COMBINER_TERMS]; - } unit[8]; + } unit[MAX_TEXTURE_UNITS]; }; #define FOG_LINEAR 0 @@ -240,25 +246,51 @@ static GLuint translate_mode( GLenum envMode, GLenum mode ) } } -#define TEXTURE_UNKNOWN_INDEX 7 -static GLuint translate_tex_src_bit( GLbitfield bit ) + +/** + * Do we need to clamp the results of the given texture env/combine mode? + * If the inputs to the mode are in [0,1] we don't always have to clamp + * the results. + */ +static GLboolean +need_saturate( GLuint mode ) { - /* make sure number of switch cases is correct */ - assert(NUM_TEXTURE_TARGETS == 7); - switch (bit) { - case TEXTURE_1D_BIT: return TEXTURE_1D_INDEX; - case TEXTURE_2D_BIT: return TEXTURE_2D_INDEX; - case TEXTURE_RECT_BIT: return TEXTURE_RECT_INDEX; - case TEXTURE_3D_BIT: return TEXTURE_3D_INDEX; - case TEXTURE_CUBE_BIT: return TEXTURE_CUBE_INDEX; - case TEXTURE_1D_ARRAY_BIT: return TEXTURE_1D_ARRAY_INDEX; - case TEXTURE_2D_ARRAY_BIT: return TEXTURE_2D_ARRAY_INDEX; + switch (mode) { + case MODE_REPLACE: + case MODE_MODULATE: + case MODE_INTERPOLATE: + return GL_FALSE; + case MODE_ADD: + case MODE_ADD_SIGNED: + case MODE_SUBTRACT: + case MODE_DOT3_RGB: + case MODE_DOT3_RGB_EXT: + case MODE_DOT3_RGBA: + case MODE_DOT3_RGBA_EXT: + case MODE_MODULATE_ADD_ATI: + case MODE_MODULATE_SIGNED_ADD_ATI: + case MODE_MODULATE_SUBTRACT_ATI: + case MODE_ADD_PRODUCTS: + case MODE_ADD_PRODUCTS_SIGNED: + case MODE_BUMP_ENVMAP_ATI: + return GL_TRUE; default: assert(0); - return TEXTURE_UNKNOWN_INDEX; } } + + +/** + * Translate TEXTURE_x_BIT to TEXTURE_x_INDEX. + */ +static GLuint translate_tex_src_bit( GLbitfield bit ) +{ + ASSERT(bit); + return _mesa_ffs(bit) - 1; +} + + #define VERT_BIT_TEX_ANY (0xff << VERT_ATTRIB_TEX0) #define VERT_RESULT_TEX_ANY (0xff << VERT_RESULT_TEX0) @@ -371,55 +403,55 @@ static GLbitfield get_fp_input_mask( GLcontext *ctx ) * Examine current texture environment state and generate a unique * key to identify it. */ -static void make_state_key( GLcontext *ctx, struct state_key *key ) +static GLuint make_state_key( GLcontext *ctx, struct state_key *key ) { GLuint i, j; GLbitfield inputs_referenced = FRAG_BIT_COL0; - GLbitfield inputs_available = get_fp_input_mask( ctx ); + const GLbitfield inputs_available = get_fp_input_mask( ctx ); + GLuint keySize; memset(key, 0, sizeof(*key)); /* _NEW_TEXTURE */ for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; + const struct gl_texture_object *texObj = texUnit->_Current; + const struct gl_tex_env_combine_state *comb = texUnit->_CurrentCombine; GLenum format; if (!texUnit->_ReallyEnabled || !texUnit->Enabled) continue; - format = texUnit->_Current->Image[0][texUnit->_Current->BaseLevel]->_BaseFormat; + format = texObj->Image[0][texObj->BaseLevel]->_BaseFormat; key->unit[i].enabled = 1; key->enabled_units |= (1<<i); - key->nr_enabled_units = i+1; + key->nr_enabled_units = i + 1; inputs_referenced |= FRAG_BIT_TEX(i); - key->unit[i].source_index = - translate_tex_src_bit(texUnit->_ReallyEnabled); - key->unit[i].shadow = ((texUnit->_Current->CompareMode == GL_COMPARE_R_TO_TEXTURE) && + key->unit[i].source_index = + translate_tex_src_bit(texUnit->_ReallyEnabled); + + key->unit[i].shadow = ((texObj->CompareMode == GL_COMPARE_R_TO_TEXTURE) && ((format == GL_DEPTH_COMPONENT) || (format == GL_DEPTH_STENCIL_EXT))); - key->unit[i].NumArgsRGB = texUnit->_CurrentCombine->_NumArgsRGB; - key->unit[i].NumArgsA = texUnit->_CurrentCombine->_NumArgsA; + key->unit[i].NumArgsRGB = comb->_NumArgsRGB; + key->unit[i].NumArgsA = comb->_NumArgsA; key->unit[i].ModeRGB = - translate_mode(texUnit->EnvMode, texUnit->_CurrentCombine->ModeRGB); + translate_mode(texUnit->EnvMode, comb->ModeRGB); key->unit[i].ModeA = - translate_mode(texUnit->EnvMode, texUnit->_CurrentCombine->ModeA); + translate_mode(texUnit->EnvMode, comb->ModeA); - key->unit[i].ScaleShiftRGB = texUnit->_CurrentCombine->ScaleShiftRGB; - key->unit[i].ScaleShiftA = texUnit->_CurrentCombine->ScaleShiftA; + key->unit[i].ScaleShiftRGB = comb->ScaleShiftRGB; + key->unit[i].ScaleShiftA = comb->ScaleShiftA; for (j = 0; j < MAX_COMBINER_TERMS; j++) { - key->unit[i].OptRGB[j].Operand = - translate_operand(texUnit->_CurrentCombine->OperandRGB[j]); - key->unit[i].OptA[j].Operand = - translate_operand(texUnit->_CurrentCombine->OperandA[j]); - key->unit[i].OptRGB[j].Source = - translate_source(texUnit->_CurrentCombine->SourceRGB[j]); - key->unit[i].OptA[j].Source = - translate_source(texUnit->_CurrentCombine->SourceA[j]); + key->unit[i].OptRGB[j].Operand = translate_operand(comb->OperandRGB[j]); + key->unit[i].OptA[j].Operand = translate_operand(comb->OperandA[j]); + key->unit[i].OptRGB[j].Source = translate_source(comb->SourceRGB[j]); + key->unit[i].OptA[j].Source = translate_source(comb->SourceA[j]); } if (key->unit[i].ModeRGB == MODE_BUMP_ENVMAP_ATI) { @@ -447,8 +479,15 @@ static void make_state_key( GLcontext *ctx, struct state_key *key ) } key->inputs_available = (inputs_available & inputs_referenced); + + /* compute size of state key, ignoring unused texture units */ + keySize = sizeof(*key) - sizeof(key->unit) + + key->nr_enabled_units * sizeof(key->unit[0]); + + return keySize; } + /** * Use uregs to represent registers internally, translate to Mesa's * expected formats on emit. @@ -466,10 +505,8 @@ struct ureg { GLuint file:4; GLuint idx:8; GLuint negatebase:1; - GLuint abs:1; - GLuint negateabs:1; GLuint swz:12; - GLuint pad:5; + GLuint pad:7; }; static const struct ureg undef = { @@ -477,8 +514,6 @@ static const struct ureg undef = { ~0, 0, 0, - 0, - 0, 0 }; @@ -487,7 +522,6 @@ static const struct ureg undef = { */ struct texenv_fragment_program { struct gl_fragment_program *program; - GLcontext *ctx; struct state_key *state; GLbitfield alu_temps; /**< Track texture indirections, see spec. */ @@ -524,8 +558,6 @@ static struct ureg make_ureg(GLuint file, GLuint idx) reg.file = file; reg.idx = idx; reg.negatebase = 0; - reg.abs = 0; - reg.negateabs = 0; reg.swz = SWIZZLE_NOOP; reg.pad = 0; return reg; @@ -691,7 +723,7 @@ static void emit_arg( struct prog_src_register *reg, reg->Index = ureg.idx; reg->Swizzle = ureg.swz; reg->Negate = ureg.negatebase ? NEGATE_XYZW : NEGATE_NONE; - reg->Abs = ureg.abs; + reg->Abs = GL_FALSE; } static void emit_dst( struct prog_dst_register *dst, @@ -714,7 +746,7 @@ emit_op(struct texenv_fragment_program *p, struct ureg src1, struct ureg src2 ) { - GLuint nr = p->program->Base.NumInstructions++; + const GLuint nr = p->program->Base.NumInstructions++; struct prog_instruction *inst = &p->program->Base.Instructions[nr]; assert(nr < MAX_INSTRUCTIONS); @@ -952,17 +984,22 @@ static struct ureg emit_combine_source( struct texenv_fragment_program *p, } } +/** + * Check if the RGB and Alpha sources and operands match for the given + * texture unit's combinder state. When the RGB and A sources and + * operands match, we can emit fewer instructions. + */ static GLboolean args_match( const struct state_key *key, GLuint unit ) { - GLuint i, nr = key->unit[unit].NumArgsRGB; + GLuint i, numArgs = key->unit[unit].NumArgsRGB; - for (i = 0 ; i < nr ; i++) { + for (i = 0; i < numArgs; i++) { if (key->unit[unit].OptA[i].Source != key->unit[unit].OptRGB[i].Source) return GL_FALSE; - switch(key->unit[unit].OptA[i].Operand) { + switch (key->unit[unit].OptA[i].Operand) { case OPR_SRC_ALPHA: - switch(key->unit[unit].OptRGB[i].Operand) { + switch (key->unit[unit].OptRGB[i].Operand) { case OPR_SRC_COLOR: case OPR_SRC_ALPHA: break; @@ -971,7 +1008,7 @@ static GLboolean args_match( const struct state_key *key, GLuint unit ) } break; case OPR_ONE_MINUS_SRC_ALPHA: - switch(key->unit[unit].OptRGB[i].Operand) { + switch (key->unit[unit].OptRGB[i].Operand) { case OPR_ONE_MINUS_SRC_COLOR: case OPR_ONE_MINUS_SRC_ALPHA: break; @@ -1113,7 +1150,7 @@ static struct ureg emit_texenv(struct texenv_fragment_program *p, GLuint unit) { const struct state_key *key = p->state; - GLboolean saturate; + GLboolean rgb_saturate, alpha_saturate; GLuint rgb_shift, alpha_shift; struct ureg out, dest; @@ -1143,7 +1180,19 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit) /* If we'll do rgb/alpha shifting don't saturate in emit_combine(). * We don't want to clamp twice. */ - saturate = !(rgb_shift || alpha_shift); + if (rgb_shift) + rgb_saturate = GL_FALSE; /* saturate after rgb shift */ + else if (need_saturate(key->unit[unit].ModeRGB)) + rgb_saturate = GL_TRUE; + else + rgb_saturate = GL_FALSE; + + if (alpha_shift) + alpha_saturate = GL_FALSE; /* saturate after alpha shift */ + else if (need_saturate(key->unit[unit].ModeA)) + alpha_saturate = GL_TRUE; + else + alpha_saturate = GL_FALSE; /* If this is the very last calculation, emit direct to output reg: */ @@ -1159,7 +1208,7 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit) */ if (key->unit[unit].ModeRGB == key->unit[unit].ModeA && args_match(key, unit)) { - out = emit_combine( p, dest, WRITEMASK_XYZW, saturate, + out = emit_combine( p, dest, WRITEMASK_XYZW, rgb_saturate, unit, key->unit[unit].NumArgsRGB, key->unit[unit].ModeRGB, @@ -1167,7 +1216,7 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit) } else if (key->unit[unit].ModeRGB == MODE_DOT3_RGBA_EXT || key->unit[unit].ModeRGB == MODE_DOT3_RGBA) { - out = emit_combine( p, dest, WRITEMASK_XYZW, saturate, + out = emit_combine( p, dest, WRITEMASK_XYZW, rgb_saturate, unit, key->unit[unit].NumArgsRGB, key->unit[unit].ModeRGB, @@ -1177,12 +1226,12 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit) /* Need to do something to stop from re-emitting identical * argument calculations here: */ - out = emit_combine( p, dest, WRITEMASK_XYZ, saturate, + out = emit_combine( p, dest, WRITEMASK_XYZ, rgb_saturate, unit, key->unit[unit].NumArgsRGB, key->unit[unit].ModeRGB, key->unit[unit].OptRGB); - out = emit_combine( p, dest, WRITEMASK_W, saturate, + out = emit_combine( p, dest, WRITEMASK_W, alpha_saturate, unit, key->unit[unit].NumArgsA, key->unit[unit].ModeA, @@ -1193,8 +1242,7 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit) */ if (alpha_shift || rgb_shift) { struct ureg shift; - - saturate = GL_TRUE; /* always saturate at this point */ + GLboolean saturate = GL_TRUE; /* always saturate at this point */ if (rgb_shift == alpha_shift) { shift = register_scalar_const(p, (GLfloat)(1<<rgb_shift)); @@ -1220,7 +1268,7 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit) static void load_texture( struct texenv_fragment_program *p, GLuint unit ) { if (is_undef(p->src_texture[unit])) { - GLuint texTarget = p->state->unit[unit].source_index; + const GLuint texTarget = p->state->unit[unit].source_index; struct ureg texcoord; struct ureg tmp = get_tex_temp( p ); @@ -1232,9 +1280,6 @@ static void load_texture( struct texenv_fragment_program *p, GLuint unit ) texcoord = p->texcoord_tex[unit]; } - if (texTarget == TEXTURE_UNKNOWN_INDEX) - program_error(p, "TexSrcBit"); - /* TODO: Use D0_MASK_XY where possible. */ if (p->state->unit[unit].enabled) { @@ -1293,7 +1338,7 @@ static GLboolean load_texenv_source( struct texenv_fragment_program *p, * Generate instructions for loading all texture source terms. */ static GLboolean -load_texunit_sources( struct texenv_fragment_program *p, int unit ) +load_texunit_sources( struct texenv_fragment_program *p, GLuint unit ) { const struct state_key *key = p->state; GLuint i; @@ -1313,7 +1358,7 @@ load_texunit_sources( struct texenv_fragment_program *p, int unit ) * Generate instructions for loading bump map textures. */ static GLboolean -load_texunit_bumpmap( struct texenv_fragment_program *p, int unit ) +load_texunit_bumpmap( struct texenv_fragment_program *p, GLuint unit ) { const struct state_key *key = p->state; GLuint bumpedUnitNr = key->unit[unit].OptRGB[1].Source - SRC_TEXTURE0; @@ -1329,17 +1374,20 @@ load_texunit_bumpmap( struct texenv_fragment_program *p, int unit ) texcDst = get_tex_temp( p ); p->texcoord_tex[bumpedUnitNr] = texcDst; - /* apply rot matrix and add coords to be available in next phase */ - /* dest = (Arg0.xxxx * rotMat0 + Arg1) + (Arg0.yyyy * rotMat1) */ - /* note only 2 coords are affected the rest are left unchanged (mul by 0) */ + /* Apply rot matrix and add coords to be available in next phase. + * dest = (Arg0.xxxx * rotMat0 + Arg1) + (Arg0.yyyy * rotMat1) + * note only 2 coords are affected the rest are left unchanged (mul by 0) + */ emit_arith( p, OPCODE_MAD, texcDst, WRITEMASK_XYZW, 0, swizzle1(bumpMapRes, SWIZZLE_X), rotMat0, texcSrc ); emit_arith( p, OPCODE_MAD, texcDst, WRITEMASK_XYZW, 0, swizzle1(bumpMapRes, SWIZZLE_Y), rotMat1, texcDst ); - /* move 0,0,0,1 into bumpmap src if someone (crossbar) is foolish - enough to access this later, should optimize away */ - emit_arith( p, OPCODE_MOV, bumpMapRes, WRITEMASK_XYZW, 0, constdudvcolor, undef, undef ); + /* Move 0,0,0,1 into bumpmap src if someone (crossbar) is foolish + * enough to access this later, should optimize away. + */ + emit_arith( p, OPCODE_MOV, bumpMapRes, WRITEMASK_XYZW, 0, + constdudvcolor, undef, undef ); return GL_TRUE; } @@ -1358,7 +1406,6 @@ create_new_program(GLcontext *ctx, struct state_key *key, struct ureg cf, out; _mesa_memset(&p, 0, sizeof(p)); - p.ctx = ctx; p.state = key; p.program = program; @@ -1367,17 +1414,17 @@ create_new_program(GLcontext *ctx, struct state_key *key, */ p.program->Base.Instructions = instBuffer; p.program->Base.Target = GL_FRAGMENT_PROGRAM_ARB; - p.program->Base.NumTexIndirections = 1; + p.program->Base.String = NULL; + p.program->Base.NumTexIndirections = 1; /* is this right? */ p.program->Base.NumTexInstructions = 0; p.program->Base.NumAluInstructions = 0; - p.program->Base.String = NULL; - p.program->Base.NumInstructions = - p.program->Base.NumTemporaries = - p.program->Base.NumParameters = - p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0; + p.program->Base.NumInstructions = 0; + p.program->Base.NumTemporaries = 0; + p.program->Base.NumParameters = 0; + p.program->Base.NumAttributes = 0; + p.program->Base.NumAddressRegs = 0; p.program->Base.Parameters = _mesa_new_parameter_list(); - - p.program->Base.InputsRead = 0; + p.program->Base.InputsRead = 0x0; p.program->Base.OutputsWritten = 1 << FRAG_RESULT_COLOR; for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { @@ -1394,10 +1441,12 @@ create_new_program(GLcontext *ctx, struct state_key *key, release_temps(ctx, &p); if (key->enabled_units) { - GLboolean needbumpstage = GL_FALSE; + GLboolean needbumpstage = GL_FALSE; + /* Zeroth pass - bump map textures first */ - for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++) - if (key->unit[unit].enabled && key->unit[unit].ModeRGB == MODE_BUMP_ENVMAP_ATI) { + for (unit = 0; unit < key->nr_enabled_units; unit++) + if (key->unit[unit].enabled && + key->unit[unit].ModeRGB == MODE_BUMP_ENVMAP_ATI) { needbumpstage = GL_TRUE; load_texunit_bumpmap( &p, unit ); } @@ -1408,7 +1457,7 @@ create_new_program(GLcontext *ctx, struct state_key *key, * all referenced texture sources and emit texld instructions * for each: */ - for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++) + for (unit = 0; unit < key->nr_enabled_units; unit++) if (key->unit[unit].enabled) { load_texunit_sources( &p, unit ); p.last_tex_stage = unit; @@ -1416,8 +1465,8 @@ create_new_program(GLcontext *ctx, struct state_key *key, /* Second pass - emit combine instructions to build final color: */ - for (unit = 0 ; unit < ctx->Const.MaxTextureUnits; unit++) - if (key->enabled_units & (1<<unit)) { + for (unit = 0; unit < key->nr_enabled_units; unit++) + if (key->unit[unit].enabled) { p.src_previous = emit_texenv( &p, unit ); reserve_temp(&p, p.src_previous); /* don't re-use this temp reg */ release_temps(ctx, &p); /* release all temps */ @@ -1450,9 +1499,11 @@ create_new_program(GLcontext *ctx, struct state_key *key, * a reduced value and not what is expected in FogOption */ p.program->FogOption = ctx->Fog.Mode; - p.program->Base.InputsRead |= FRAG_BIT_FOGC; /* XXX new */ - } else + p.program->Base.InputsRead |= FRAG_BIT_FOGC; + } + else { p.program->FogOption = GL_NONE; + } if (p.program->Base.NumTexIndirections > ctx->Const.FragmentProgram.MaxTexIndirections) program_error(&p, "Exceeded max nr indirect texture lookups"); @@ -1505,12 +1556,13 @@ _mesa_get_fixed_func_fragment_program(GLcontext *ctx) { struct gl_fragment_program *prog; struct state_key key; + GLuint keySize; - make_state_key(ctx, &key); + keySize = make_state_key(ctx, &key); prog = (struct gl_fragment_program *) _mesa_search_program_cache(ctx->FragmentProgram.Cache, - &key, sizeof(key)); + &key, keySize); if (!prog) { prog = (struct gl_fragment_program *) @@ -1519,7 +1571,7 @@ _mesa_get_fixed_func_fragment_program(GLcontext *ctx) create_new_program(ctx, &key, prog); _mesa_program_cache_insert(ctx, ctx->FragmentProgram.Cache, - &key, sizeof(key), &prog->Base); + &key, keySize, &prog->Base); } return prog; |