diff options
Diffstat (limited to 'nx-X11/extras/Mesa/src/mesa/main/texenvprogram.c')
-rw-r--r-- | nx-X11/extras/Mesa/src/mesa/main/texenvprogram.c | 1165 |
1 files changed, 0 insertions, 1165 deletions
diff --git a/nx-X11/extras/Mesa/src/mesa/main/texenvprogram.c b/nx-X11/extras/Mesa/src/mesa/main/texenvprogram.c deleted file mode 100644 index 4cb97469a..000000000 --- a/nx-X11/extras/Mesa/src/mesa/main/texenvprogram.c +++ /dev/null @@ -1,1165 +0,0 @@ -/************************************************************************** - * - * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include "glheader.h" -#include "macros.h" -#include "enums.h" -#include "texenvprogram.h" - -#include "shader/program.h" -#include "shader/nvfragprog.h" -#include "shader/arbfragparse.h" - - -#define DISASSEM (MESA_VERBOSE & VERBOSE_DISASSEM) - -struct mode_opt { - unsigned Source:4; - unsigned Operand:3; -}; - -struct state_key { - GLuint enabled_units; - unsigned separate_specular:1; - unsigned fog_enabled:1; - unsigned fog_mode:2; - - struct { - unsigned enabled:1; - unsigned source_index:3; - unsigned ScaleShiftRGB:2; - unsigned ScaleShiftA:2; - - unsigned NumArgsRGB:2; - unsigned ModeRGB:4; - struct mode_opt OptRGB[3]; - - unsigned NumArgsA:2; - unsigned ModeA:4; - struct mode_opt OptA[3]; - } unit[8]; -}; - -#define FOG_LINEAR 0 -#define FOG_EXP 1 -#define FOG_EXP2 2 -#define FOG_UNKNOWN 3 - -static GLuint translate_fog_mode( GLenum mode ) -{ - switch (mode) { - case GL_LINEAR: return FOG_LINEAR; - case GL_EXP: return FOG_EXP; - case GL_EXP2: return FOG_EXP2; - default: return FOG_UNKNOWN; - } -} - -#define OPR_SRC_COLOR 0 -#define OPR_ONE_MINUS_SRC_COLOR 1 -#define OPR_SRC_ALPHA 2 -#define OPR_ONE_MINUS_SRC_ALPHA 3 -#define OPR_ZERO 4 -#define OPR_ONE 5 -#define OPR_UNKNOWN 7 - -static GLuint translate_operand( GLenum operand ) -{ - switch (operand) { - case GL_SRC_COLOR: return OPR_SRC_COLOR; - case GL_ONE_MINUS_SRC_COLOR: return OPR_ONE_MINUS_SRC_COLOR; - case GL_SRC_ALPHA: return OPR_SRC_ALPHA; - case GL_ONE_MINUS_SRC_ALPHA: return OPR_ONE_MINUS_SRC_ALPHA; - case GL_ZERO: return OPR_ZERO; - case GL_ONE: return OPR_ONE; - default: return OPR_UNKNOWN; - } -} - -#define SRC_TEXTURE 0 -#define SRC_TEXTURE0 1 -#define SRC_TEXTURE1 2 -#define SRC_TEXTURE2 3 -#define SRC_TEXTURE3 4 -#define SRC_TEXTURE4 5 -#define SRC_TEXTURE5 6 -#define SRC_TEXTURE6 7 -#define SRC_TEXTURE7 8 -#define SRC_CONSTANT 9 -#define SRC_PRIMARY_COLOR 10 -#define SRC_PREVIOUS 11 -#define SRC_UNKNOWN 15 - -static GLuint translate_source( GLenum src ) -{ - switch (src) { - case GL_TEXTURE: return SRC_TEXTURE; - case GL_TEXTURE0: - case GL_TEXTURE1: - case GL_TEXTURE2: - case GL_TEXTURE3: - case GL_TEXTURE4: - case GL_TEXTURE5: - case GL_TEXTURE6: - case GL_TEXTURE7: return SRC_TEXTURE0 + (src - GL_TEXTURE0); - case GL_CONSTANT: return SRC_CONSTANT; - case GL_PRIMARY_COLOR: return SRC_PRIMARY_COLOR; - case GL_PREVIOUS: return SRC_PREVIOUS; - default: return SRC_UNKNOWN; - } -} - -#define MODE_REPLACE 0 -#define MODE_MODULATE 1 -#define MODE_ADD 2 -#define MODE_ADD_SIGNED 3 -#define MODE_INTERPOLATE 4 -#define MODE_SUBTRACT 5 -#define MODE_DOT3_RGB 6 -#define MODE_DOT3_RGB_EXT 7 -#define MODE_DOT3_RGBA 8 -#define MODE_DOT3_RGBA_EXT 9 -#define MODE_MODULATE_ADD_ATI 10 -#define MODE_MODULATE_SIGNED_ADD_ATI 11 -#define MODE_MODULATE_SUBTRACT_ATI 12 -#define MODE_UNKNOWN 15 - -static GLuint translate_mode( GLenum mode ) -{ - switch (mode) { - case GL_REPLACE: return MODE_REPLACE; - case GL_MODULATE: return MODE_MODULATE; - case GL_ADD: return MODE_ADD; - case GL_ADD_SIGNED: return MODE_ADD_SIGNED; - case GL_INTERPOLATE: return MODE_INTERPOLATE; - case GL_SUBTRACT: return MODE_SUBTRACT; - case GL_DOT3_RGB: return MODE_DOT3_RGB; - case GL_DOT3_RGB_EXT: return MODE_DOT3_RGB_EXT; - case GL_DOT3_RGBA: return MODE_DOT3_RGBA; - case GL_DOT3_RGBA_EXT: return MODE_DOT3_RGBA_EXT; - case GL_MODULATE_ADD_ATI: return MODE_MODULATE_ADD_ATI; - case GL_MODULATE_SIGNED_ADD_ATI: return MODE_MODULATE_SIGNED_ADD_ATI; - case GL_MODULATE_SUBTRACT_ATI: return MODE_MODULATE_SUBTRACT_ATI; - default: return MODE_UNKNOWN; - } -} - -#define TEXTURE_UNKNOWN_INDEX 7 -static GLuint translate_tex_src_bit( GLuint bit ) -{ - 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; - default: return TEXTURE_UNKNOWN_INDEX; - } -} - -static struct state_key *make_state_key( GLcontext *ctx ) -{ - struct state_key *key = CALLOC_STRUCT(state_key); - GLuint i, j; - - for (i=0;i<MAX_TEXTURE_UNITS;i++) { - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; - - if (!texUnit->_ReallyEnabled) - continue; - - key->unit[i].enabled = 1; - key->enabled_units |= (1<<i); - - key->unit[i].source_index = - translate_tex_src_bit(texUnit->_ReallyEnabled); - - key->unit[i].NumArgsRGB = texUnit->_CurrentCombine->_NumArgsRGB; - key->unit[i].NumArgsA = texUnit->_CurrentCombine->_NumArgsA; - - key->unit[i].ModeRGB = - translate_mode(texUnit->_CurrentCombine->ModeRGB); - key->unit[i].ModeA = - translate_mode(texUnit->_CurrentCombine->ModeA); - - key->unit[i].ScaleShiftRGB = texUnit->_CurrentCombine->ScaleShiftRGB; - key->unit[i].ScaleShiftA = texUnit->_CurrentCombine->ScaleShiftRGB; - - for (j=0;j<3;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]); - } - } - - if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) - key->separate_specular = 1; - - if (ctx->Fog.Enabled) { - key->fog_enabled = 1; - key->fog_mode = translate_fog_mode(ctx->Fog.Mode); - } - - return key; -} - -/* Use uregs to represent registers internally, translate to Mesa's - * expected formats on emit. - * - * NOTE: These are passed by value extensively in this file rather - * than as usual by pointer reference. If this disturbs you, try - * remembering they are just 32bits in size. - * - * GCC is smart enough to deal with these dword-sized structures in - * much the same way as if I had defined them as dwords and was using - * macros to access and set the fields. This is much nicer and easier - * to evolve. - */ -struct ureg { - GLuint file:4; - GLuint idx:8; - GLuint negatebase:1; - GLuint abs:1; - GLuint negateabs:1; - GLuint swz:12; - GLuint pad:5; -}; - -const static struct ureg undef = { - ~0, - ~0, - 0, - 0, - 0, - 0, - 0 -}; - -#define X 0 -#define Y 1 -#define Z 2 -#define W 3 - -/* State used to build the fragment program: - */ -struct texenv_fragment_program { - struct fragment_program *program; - GLcontext *ctx; - struct state_key *state; - - 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. - */ - - - GLboolean error; - - struct ureg src_texture[MAX_TEXTURE_UNITS]; - /* Reg containing each texture unit's sampled texture color, - * else undef. - */ - - struct ureg src_previous; /* Reg containing color from previous - * stage. May need to be decl'd. - */ - - GLuint last_tex_stage; /* Number of last enabled texture unit */ - - struct ureg half; - struct ureg one; - struct ureg zero; -}; - - - -static struct ureg make_ureg(GLuint file, GLuint idx) -{ - struct ureg reg; - reg.file = file; - reg.idx = idx; - reg.negatebase = 0; - reg.abs = 0; - reg.negateabs = 0; - reg.swz = SWIZZLE_NOOP; - reg.pad = 0; - return reg; -} - -static struct ureg swizzle( struct ureg reg, int x, int y, int z, int w ) -{ - reg.swz = MAKE_SWIZZLE4(GET_SWZ(reg.swz, x), - GET_SWZ(reg.swz, y), - GET_SWZ(reg.swz, z), - GET_SWZ(reg.swz, w)); - - return reg; -} - -static struct ureg swizzle1( struct ureg reg, int x ) -{ - return swizzle(reg, x, x, x, x); -} - -static struct ureg negate( struct ureg reg ) -{ - reg.negatebase ^= 1; - return reg; -} - -static GLboolean is_undef( struct ureg reg ) -{ - return reg.file == 0xf; -} - - -static struct ureg get_temp( struct texenv_fragment_program *p ) -{ - int bit; - - /* First try and reuse temps which have been used already: - */ - bit = ffs( ~p->temp_in_use & p->alu_temps ); - - /* Then any unused temporary: - */ - if (!bit) - bit = ffs( ~p->temp_in_use ); - - if (!bit) { - _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__); - exit(1); - } - - p->temp_in_use |= 1<<(bit-1); - return make_ureg(PROGRAM_TEMPORARY, (bit-1)); -} - -static struct ureg get_tex_temp( struct texenv_fragment_program *p ) -{ - int bit; - - /* 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->alu_temps & ~p->temps_output ); - - /* Then any unused temporary: - */ - if (!bit) - bit = ffs( ~p->temp_in_use ); - - if (!bit) { - _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__); - exit(1); - } - - p->temp_in_use |= 1<<(bit-1); - return make_ureg(PROGRAM_TEMPORARY, (bit-1)); -} - - -static void release_temps( struct texenv_fragment_program *p ) -{ - GLuint max_temp = p->ctx->Const.MaxFragmentProgramTemps; - - /* KW: To support tex_env_crossbar, don't release the registers in - * temps_output. - */ - if (max_temp >= sizeof(int) * 8) - p->temp_in_use = p->temps_output; - else - p->temp_in_use = ~((1<<max_temp)-1) | p->temps_output; -} - - -static struct ureg register_param6( struct texenv_fragment_program *p, - GLint s0, - GLint s1, - GLint s2, - GLint s3, - GLint s4, - GLint s5) -{ - GLint tokens[6]; - GLuint idx; - tokens[0] = s0; - tokens[1] = s1; - tokens[2] = s2; - tokens[3] = s3; - tokens[4] = s4; - tokens[5] = s5; - idx = _mesa_add_state_reference( p->program->Parameters, tokens ); - return make_ureg(PROGRAM_STATE_VAR, idx); -} - - -#define register_param1(p,s0) register_param6(p,s0,0,0,0,0,0) -#define register_param2(p,s0,s1) register_param6(p,s0,s1,0,0,0,0) -#define register_param3(p,s0,s1,s2) register_param6(p,s0,s1,s2,0,0,0) -#define register_param4(p,s0,s1,s2,s3) register_param6(p,s0,s1,s2,s3,0,0) - - -static struct ureg register_input( struct texenv_fragment_program *p, GLuint input ) -{ - p->program->InputsRead |= (1<<input); - return make_ureg(PROGRAM_INPUT, input); -} - - -static void emit_arg( struct fp_src_register *reg, - struct ureg ureg ) -{ - reg->File = ureg.file; - reg->Index = ureg.idx; - reg->Swizzle = ureg.swz; - reg->NegateBase = ureg.negatebase; - reg->Abs = ureg.abs; - reg->NegateAbs = ureg.negateabs; -} - -static void emit_dst( struct fp_dst_register *dst, - struct ureg ureg, GLuint mask ) -{ - dst->File = ureg.file; - dst->Index = ureg.idx; - dst->WriteMask = mask; - dst->CondMask = 0; - dst->CondSwizzle = 0; -} - -static struct fp_instruction * -emit_op(struct texenv_fragment_program *p, - GLuint op, - struct ureg dest, - GLuint mask, - GLuint saturate, - struct ureg src0, - struct ureg src1, - struct ureg src2 ) -{ - GLuint nr = p->program->Base.NumInstructions++; - struct fp_instruction *inst = &p->program->Instructions[nr]; - - memset(inst, 0, sizeof(*inst)); - inst->Opcode = op; - - emit_arg( &inst->SrcReg[0], src0 ); - emit_arg( &inst->SrcReg[1], src1 ); - emit_arg( &inst->SrcReg[2], src2 ); - - inst->Saturate = saturate; - - emit_dst( &inst->DstReg, dest, mask ); - - /* Accounting for indirection tracking: - */ - if (dest.file == PROGRAM_TEMPORARY) - p->temps_output |= 1 << dest.idx; - - return inst; -} - - -static struct ureg emit_arith( struct texenv_fragment_program *p, - GLuint op, - struct ureg dest, - GLuint mask, - GLuint saturate, - struct ureg src0, - struct ureg src1, - struct ureg src2 ) -{ - 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; -} - -static struct ureg emit_texld( struct texenv_fragment_program *p, - GLuint op, - struct ureg dest, - GLuint destmask, - GLuint tex_unit, - GLuint tex_idx, - struct ureg coord ) -{ - struct fp_instruction *inst = emit_op( p, op, - dest, destmask, - 0, /* don't saturate? */ - coord, /* arg 0? */ - undef, - undef); - - inst->TexSrcIdx = tex_idx; - inst->TexSrcUnit = tex_unit; - - p->program->NumTexInstructions++; - - /* 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 = 1<<coord.idx; - p->alu_temps = 0; - assert(0); /* KW: texture env crossbar */ - } - - return dest; -} - - -static struct ureg register_const4f( struct texenv_fragment_program *p, - GLfloat s0, - GLfloat s1, - GLfloat s2, - GLfloat s3) -{ - GLfloat values[4]; - GLuint idx; - values[0] = s0; - values[1] = s1; - values[2] = s2; - values[3] = s3; - idx = _mesa_add_unnamed_constant( p->program->Parameters, values ); - return make_ureg(PROGRAM_STATE_VAR, idx); -} - -#define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0) -#define register_const1f(p, s0) register_const4f(p, s0, 0, 0, 1) -#define register_const2f(p, s0, s1) register_const4f(p, s0, s1, 0, 1) -#define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1) - - - - -static struct ureg get_one( struct texenv_fragment_program *p ) -{ - if (is_undef(p->one)) - p->one = register_scalar_const(p, 1.0); - return p->one; -} - -static struct ureg get_half( struct texenv_fragment_program *p ) -{ - if (is_undef(p->half)) - p->one = register_scalar_const(p, 0.5); - return p->half; -} - -static struct ureg get_zero( struct texenv_fragment_program *p ) -{ - if (is_undef(p->zero)) - p->one = register_scalar_const(p, 0.0); - return p->zero; -} - - - - - -static void program_error( struct texenv_fragment_program *p, const char *msg ) -{ - _mesa_problem(NULL, msg); - p->error = 1; -} - -static struct ureg get_source( struct texenv_fragment_program *p, - GLuint src, GLuint unit ) -{ - switch (src) { - case SRC_TEXTURE: - assert(!is_undef(p->src_texture[unit])); - return p->src_texture[unit]; - - case SRC_TEXTURE0: - case SRC_TEXTURE1: - case SRC_TEXTURE2: - case SRC_TEXTURE3: - case SRC_TEXTURE4: - case SRC_TEXTURE5: - case SRC_TEXTURE6: - case SRC_TEXTURE7: - assert(!is_undef(p->src_texture[src - SRC_TEXTURE0])); - return p->src_texture[src - SRC_TEXTURE0]; - - case SRC_CONSTANT: - return register_param2(p, STATE_TEXENV_COLOR, unit); - - case SRC_PRIMARY_COLOR: - return register_input(p, FRAG_ATTRIB_COL0); - - case SRC_PREVIOUS: - default: - if (is_undef(p->src_previous)) - return register_input(p, FRAG_ATTRIB_COL0); - else - return p->src_previous; - } -} - -static struct ureg emit_combine_source( struct texenv_fragment_program *p, - GLuint mask, - GLuint unit, - GLuint source, - GLuint operand ) -{ - struct ureg arg, src, one; - - src = get_source(p, source, unit); - - switch (operand) { - case OPR_ONE_MINUS_SRC_COLOR: - /* Get unused tmp, - * Emit tmp = 1.0 - arg.xyzw - */ - arg = get_temp( p ); - one = get_one( p ); - return emit_arith( p, FP_OPCODE_SUB, arg, mask, 0, one, src, undef); - - case OPR_SRC_ALPHA: - if (mask == WRITEMASK_W) - return src; - else - return swizzle1( src, W ); - case OPR_ONE_MINUS_SRC_ALPHA: - /* Get unused tmp, - * Emit tmp = 1.0 - arg.wwww - */ - arg = get_temp(p); - one = get_one(p); - return emit_arith(p, FP_OPCODE_SUB, arg, mask, 0, - one, swizzle1(src, W), undef); - case OPR_ZERO: - return get_zero(p); - case OPR_ONE: - return get_one(p); - case OPR_SRC_COLOR: - default: - return src; - } -} - -static GLboolean args_match( struct state_key *key, GLuint unit ) -{ - int i, nr = key->unit[unit].NumArgsRGB; - - for (i = 0 ; i < nr ; i++) { - if (key->unit[unit].OptA[i].Source != key->unit[unit].OptRGB[i].Source) - return GL_FALSE; - - switch(key->unit[unit].OptA[i].Operand) { - case OPR_SRC_ALPHA: - switch(key->unit[unit].OptRGB[i].Operand) { - case OPR_SRC_COLOR: - case OPR_SRC_ALPHA: - break; - default: - return GL_FALSE; - } - break; - case OPR_ONE_MINUS_SRC_ALPHA: - switch(key->unit[unit].OptRGB[i].Operand) { - case OPR_ONE_MINUS_SRC_COLOR: - case OPR_ONE_MINUS_SRC_ALPHA: - break; - default: - return GL_FALSE; - } - break; - default: - return GL_FALSE; /* impossible */ - } - } - - return GL_TRUE; -} - -static struct ureg emit_combine( struct texenv_fragment_program *p, - struct ureg dest, - GLuint mask, - GLuint saturate, - GLuint unit, - GLuint nr, - GLuint mode, - struct mode_opt *opt) -{ - struct ureg src[3]; - struct ureg tmp, half; - int i; - - for (i = 0; i < nr; i++) - src[i] = emit_combine_source( p, mask, unit, opt[i].Source, opt[i].Operand ); - - switch (mode) { - case MODE_REPLACE: - if (mask == WRITEMASK_XYZW && !saturate) - return src[0]; - else - return emit_arith( p, FP_OPCODE_MOV, dest, mask, saturate, src[0], undef, undef ); - case MODE_MODULATE: - return emit_arith( p, FP_OPCODE_MUL, dest, mask, saturate, - src[0], src[1], undef ); - case MODE_ADD: - return emit_arith( p, FP_OPCODE_ADD, dest, mask, saturate, - src[0], src[1], undef ); - case MODE_ADD_SIGNED: - /* tmp = arg0 + arg1 - * result = tmp - .5 - */ - half = get_half(p); - 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 MODE_INTERPOLATE: - /* Arg0 * (Arg2) + Arg1 * (1-Arg2) -- note arguments are reordered: - */ - return emit_arith( p, FP_OPCODE_LRP, dest, mask, saturate, src[2], src[0], src[1] ); - - case MODE_SUBTRACT: - return emit_arith( p, FP_OPCODE_SUB, dest, mask, saturate, src[0], src[1], undef ); - - case MODE_DOT3_RGBA: - case MODE_DOT3_RGBA_EXT: - case MODE_DOT3_RGB_EXT: - case MODE_DOT3_RGB: { - struct ureg tmp0 = get_temp( p ); - struct ureg tmp1 = get_temp( p ); - struct ureg neg1 = register_scalar_const(p, -1); - struct ureg two = register_scalar_const(p, 2); - - /* tmp0 = 2*src0 - 1 - * tmp1 = 2*src1 - 1 - * - * dst = tmp0 dot3 tmp1 - */ - emit_arith( p, FP_OPCODE_MAD, tmp0, WRITEMASK_XYZW, 0, - two, src[0], neg1); - - if (memcmp(&src[0], &src[1], sizeof(struct ureg)) == 0) - tmp1 = tmp0; - else - emit_arith( p, FP_OPCODE_MAD, tmp1, WRITEMASK_XYZW, 0, - two, src[1], neg1); - emit_arith( p, FP_OPCODE_DP3, dest, mask, saturate, tmp0, tmp1, undef); - return dest; - } - case MODE_MODULATE_ADD_ATI: - /* Arg0 * Arg2 + Arg1 */ - return emit_arith( p, FP_OPCODE_MAD, dest, mask, saturate, - src[0], src[2], src[1] ); - case MODE_MODULATE_SIGNED_ADD_ATI: { - /* Arg0 * Arg2 + Arg1 - 0.5 */ - struct ureg tmp0 = get_temp(p); - half = get_half(p); - emit_arith( p, FP_OPCODE_MAD, tmp0, mask, 0, src[0], src[2], src[1] ); - emit_arith( p, FP_OPCODE_SUB, dest, mask, saturate, tmp0, half, undef ); - return dest; - } - case MODE_MODULATE_SUBTRACT_ATI: - /* Arg0 * Arg2 - Arg1 */ - emit_arith( p, FP_OPCODE_MAD, dest, mask, 0, src[0], src[2], negate(src[1]) ); - return dest; - default: - return src[0]; - } -} - - -static struct ureg emit_texenv( struct texenv_fragment_program *p, int unit ) -{ - struct state_key *key = p->state; - GLuint saturate = (unit < p->last_tex_stage); - GLuint rgb_shift, alpha_shift; - struct ureg out, shift; - struct ureg dest; - - if (!key->unit[unit].enabled) { - return get_source(p, SRC_PREVIOUS, 0); - } - - switch (key->unit[unit].ModeRGB) { - case MODE_DOT3_RGB_EXT: - alpha_shift = key->unit[unit].ScaleShiftA; - rgb_shift = 0; - break; - case MODE_DOT3_RGBA_EXT: - alpha_shift = 0; - rgb_shift = 0; - break; - default: - rgb_shift = key->unit[unit].ScaleShiftRGB; - alpha_shift = key->unit[unit].ScaleShiftA; - break; - } - - /* If this is the very last calculation, emit direct to output reg: - */ - if (key->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 - */ - if (key->unit[unit].ModeRGB == key->unit[unit].ModeA && - args_match(key, unit)) { - out = emit_combine( p, dest, WRITEMASK_XYZW, saturate, - unit, - key->unit[unit].NumArgsRGB, - key->unit[unit].ModeRGB, - key->unit[unit].OptRGB); - } - else if (key->unit[unit].ModeRGB == MODE_DOT3_RGBA_EXT || - key->unit[unit].ModeA == MODE_DOT3_RGBA) { - - out = emit_combine( p, dest, WRITEMASK_XYZW, saturate, - unit, - key->unit[unit].NumArgsRGB, - key->unit[unit].ModeRGB, - key->unit[unit].OptRGB); - } - else { - /* Need to do something to stop from re-emitting identical - * argument calculations here: - */ - out = emit_combine( p, dest, WRITEMASK_XYZ, saturate, - unit, - key->unit[unit].NumArgsRGB, - key->unit[unit].ModeRGB, - key->unit[unit].OptRGB); - out = emit_combine( p, dest, WRITEMASK_W, saturate, - unit, - key->unit[unit].NumArgsA, - key->unit[unit].ModeA, - key->unit[unit].OptA); - } - - /* Deal with the final shift: - */ - if (alpha_shift || rgb_shift) { - if (rgb_shift == alpha_shift) { - shift = register_scalar_const(p, 1<<rgb_shift); - } - else { - shift = register_const4f(p, - 1<<rgb_shift, - 1<<rgb_shift, - 1<<rgb_shift, - 1<<alpha_shift); - } - return emit_arith( p, FP_OPCODE_MUL, dest, WRITEMASK_XYZW, - saturate, out, shift, undef ); - } - else - return out; -} - - - -static void load_texture( struct texenv_fragment_program *p, GLuint unit ) -{ - if (is_undef(p->src_texture[unit])) { - GLuint dim = p->state->unit[unit].source_index; - struct ureg texcoord = register_input(p, FRAG_ATTRIB_TEX0+unit); - struct ureg tmp = get_tex_temp( p ); - - if (dim == TEXTURE_UNKNOWN_INDEX) - program_error(p, "TexSrcBit"); - - /* TODO: Use D0_MASK_XY where possible. - */ - p->src_texture[unit] = emit_texld( p, FP_OPCODE_TXP, - tmp, WRITEMASK_XYZW, - unit, dim, texcoord ); - } -} - -static GLboolean load_texenv_source( struct texenv_fragment_program *p, - GLuint src, GLuint unit ) -{ - switch (src) { - case SRC_TEXTURE: - load_texture(p, unit); - break; - - case SRC_TEXTURE0: - case SRC_TEXTURE1: - case SRC_TEXTURE2: - case SRC_TEXTURE3: - case SRC_TEXTURE4: - case SRC_TEXTURE5: - case SRC_TEXTURE6: - case SRC_TEXTURE7: - if (!p->state->unit[src - SRC_TEXTURE0].enabled) - return GL_FALSE; - load_texture(p, src - SRC_TEXTURE0); - break; - - default: - break; - } - - return GL_TRUE; -} - -static GLboolean load_texunit_sources( struct texenv_fragment_program *p, int unit ) -{ - struct state_key *key = p->state; - int i, nr = key->unit[unit].NumArgsRGB; - for (i = 0; i < nr; i++) { - if (!load_texenv_source( p, key->unit[unit].OptRGB[i].Source, unit) || - !load_texenv_source( p, key->unit[unit].OptA[i].Source, unit )) - return GL_FALSE; - } - return GL_TRUE; -} - -static void create_new_program(struct state_key *key, GLcontext *ctx, - struct fragment_program *program) -{ - struct texenv_fragment_program p; - GLuint unit; - struct ureg cf, out; - - _mesa_memset(&p, 0, sizeof(p)); - p.ctx = ctx; - p.state = key; - p.program = program; - - p.program->Instructions = MALLOC(sizeof(struct fp_instruction) * 100); - p.program->Base.NumInstructions = 0; - p.program->Base.Target = GL_FRAGMENT_PROGRAM_ARB; - p.program->NumTexIndirections = 1; /* correct? */ - p.program->NumTexInstructions = 0; - p.program->NumAluInstructions = 0; - p.program->Base.String = 0; - p.program->Base.NumInstructions = - p.program->Base.NumTemporaries = - p.program->Base.NumParameters = - p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0; - p.program->Parameters = _mesa_new_parameter_list(); - - p.program->InputsRead = 0; - p.program->OutputsWritten = 1 << FRAG_OUTPUT_COLR; - - for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) - p.src_texture[unit] = undef; - - p.src_previous = undef; - p.last_tex_stage = 0; - release_temps(&p); - - if (key->enabled_units) { - /* First pass - to support texture_env_crossbar, first identify - * all referenced texture sources and emit texld instructions - * for each: - */ - for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++) - if (key->unit[unit].enabled) { - if (load_texunit_sources( &p, unit )) - p.last_tex_stage = unit; - } - - /* Second pass - emit combine instructions to build final color: - */ - for (unit = 0 ; unit < ctx->Const.MaxTextureUnits; unit++) - if (key->enabled_units & (1<<unit)) { - p.src_previous = emit_texenv( &p, unit ); - release_temps(&p); /* release all temps */ - } - } - - cf = get_source( &p, SRC_PREVIOUS, 0 ); - out = make_ureg( PROGRAM_OUTPUT, FRAG_OUTPUT_COLR ); - - if (key->separate_specular) { - /* Emit specular add. - */ - struct ureg s = register_input(&p, FRAG_ATTRIB_COL1); - emit_arith( &p, FP_OPCODE_ADD, out, WRITEMASK_XYZ, 0, cf, s, undef ); - } - else if (memcmp(&cf, &out, sizeof(cf)) != 0) { - /* Will wind up in here if no texture enabled or a couple of - * other scenarios (GL_REPLACE for instance). - */ - emit_arith( &p, FP_OPCODE_MOV, out, WRITEMASK_XYZW, 0, cf, undef, undef ); - } - - /* Finish up: - */ - emit_arith( &p, FP_OPCODE_END, undef, WRITEMASK_XYZW, 0, undef, undef, undef); - - if (key->fog_enabled) { - /* Pull fog mode from GLcontext, the value in the state key is - * a reduced value and not what is expected in FogOption - */ - p.program->FogOption = ctx->Fog.Mode; - } else - p.program->FogOption = GL_NONE; - - if (p.program->NumTexIndirections > ctx->Const.MaxFragmentProgramTexIndirections) - program_error(&p, "Exceeded max nr indirect texture lookups"); - - if (p.program->NumTexInstructions > ctx->Const.MaxFragmentProgramTexInstructions) - program_error(&p, "Exceeded max TEX instructions"); - - if (p.program->NumAluInstructions > ctx->Const.MaxFragmentProgramAluInstructions) - program_error(&p, "Exceeded max ALU instructions"); - - - /* Notify driver the fragment program has (actually) changed. - */ - if (ctx->Driver.ProgramStringNotify || DISASSEM) { - if (ctx->Driver.ProgramStringNotify) - ctx->Driver.ProgramStringNotify( ctx, GL_FRAGMENT_PROGRAM_ARB, - &p.program->Base ); - - if (DISASSEM) { - _mesa_debug_fp_inst(p.program->NumTexInstructions + p.program->NumAluInstructions, - p.program->Instructions); - _mesa_printf("\n"); - } - - } - -} - -static void *search_cache( struct texenvprog_cache *cache, - GLuint hash, - const void *key, - GLuint keysize) -{ - struct texenvprog_cache *c; - - for (c = cache; c; c = c->next) { - if (c->hash == hash && memcmp(c->key, key, keysize) == 0) - return c->data; - } - - return NULL; -} - -static void cache_item( struct texenvprog_cache **cache, - GLuint hash, - void *key, - void *data ) -{ - struct texenvprog_cache *c = MALLOC(sizeof(*c)); - c->hash = hash; - c->key = key; - c->data = data; - c->next = *cache; - *cache = c; -} - -static GLuint hash_key( struct state_key *key ) -{ - GLuint *ikey = (GLuint *)key; - GLuint hash = 0, i; - - /* I'm sure this can be improved on, but speed is important: - */ - for (i = 0; i < sizeof(*key)/sizeof(GLuint); i++) - hash ^= ikey[i]; - - return hash; -} - -void _mesa_UpdateTexEnvProgram( GLcontext *ctx ) -{ - struct state_key *key; - GLuint hash; - - if (ctx->FragmentProgram._Enabled) - return; - - key = make_state_key(ctx); - hash = hash_key(key); - - ctx->FragmentProgram._Current = ctx->_TexEnvProgram = - (struct fragment_program *) - search_cache(ctx->Texture.env_fp_cache, hash, key, sizeof(*key)); - - if (!ctx->_TexEnvProgram) { - if (0) _mesa_printf("Building new texenv proggy for key %x\n", hash); - - ctx->FragmentProgram._Current = ctx->_TexEnvProgram = - (struct fragment_program *) - ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); - - create_new_program(key, ctx, ctx->_TexEnvProgram); - - cache_item(&ctx->Texture.env_fp_cache, hash, key, ctx->_TexEnvProgram); - } else { - FREE(key); - if (0) _mesa_printf("Found existing texenv program for key %x\n", hash); - } - -} - -void _mesa_TexEnvProgramCacheDestroy( GLcontext *ctx ) -{ - struct texenvprog_cache *a, *tmp; - - for (a = ctx->Texture.env_fp_cache; a; a = tmp) { - tmp = a->next; - FREE(a->key); - FREE(a->data); - FREE(a); - } -} - |