X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ftexenvprogram.c;h=d7e77e759e096a578916764876bfb755e05324b1;hb=a73ba2d31b87e974f6846a8aaced704634f6f657;hp=8c588538b11082af2b24f539a7deb51738a5cec9;hpb=1480bcacfec8f215c5827278a5f984c6bf68ba69;p=mesa.git diff --git a/src/mesa/main/texenvprogram.c b/src/mesa/main/texenvprogram.c index 8c588538b11..d7e77e759e0 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; /**< SRC_x */ - GLuint Operand:3; /**< OPR_x */ +#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 { @@ -95,6 +99,7 @@ struct state_key { 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; /**< TEXTURE_x_INDEX */ @@ -104,10 +109,11 @@ struct state_key { GLuint NumArgsRGB:3; /**< up to MAX_COMBINER_TERMS */ GLuint ModeRGB:5; /**< MODE_x */ - struct mode_opt OptRGB[MAX_COMBINER_TERMS]; 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[MAX_TEXTURE_UNITS]; }; @@ -241,6 +247,41 @@ static GLuint translate_mode( GLenum envMode, GLenum mode ) } +/** + * 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 ) +{ + 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 GL_FALSE; + } +} + + + /** * Translate TEXTURE_x_BIT to TEXTURE_x_INDEX. */ @@ -363,11 +404,12 @@ 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; const GLbitfield inputs_available = get_fp_input_mask( ctx ); + GLuint keySize; memset(key, 0, sizeof(*key)); @@ -385,7 +427,7 @@ static void make_state_key( GLcontext *ctx, struct state_key *key ) key->unit[i].enabled = 1; key->enabled_units |= (1<nr_enabled_units = i+1; + key->nr_enabled_units = i + 1; inputs_referenced |= FRAG_BIT_TEX(i); key->unit[i].source_index = @@ -438,8 +480,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. @@ -474,7 +523,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. */ @@ -946,7 +994,7 @@ static GLboolean args_match( const struct state_key *key, GLuint unit ) { GLuint i, numArgs = key->unit[unit].NumArgsRGB; - for (i = 0 ; i < numArgs ; i++) { + for (i = 0; i < numArgs; i++) { if (key->unit[unit].OptA[i].Source != key->unit[unit].OptRGB[i].Source) return GL_FALSE; @@ -1103,7 +1151,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; @@ -1133,7 +1181,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: */ @@ -1149,7 +1209,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, @@ -1157,7 +1217,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, @@ -1167,12 +1227,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, @@ -1183,8 +1243,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<state; GLuint i; @@ -1300,7 +1359,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; @@ -1316,17 +1375,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; } @@ -1345,7 +1407,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; @@ -1354,17 +1415,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++) { @@ -1381,10 +1442,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 ); } @@ -1395,7 +1458,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; @@ -1403,8 +1466,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<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 */ @@ -1437,9 +1500,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"); @@ -1492,12 +1557,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 *) @@ -1506,7 +1572,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;