Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentexenvprogram.c
Go to the documentation of this file.
00001 /************************************************************************** 00002 * 00003 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. 00004 * All Rights Reserved. 00005 * 00006 * Permission is hereby granted, free of charge, to any person obtaining a 00007 * copy of this software and associated documentation files (the 00008 * "Software"), to deal in the Software without restriction, including 00009 * without limitation the rights to use, copy, modify, merge, publish, 00010 * distribute, sub license, and/or sell copies of the Software, and to 00011 * permit persons to whom the Software is furnished to do so, subject to 00012 * the following conditions: 00013 * 00014 * The above copyright notice and this permission notice (including the 00015 * next paragraph) shall be included in all copies or substantial portions 00016 * of the Software. 00017 * 00018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00019 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00020 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 00021 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 00022 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 00023 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 00024 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00025 * 00026 **************************************************************************/ 00027 00028 #include "glheader.h" 00029 #include "macros.h" 00030 #include "enums.h" 00031 #include "shader/program.h" 00032 #include "shader/prog_parameter.h" 00033 #include "shader/prog_cache.h" 00034 #include "shader/prog_instruction.h" 00035 #include "shader/prog_print.h" 00036 #include "shader/prog_statevars.h" 00037 #include "shader/programopt.h" 00038 #include "texenvprogram.h" 00039 00040 00041 /* 00042 * Note on texture units: 00043 * 00044 * The number of texture units supported by fixed-function fragment 00045 * processing is MAX_TEXTURE_COORD_UNITS, not MAX_TEXTURE_IMAGE_UNITS. 00046 * That's because there's a one-to-one correspondence between texture 00047 * coordinates and samplers in fixed-function processing. 00048 * 00049 * Since fixed-function vertex processing is limited to MAX_TEXTURE_COORD_UNITS 00050 * sets of texcoords, so is fixed-function fragment processing. 00051 * 00052 * We can safely use ctx->Const.MaxTextureUnits for loop bounds. 00053 */ 00054 00055 00056 struct texenvprog_cache_item 00057 { 00058 GLuint hash; 00059 void *key; 00060 struct gl_fragment_program *data; 00061 struct texenvprog_cache_item *next; 00062 }; 00063 00064 00070 #define MAX_INSTRUCTIONS ((MAX_TEXTURE_COORD_UNITS * 4) + 12) 00071 00072 #define DISASSEM (MESA_VERBOSE & VERBOSE_DISASSEM) 00073 00074 struct mode_opt { 00075 GLuint Source:4; 00076 GLuint Operand:3; 00077 }; 00078 00079 struct state_key { 00080 GLbitfield enabled_units; 00081 GLuint separate_specular:1; 00082 GLuint fog_enabled:1; 00083 GLuint fog_mode:2; 00084 00085 struct { 00086 GLuint enabled:1; 00087 GLuint source_index:3; /* one of TEXTURE_1D/2D/3D/CUBE/RECT_INDEX */ 00088 GLuint shadow:1; 00089 GLuint ScaleShiftRGB:2; 00090 GLuint ScaleShiftA:2; 00091 00092 GLuint NumArgsRGB:2; 00093 GLuint ModeRGB:4; 00094 struct mode_opt OptRGB[3]; 00095 00096 GLuint NumArgsA:2; 00097 GLuint ModeA:4; 00098 struct mode_opt OptA[3]; 00099 } unit[8]; 00100 }; 00101 00102 #define FOG_LINEAR 0 00103 #define FOG_EXP 1 00104 #define FOG_EXP2 2 00105 #define FOG_UNKNOWN 3 00106 00107 static GLuint translate_fog_mode( GLenum mode ) 00108 { 00109 switch (mode) { 00110 case GL_LINEAR: return FOG_LINEAR; 00111 case GL_EXP: return FOG_EXP; 00112 case GL_EXP2: return FOG_EXP2; 00113 default: return FOG_UNKNOWN; 00114 } 00115 } 00116 00117 #define OPR_SRC_COLOR 0 00118 #define OPR_ONE_MINUS_SRC_COLOR 1 00119 #define OPR_SRC_ALPHA 2 00120 #define OPR_ONE_MINUS_SRC_ALPHA 3 00121 #define OPR_ZERO 4 00122 #define OPR_ONE 5 00123 #define OPR_UNKNOWN 7 00124 00125 static GLuint translate_operand( GLenum operand ) 00126 { 00127 switch (operand) { 00128 case GL_SRC_COLOR: return OPR_SRC_COLOR; 00129 case GL_ONE_MINUS_SRC_COLOR: return OPR_ONE_MINUS_SRC_COLOR; 00130 case GL_SRC_ALPHA: return OPR_SRC_ALPHA; 00131 case GL_ONE_MINUS_SRC_ALPHA: return OPR_ONE_MINUS_SRC_ALPHA; 00132 case GL_ZERO: return OPR_ZERO; 00133 case GL_ONE: return OPR_ONE; 00134 default: return OPR_UNKNOWN; 00135 } 00136 } 00137 00138 #define SRC_TEXTURE 0 00139 #define SRC_TEXTURE0 1 00140 #define SRC_TEXTURE1 2 00141 #define SRC_TEXTURE2 3 00142 #define SRC_TEXTURE3 4 00143 #define SRC_TEXTURE4 5 00144 #define SRC_TEXTURE5 6 00145 #define SRC_TEXTURE6 7 00146 #define SRC_TEXTURE7 8 00147 #define SRC_CONSTANT 9 00148 #define SRC_PRIMARY_COLOR 10 00149 #define SRC_PREVIOUS 11 00150 #define SRC_UNKNOWN 15 00151 00152 static GLuint translate_source( GLenum src ) 00153 { 00154 switch (src) { 00155 case GL_TEXTURE: return SRC_TEXTURE; 00156 case GL_TEXTURE0: 00157 case GL_TEXTURE1: 00158 case GL_TEXTURE2: 00159 case GL_TEXTURE3: 00160 case GL_TEXTURE4: 00161 case GL_TEXTURE5: 00162 case GL_TEXTURE6: 00163 case GL_TEXTURE7: return SRC_TEXTURE0 + (src - GL_TEXTURE0); 00164 case GL_CONSTANT: return SRC_CONSTANT; 00165 case GL_PRIMARY_COLOR: return SRC_PRIMARY_COLOR; 00166 case GL_PREVIOUS: return SRC_PREVIOUS; 00167 default: return SRC_UNKNOWN; 00168 } 00169 } 00170 00171 #define MODE_REPLACE 0 00172 #define MODE_MODULATE 1 00173 #define MODE_ADD 2 00174 #define MODE_ADD_SIGNED 3 00175 #define MODE_INTERPOLATE 4 00176 #define MODE_SUBTRACT 5 00177 #define MODE_DOT3_RGB 6 00178 #define MODE_DOT3_RGB_EXT 7 00179 #define MODE_DOT3_RGBA 8 00180 #define MODE_DOT3_RGBA_EXT 9 00181 #define MODE_MODULATE_ADD_ATI 10 00182 #define MODE_MODULATE_SIGNED_ADD_ATI 11 00183 #define MODE_MODULATE_SUBTRACT_ATI 12 00184 #define MODE_UNKNOWN 15 00185 00186 static GLuint translate_mode( GLenum mode ) 00187 { 00188 switch (mode) { 00189 case GL_REPLACE: return MODE_REPLACE; 00190 case GL_MODULATE: return MODE_MODULATE; 00191 case GL_ADD: return MODE_ADD; 00192 case GL_ADD_SIGNED: return MODE_ADD_SIGNED; 00193 case GL_INTERPOLATE: return MODE_INTERPOLATE; 00194 case GL_SUBTRACT: return MODE_SUBTRACT; 00195 case GL_DOT3_RGB: return MODE_DOT3_RGB; 00196 case GL_DOT3_RGB_EXT: return MODE_DOT3_RGB_EXT; 00197 case GL_DOT3_RGBA: return MODE_DOT3_RGBA; 00198 case GL_DOT3_RGBA_EXT: return MODE_DOT3_RGBA_EXT; 00199 case GL_MODULATE_ADD_ATI: return MODE_MODULATE_ADD_ATI; 00200 case GL_MODULATE_SIGNED_ADD_ATI: return MODE_MODULATE_SIGNED_ADD_ATI; 00201 case GL_MODULATE_SUBTRACT_ATI: return MODE_MODULATE_SUBTRACT_ATI; 00202 default: return MODE_UNKNOWN; 00203 } 00204 } 00205 00206 #define TEXTURE_UNKNOWN_INDEX 7 00207 static GLuint translate_tex_src_bit( GLbitfield bit ) 00208 { 00209 switch (bit) { 00210 case TEXTURE_1D_BIT: return TEXTURE_1D_INDEX; 00211 case TEXTURE_2D_BIT: return TEXTURE_2D_INDEX; 00212 case TEXTURE_RECT_BIT: return TEXTURE_RECT_INDEX; 00213 case TEXTURE_3D_BIT: return TEXTURE_3D_INDEX; 00214 case TEXTURE_CUBE_BIT: return TEXTURE_CUBE_INDEX; 00215 default: return TEXTURE_UNKNOWN_INDEX; 00216 } 00217 } 00218 00223 static void make_state_key( GLcontext *ctx, struct state_key *key ) 00224 { 00225 GLuint i, j; 00226 00227 memset(key, 0, sizeof(*key)); 00228 00229 for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { 00230 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; 00231 GLenum format; 00232 00233 if (!texUnit->_ReallyEnabled || !texUnit->Enabled) 00234 continue; 00235 00236 format = texUnit->_Current->Image[0][texUnit->_Current->BaseLevel]->_BaseFormat; 00237 00238 key->unit[i].enabled = 1; 00239 key->enabled_units |= (1<<i); 00240 00241 key->unit[i].source_index = 00242 translate_tex_src_bit(texUnit->_ReallyEnabled); 00243 key->unit[i].shadow = ((texUnit->_Current->CompareMode == GL_COMPARE_R_TO_TEXTURE) && 00244 ((format == GL_DEPTH_COMPONENT) || 00245 (format == GL_DEPTH_STENCIL_EXT))); 00246 00247 key->unit[i].NumArgsRGB = texUnit->_CurrentCombine->_NumArgsRGB; 00248 key->unit[i].NumArgsA = texUnit->_CurrentCombine->_NumArgsA; 00249 00250 key->unit[i].ModeRGB = 00251 translate_mode(texUnit->_CurrentCombine->ModeRGB); 00252 key->unit[i].ModeA = 00253 translate_mode(texUnit->_CurrentCombine->ModeA); 00254 00255 key->unit[i].ScaleShiftRGB = texUnit->_CurrentCombine->ScaleShiftRGB; 00256 key->unit[i].ScaleShiftA = texUnit->_CurrentCombine->ScaleShiftA; 00257 00258 for (j=0;j<3;j++) { 00259 key->unit[i].OptRGB[j].Operand = 00260 translate_operand(texUnit->_CurrentCombine->OperandRGB[j]); 00261 key->unit[i].OptA[j].Operand = 00262 translate_operand(texUnit->_CurrentCombine->OperandA[j]); 00263 key->unit[i].OptRGB[j].Source = 00264 translate_source(texUnit->_CurrentCombine->SourceRGB[j]); 00265 key->unit[i].OptA[j].Source = 00266 translate_source(texUnit->_CurrentCombine->SourceA[j]); 00267 } 00268 } 00269 00270 if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) 00271 key->separate_specular = 1; 00272 00273 if (ctx->Fog.Enabled) { 00274 key->fog_enabled = 1; 00275 key->fog_mode = translate_fog_mode(ctx->Fog.Mode); 00276 } 00277 } 00278 00279 /* Use uregs to represent registers internally, translate to Mesa's 00280 * expected formats on emit. 00281 * 00282 * NOTE: These are passed by value extensively in this file rather 00283 * than as usual by pointer reference. If this disturbs you, try 00284 * remembering they are just 32bits in size. 00285 * 00286 * GCC is smart enough to deal with these dword-sized structures in 00287 * much the same way as if I had defined them as dwords and was using 00288 * macros to access and set the fields. This is much nicer and easier 00289 * to evolve. 00290 */ 00291 struct ureg { 00292 GLuint file:4; 00293 GLuint idx:8; 00294 GLuint negatebase:1; 00295 GLuint abs:1; 00296 GLuint negateabs:1; 00297 GLuint swz:12; 00298 GLuint pad:5; 00299 }; 00300 00301 static const struct ureg undef = { 00302 PROGRAM_UNDEFINED, 00303 ~0, 00304 0, 00305 0, 00306 0, 00307 0, 00308 0 00309 }; 00310 00311 00312 /* State used to build the fragment program: 00313 */ 00314 struct texenv_fragment_program { 00315 struct gl_fragment_program *program; 00316 GLcontext *ctx; 00317 struct state_key *state; 00318 00319 GLbitfield alu_temps; /* Track texture indirections, see spec. */ 00320 GLbitfield temps_output; /* Track texture indirections, see spec. */ 00321 GLbitfield temp_in_use; /* Tracks temporary regs which are in use. */ 00322 GLboolean error; 00323 00324 struct ureg src_texture[MAX_TEXTURE_COORD_UNITS]; 00325 /* Reg containing each texture unit's sampled texture color, 00326 * else undef. 00327 */ 00328 00329 struct ureg src_previous; /* Reg containing color from previous 00330 * stage. May need to be decl'd. 00331 */ 00332 00333 GLuint last_tex_stage; /* Number of last enabled texture unit */ 00334 00335 struct ureg half; 00336 struct ureg one; 00337 struct ureg zero; 00338 }; 00339 00340 00341 00342 static struct ureg make_ureg(GLuint file, GLuint idx) 00343 { 00344 struct ureg reg; 00345 reg.file = file; 00346 reg.idx = idx; 00347 reg.negatebase = 0; 00348 reg.abs = 0; 00349 reg.negateabs = 0; 00350 reg.swz = SWIZZLE_NOOP; 00351 reg.pad = 0; 00352 return reg; 00353 } 00354 00355 static struct ureg swizzle( struct ureg reg, int x, int y, int z, int w ) 00356 { 00357 reg.swz = MAKE_SWIZZLE4(GET_SWZ(reg.swz, x), 00358 GET_SWZ(reg.swz, y), 00359 GET_SWZ(reg.swz, z), 00360 GET_SWZ(reg.swz, w)); 00361 00362 return reg; 00363 } 00364 00365 static struct ureg swizzle1( struct ureg reg, int x ) 00366 { 00367 return swizzle(reg, x, x, x, x); 00368 } 00369 00370 static struct ureg negate( struct ureg reg ) 00371 { 00372 reg.negatebase ^= 1; 00373 return reg; 00374 } 00375 00376 static GLboolean is_undef( struct ureg reg ) 00377 { 00378 return reg.file == PROGRAM_UNDEFINED; 00379 } 00380 00381 00382 static struct ureg get_temp( struct texenv_fragment_program *p ) 00383 { 00384 GLint bit; 00385 00386 /* First try and reuse temps which have been used already: 00387 */ 00388 bit = _mesa_ffs( ~p->temp_in_use & p->alu_temps ); 00389 00390 /* Then any unused temporary: 00391 */ 00392 if (!bit) 00393 bit = _mesa_ffs( ~p->temp_in_use ); 00394 00395 if (!bit) { 00396 _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__); 00397 _mesa_exit(1); 00398 } 00399 00400 if ((GLuint) bit > p->program->Base.NumTemporaries) 00401 p->program->Base.NumTemporaries = bit; 00402 00403 p->temp_in_use |= 1<<(bit-1); 00404 return make_ureg(PROGRAM_TEMPORARY, (bit-1)); 00405 } 00406 00407 static struct ureg get_tex_temp( struct texenv_fragment_program *p ) 00408 { 00409 int bit; 00410 00411 /* First try to find availble temp not previously used (to avoid 00412 * starting a new texture indirection). According to the spec, the 00413 * ~p->temps_output isn't necessary, but will keep it there for 00414 * now: 00415 */ 00416 bit = _mesa_ffs( ~p->temp_in_use & ~p->alu_temps & ~p->temps_output ); 00417 00418 /* Then any unused temporary: 00419 */ 00420 if (!bit) 00421 bit = _mesa_ffs( ~p->temp_in_use ); 00422 00423 if (!bit) { 00424 _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__); 00425 _mesa_exit(1); 00426 } 00427 00428 if ((GLuint) bit > p->program->Base.NumTemporaries) 00429 p->program->Base.NumTemporaries = bit; 00430 00431 p->temp_in_use |= 1<<(bit-1); 00432 return make_ureg(PROGRAM_TEMPORARY, (bit-1)); 00433 } 00434 00435 00436 static void release_temps(GLcontext *ctx, struct texenv_fragment_program *p ) 00437 { 00438 GLuint max_temp = ctx->Const.FragmentProgram.MaxTemps; 00439 00440 /* KW: To support tex_env_crossbar, don't release the registers in 00441 * temps_output. 00442 */ 00443 if (max_temp >= sizeof(int) * 8) 00444 p->temp_in_use = p->temps_output; 00445 else 00446 p->temp_in_use = ~((1<<max_temp)-1) | p->temps_output; 00447 } 00448 00449 00450 static struct ureg register_param5( struct texenv_fragment_program *p, 00451 GLint s0, 00452 GLint s1, 00453 GLint s2, 00454 GLint s3, 00455 GLint s4) 00456 { 00457 gl_state_index tokens[STATE_LENGTH]; 00458 GLuint idx; 00459 tokens[0] = s0; 00460 tokens[1] = s1; 00461 tokens[2] = s2; 00462 tokens[3] = s3; 00463 tokens[4] = s4; 00464 idx = _mesa_add_state_reference( p->program->Base.Parameters, tokens ); 00465 return make_ureg(PROGRAM_STATE_VAR, idx); 00466 } 00467 00468 00469 #define register_param1(p,s0) register_param5(p,s0,0,0,0,0) 00470 #define register_param2(p,s0,s1) register_param5(p,s0,s1,0,0,0) 00471 #define register_param3(p,s0,s1,s2) register_param5(p,s0,s1,s2,0,0) 00472 #define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0) 00473 00474 00475 static struct ureg register_input( struct texenv_fragment_program *p, GLuint input ) 00476 { 00477 p->program->Base.InputsRead |= (1 << input); 00478 return make_ureg(PROGRAM_INPUT, input); 00479 } 00480 00481 00482 static void emit_arg( struct prog_src_register *reg, 00483 struct ureg ureg ) 00484 { 00485 reg->File = ureg.file; 00486 reg->Index = ureg.idx; 00487 reg->Swizzle = ureg.swz; 00488 reg->NegateBase = ureg.negatebase ? 0xf : 0x0; 00489 reg->Abs = ureg.abs; 00490 reg->NegateAbs = ureg.negateabs; 00491 } 00492 00493 static void emit_dst( struct prog_dst_register *dst, 00494 struct ureg ureg, GLuint mask ) 00495 { 00496 dst->File = ureg.file; 00497 dst->Index = ureg.idx; 00498 dst->WriteMask = mask; 00499 dst->CondMask = COND_TR; /* always pass cond test */ 00500 dst->CondSwizzle = SWIZZLE_NOOP; 00501 } 00502 00503 static struct prog_instruction * 00504 emit_op(struct texenv_fragment_program *p, 00505 enum prog_opcode op, 00506 struct ureg dest, 00507 GLuint mask, 00508 GLboolean saturate, 00509 struct ureg src0, 00510 struct ureg src1, 00511 struct ureg src2 ) 00512 { 00513 GLuint nr = p->program->Base.NumInstructions++; 00514 struct prog_instruction *inst = &p->program->Base.Instructions[nr]; 00515 00516 assert(nr < MAX_INSTRUCTIONS); 00517 00518 _mesa_init_instructions(inst, 1); 00519 inst->Opcode = op; 00520 00521 emit_arg( &inst->SrcReg[0], src0 ); 00522 emit_arg( &inst->SrcReg[1], src1 ); 00523 emit_arg( &inst->SrcReg[2], src2 ); 00524 00525 inst->SaturateMode = saturate ? SATURATE_ZERO_ONE : SATURATE_OFF; 00526 00527 emit_dst( &inst->DstReg, dest, mask ); 00528 00529 /* Accounting for indirection tracking: 00530 */ 00531 if (dest.file == PROGRAM_TEMPORARY) 00532 p->temps_output |= 1 << dest.idx; 00533 00534 return inst; 00535 } 00536 00537 00538 static struct ureg emit_arith( struct texenv_fragment_program *p, 00539 enum prog_opcode op, 00540 struct ureg dest, 00541 GLuint mask, 00542 GLboolean saturate, 00543 struct ureg src0, 00544 struct ureg src1, 00545 struct ureg src2 ) 00546 { 00547 emit_op(p, op, dest, mask, saturate, src0, src1, src2); 00548 00549 /* Accounting for indirection tracking: 00550 */ 00551 if (src0.file == PROGRAM_TEMPORARY) 00552 p->alu_temps |= 1 << src0.idx; 00553 00554 if (!is_undef(src1) && src1.file == PROGRAM_TEMPORARY) 00555 p->alu_temps |= 1 << src1.idx; 00556 00557 if (!is_undef(src2) && src2.file == PROGRAM_TEMPORARY) 00558 p->alu_temps |= 1 << src2.idx; 00559 00560 if (dest.file == PROGRAM_TEMPORARY) 00561 p->alu_temps |= 1 << dest.idx; 00562 00563 p->program->Base.NumAluInstructions++; 00564 return dest; 00565 } 00566 00567 static struct ureg emit_texld( struct texenv_fragment_program *p, 00568 enum prog_opcode op, 00569 struct ureg dest, 00570 GLuint destmask, 00571 GLuint tex_unit, 00572 GLuint tex_idx, 00573 struct ureg coord ) 00574 { 00575 struct prog_instruction *inst = emit_op( p, op, 00576 dest, destmask, 00577 GL_FALSE, /* don't saturate? */ 00578 coord, /* arg 0? */ 00579 undef, 00580 undef); 00581 00582 inst->TexSrcTarget = tex_idx; 00583 inst->TexSrcUnit = tex_unit; 00584 00585 p->program->Base.NumTexInstructions++; 00586 00587 /* Is this a texture indirection? 00588 */ 00589 if ((coord.file == PROGRAM_TEMPORARY && 00590 (p->temps_output & (1<<coord.idx))) || 00591 (dest.file == PROGRAM_TEMPORARY && 00592 (p->alu_temps & (1<<dest.idx)))) { 00593 p->program->Base.NumTexIndirections++; 00594 p->temps_output = 1<<coord.idx; 00595 p->alu_temps = 0; 00596 assert(0); /* KW: texture env crossbar */ 00597 } 00598 00599 return dest; 00600 } 00601 00602 00603 static struct ureg register_const4f( struct texenv_fragment_program *p, 00604 GLfloat s0, 00605 GLfloat s1, 00606 GLfloat s2, 00607 GLfloat s3) 00608 { 00609 GLfloat values[4]; 00610 GLuint idx, swizzle; 00611 values[0] = s0; 00612 values[1] = s1; 00613 values[2] = s2; 00614 values[3] = s3; 00615 idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4, 00616 &swizzle ); 00617 ASSERT(swizzle == SWIZZLE_NOOP); 00618 return make_ureg(PROGRAM_CONSTANT, idx); 00619 } 00620 00621 #define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0) 00622 #define register_const1f(p, s0) register_const4f(p, s0, 0, 0, 1) 00623 #define register_const2f(p, s0, s1) register_const4f(p, s0, s1, 0, 1) 00624 #define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1) 00625 00626 00627 static struct ureg get_one( struct texenv_fragment_program *p ) 00628 { 00629 if (is_undef(p->one)) 00630 p->one = register_scalar_const(p, 1.0); 00631 return p->one; 00632 } 00633 00634 static struct ureg get_half( struct texenv_fragment_program *p ) 00635 { 00636 if (is_undef(p->half)) 00637 p->half = register_scalar_const(p, 0.5); 00638 return p->half; 00639 } 00640 00641 static struct ureg get_zero( struct texenv_fragment_program *p ) 00642 { 00643 if (is_undef(p->zero)) 00644 p->zero = register_scalar_const(p, 0.0); 00645 return p->zero; 00646 } 00647 00648 00649 static void program_error( struct texenv_fragment_program *p, const char *msg ) 00650 { 00651 _mesa_problem(NULL, msg); 00652 p->error = 1; 00653 } 00654 00655 static struct ureg get_source( struct texenv_fragment_program *p, 00656 GLuint src, GLuint unit ) 00657 { 00658 switch (src) { 00659 case SRC_TEXTURE: 00660 assert(!is_undef(p->src_texture[unit])); 00661 return p->src_texture[unit]; 00662 00663 case SRC_TEXTURE0: 00664 case SRC_TEXTURE1: 00665 case SRC_TEXTURE2: 00666 case SRC_TEXTURE3: 00667 case SRC_TEXTURE4: 00668 case SRC_TEXTURE5: 00669 case SRC_TEXTURE6: 00670 case SRC_TEXTURE7: 00671 assert(!is_undef(p->src_texture[src - SRC_TEXTURE0])); 00672 return p->src_texture[src - SRC_TEXTURE0]; 00673 00674 case SRC_CONSTANT: 00675 return register_param2(p, STATE_TEXENV_COLOR, unit); 00676 00677 case SRC_PRIMARY_COLOR: 00678 return register_input(p, FRAG_ATTRIB_COL0); 00679 00680 case SRC_PREVIOUS: 00681 default: 00682 if (is_undef(p->src_previous)) 00683 return register_input(p, FRAG_ATTRIB_COL0); 00684 else 00685 return p->src_previous; 00686 } 00687 } 00688 00689 static struct ureg emit_combine_source( struct texenv_fragment_program *p, 00690 GLuint mask, 00691 GLuint unit, 00692 GLuint source, 00693 GLuint operand ) 00694 { 00695 struct ureg arg, src, one; 00696 00697 src = get_source(p, source, unit); 00698 00699 switch (operand) { 00700 case OPR_ONE_MINUS_SRC_COLOR: 00701 /* Get unused tmp, 00702 * Emit tmp = 1.0 - arg.xyzw 00703 */ 00704 arg = get_temp( p ); 00705 one = get_one( p ); 00706 return emit_arith( p, OPCODE_SUB, arg, mask, 0, one, src, undef); 00707 00708 case OPR_SRC_ALPHA: 00709 if (mask == WRITEMASK_W) 00710 return src; 00711 else 00712 return swizzle1( src, SWIZZLE_W ); 00713 case OPR_ONE_MINUS_SRC_ALPHA: 00714 /* Get unused tmp, 00715 * Emit tmp = 1.0 - arg.wwww 00716 */ 00717 arg = get_temp(p); 00718 one = get_one(p); 00719 return emit_arith(p, OPCODE_SUB, arg, mask, 0, 00720 one, swizzle1(src, SWIZZLE_W), undef); 00721 case OPR_ZERO: 00722 return get_zero(p); 00723 case OPR_ONE: 00724 return get_one(p); 00725 case OPR_SRC_COLOR: 00726 default: 00727 return src; 00728 } 00729 } 00730 00731 static GLboolean args_match( struct state_key *key, GLuint unit ) 00732 { 00733 GLuint i, nr = key->unit[unit].NumArgsRGB; 00734 00735 for (i = 0 ; i < nr ; i++) { 00736 if (key->unit[unit].OptA[i].Source != key->unit[unit].OptRGB[i].Source) 00737 return GL_FALSE; 00738 00739 switch(key->unit[unit].OptA[i].Operand) { 00740 case OPR_SRC_ALPHA: 00741 switch(key->unit[unit].OptRGB[i].Operand) { 00742 case OPR_SRC_COLOR: 00743 case OPR_SRC_ALPHA: 00744 break; 00745 default: 00746 return GL_FALSE; 00747 } 00748 break; 00749 case OPR_ONE_MINUS_SRC_ALPHA: 00750 switch(key->unit[unit].OptRGB[i].Operand) { 00751 case OPR_ONE_MINUS_SRC_COLOR: 00752 case OPR_ONE_MINUS_SRC_ALPHA: 00753 break; 00754 default: 00755 return GL_FALSE; 00756 } 00757 break; 00758 default: 00759 return GL_FALSE; /* impossible */ 00760 } 00761 } 00762 00763 return GL_TRUE; 00764 } 00765 00766 static struct ureg emit_combine( struct texenv_fragment_program *p, 00767 struct ureg dest, 00768 GLuint mask, 00769 GLboolean saturate, 00770 GLuint unit, 00771 GLuint nr, 00772 GLuint mode, 00773 const struct mode_opt *opt) 00774 { 00775 struct ureg src[3]; 00776 struct ureg tmp, half; 00777 GLuint i; 00778 00779 tmp = undef; /* silence warning (bug 5318) */ 00780 00781 for (i = 0; i < nr; i++) 00782 src[i] = emit_combine_source( p, mask, unit, opt[i].Source, opt[i].Operand ); 00783 00784 switch (mode) { 00785 case MODE_REPLACE: 00786 if (mask == WRITEMASK_XYZW && !saturate) 00787 return src[0]; 00788 else 00789 return emit_arith( p, OPCODE_MOV, dest, mask, saturate, src[0], undef, undef ); 00790 case MODE_MODULATE: 00791 return emit_arith( p, OPCODE_MUL, dest, mask, saturate, 00792 src[0], src[1], undef ); 00793 case MODE_ADD: 00794 return emit_arith( p, OPCODE_ADD, dest, mask, saturate, 00795 src[0], src[1], undef ); 00796 case MODE_ADD_SIGNED: 00797 /* tmp = arg0 + arg1 00798 * result = tmp - .5 00799 */ 00800 half = get_half(p); 00801 tmp = get_temp( p ); 00802 emit_arith( p, OPCODE_ADD, tmp, mask, 0, src[0], src[1], undef ); 00803 emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp, half, undef ); 00804 return dest; 00805 case MODE_INTERPOLATE: 00806 /* Arg0 * (Arg2) + Arg1 * (1-Arg2) -- note arguments are reordered: 00807 */ 00808 return emit_arith( p, OPCODE_LRP, dest, mask, saturate, src[2], src[0], src[1] ); 00809 00810 case MODE_SUBTRACT: 00811 return emit_arith( p, OPCODE_SUB, dest, mask, saturate, src[0], src[1], undef ); 00812 00813 case MODE_DOT3_RGBA: 00814 case MODE_DOT3_RGBA_EXT: 00815 case MODE_DOT3_RGB_EXT: 00816 case MODE_DOT3_RGB: { 00817 struct ureg tmp0 = get_temp( p ); 00818 struct ureg tmp1 = get_temp( p ); 00819 struct ureg neg1 = register_scalar_const(p, -1); 00820 struct ureg two = register_scalar_const(p, 2); 00821 00822 /* tmp0 = 2*src0 - 1 00823 * tmp1 = 2*src1 - 1 00824 * 00825 * dst = tmp0 dot3 tmp1 00826 */ 00827 emit_arith( p, OPCODE_MAD, tmp0, WRITEMASK_XYZW, 0, 00828 two, src[0], neg1); 00829 00830 if (_mesa_memcmp(&src[0], &src[1], sizeof(struct ureg)) == 0) 00831 tmp1 = tmp0; 00832 else 00833 emit_arith( p, OPCODE_MAD, tmp1, WRITEMASK_XYZW, 0, 00834 two, src[1], neg1); 00835 emit_arith( p, OPCODE_DP3, dest, mask, saturate, tmp0, tmp1, undef); 00836 return dest; 00837 } 00838 case MODE_MODULATE_ADD_ATI: 00839 /* Arg0 * Arg2 + Arg1 */ 00840 return emit_arith( p, OPCODE_MAD, dest, mask, saturate, 00841 src[0], src[2], src[1] ); 00842 case MODE_MODULATE_SIGNED_ADD_ATI: { 00843 /* Arg0 * Arg2 + Arg1 - 0.5 */ 00844 struct ureg tmp0 = get_temp(p); 00845 half = get_half(p); 00846 emit_arith( p, OPCODE_MAD, tmp0, mask, 0, src[0], src[2], src[1] ); 00847 emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp0, half, undef ); 00848 return dest; 00849 } 00850 case MODE_MODULATE_SUBTRACT_ATI: 00851 /* Arg0 * Arg2 - Arg1 */ 00852 emit_arith( p, OPCODE_MAD, dest, mask, 0, src[0], src[2], negate(src[1]) ); 00853 return dest; 00854 default: 00855 return src[0]; 00856 } 00857 } 00858 00859 00863 static struct ureg 00864 emit_texenv(struct texenv_fragment_program *p, GLuint unit) 00865 { 00866 struct state_key *key = p->state; 00867 GLboolean saturate = (unit < p->last_tex_stage); 00868 GLuint rgb_shift, alpha_shift; 00869 struct ureg out, shift; 00870 struct ureg dest; 00871 00872 if (!key->unit[unit].enabled) { 00873 return get_source(p, SRC_PREVIOUS, 0); 00874 } 00875 00876 switch (key->unit[unit].ModeRGB) { 00877 case MODE_DOT3_RGB_EXT: 00878 alpha_shift = key->unit[unit].ScaleShiftA; 00879 rgb_shift = 0; 00880 break; 00881 case MODE_DOT3_RGBA_EXT: 00882 alpha_shift = 0; 00883 rgb_shift = 0; 00884 break; 00885 default: 00886 rgb_shift = key->unit[unit].ScaleShiftRGB; 00887 alpha_shift = key->unit[unit].ScaleShiftA; 00888 break; 00889 } 00890 00891 /* If this is the very last calculation, emit direct to output reg: 00892 */ 00893 if (key->separate_specular || 00894 unit != p->last_tex_stage || 00895 alpha_shift || 00896 rgb_shift) 00897 dest = get_temp( p ); 00898 else 00899 dest = make_ureg(PROGRAM_OUTPUT, FRAG_RESULT_COLR); 00900 00901 /* Emit the RGB and A combine ops 00902 */ 00903 if (key->unit[unit].ModeRGB == key->unit[unit].ModeA && 00904 args_match(key, unit)) { 00905 out = emit_combine( p, dest, WRITEMASK_XYZW, saturate, 00906 unit, 00907 key->unit[unit].NumArgsRGB, 00908 key->unit[unit].ModeRGB, 00909 key->unit[unit].OptRGB); 00910 } 00911 else if (key->unit[unit].ModeRGB == MODE_DOT3_RGBA_EXT || 00912 key->unit[unit].ModeRGB == MODE_DOT3_RGBA) { 00913 00914 out = emit_combine( p, dest, WRITEMASK_XYZW, saturate, 00915 unit, 00916 key->unit[unit].NumArgsRGB, 00917 key->unit[unit].ModeRGB, 00918 key->unit[unit].OptRGB); 00919 } 00920 else { 00921 /* Need to do something to stop from re-emitting identical 00922 * argument calculations here: 00923 */ 00924 out = emit_combine( p, dest, WRITEMASK_XYZ, saturate, 00925 unit, 00926 key->unit[unit].NumArgsRGB, 00927 key->unit[unit].ModeRGB, 00928 key->unit[unit].OptRGB); 00929 out = emit_combine( p, dest, WRITEMASK_W, saturate, 00930 unit, 00931 key->unit[unit].NumArgsA, 00932 key->unit[unit].ModeA, 00933 key->unit[unit].OptA); 00934 } 00935 00936 /* Deal with the final shift: 00937 */ 00938 if (alpha_shift || rgb_shift) { 00939 if (rgb_shift == alpha_shift) { 00940 shift = register_scalar_const(p, (GLfloat)(1<<rgb_shift)); 00941 } 00942 else { 00943 shift = register_const4f(p, 00944 (GLfloat)(1<<rgb_shift), 00945 (GLfloat)(1<<rgb_shift), 00946 (GLfloat)(1<<rgb_shift), 00947 (GLfloat)(1<<alpha_shift)); 00948 } 00949 return emit_arith( p, OPCODE_MUL, dest, WRITEMASK_XYZW, 00950 saturate, out, shift, undef ); 00951 } 00952 else 00953 return out; 00954 } 00955 00956 00960 static void load_texture( struct texenv_fragment_program *p, GLuint unit ) 00961 { 00962 if (is_undef(p->src_texture[unit])) { 00963 GLuint dim = p->state->unit[unit].source_index; 00964 struct ureg texcoord = register_input(p, FRAG_ATTRIB_TEX0+unit); 00965 struct ureg tmp = get_tex_temp( p ); 00966 00967 if (dim == TEXTURE_UNKNOWN_INDEX) 00968 program_error(p, "TexSrcBit"); 00969 00970 /* TODO: Use D0_MASK_XY where possible. 00971 */ 00972 if (p->state->unit[unit].enabled) { 00973 p->src_texture[unit] = emit_texld( p, OPCODE_TXP, 00974 tmp, WRITEMASK_XYZW, 00975 unit, dim, texcoord ); 00976 if (p->state->unit[unit].shadow) 00977 p->program->Base.ShadowSamplers |= 1 << unit; 00978 00979 p->program->Base.SamplersUsed |= (1 << unit); 00980 /* This identity mapping should already be in place 00981 * (see _mesa_init_program_struct()) but let's be safe. 00982 */ 00983 p->program->Base.SamplerUnits[unit] = unit; 00984 } 00985 else 00986 p->src_texture[unit] = get_zero(p); 00987 } 00988 } 00989 00990 static GLboolean load_texenv_source( struct texenv_fragment_program *p, 00991 GLuint src, GLuint unit ) 00992 { 00993 switch (src) { 00994 case SRC_TEXTURE: 00995 load_texture(p, unit); 00996 break; 00997 00998 case SRC_TEXTURE0: 00999 case SRC_TEXTURE1: 01000 case SRC_TEXTURE2: 01001 case SRC_TEXTURE3: 01002 case SRC_TEXTURE4: 01003 case SRC_TEXTURE5: 01004 case SRC_TEXTURE6: 01005 case SRC_TEXTURE7: 01006 load_texture(p, src - SRC_TEXTURE0); 01007 break; 01008 01009 default: 01010 break; 01011 } 01012 01013 return GL_TRUE; 01014 } 01015 01016 01020 static GLboolean 01021 load_texunit_sources( struct texenv_fragment_program *p, int unit ) 01022 { 01023 struct state_key *key = p->state; 01024 GLuint i; 01025 01026 for (i = 0; i < key->unit[unit].NumArgsRGB; i++) { 01027 load_texenv_source( p, key->unit[unit].OptRGB[i].Source, unit); 01028 } 01029 01030 for (i = 0; i < key->unit[unit].NumArgsA; i++) { 01031 load_texenv_source( p, key->unit[unit].OptA[i].Source, unit ); 01032 } 01033 01034 return GL_TRUE; 01035 } 01036 01037 01042 static void 01043 create_new_program(GLcontext *ctx, struct state_key *key, 01044 struct gl_fragment_program *program) 01045 { 01046 struct prog_instruction instBuffer[MAX_INSTRUCTIONS]; 01047 struct texenv_fragment_program p; 01048 GLuint unit; 01049 struct ureg cf, out; 01050 01051 _mesa_memset(&p, 0, sizeof(p)); 01052 p.ctx = ctx; 01053 p.state = key; 01054 p.program = program; 01055 01056 /* During code generation, use locally-allocated instruction buffer, 01057 * then alloc dynamic storage below. 01058 */ 01059 p.program->Base.Instructions = instBuffer; 01060 p.program->Base.Target = GL_FRAGMENT_PROGRAM_ARB; 01061 p.program->Base.NumTexIndirections = 1; /* correct? */ 01062 p.program->Base.NumTexInstructions = 0; 01063 p.program->Base.NumAluInstructions = 0; 01064 p.program->Base.String = NULL; 01065 p.program->Base.NumInstructions = 01066 p.program->Base.NumTemporaries = 01067 p.program->Base.NumParameters = 01068 p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0; 01069 p.program->Base.Parameters = _mesa_new_parameter_list(); 01070 01071 p.program->Base.InputsRead = 0; 01072 p.program->Base.OutputsWritten = 1 << FRAG_RESULT_COLR; 01073 01074 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) 01075 p.src_texture[unit] = undef; 01076 01077 p.src_previous = undef; 01078 p.half = undef; 01079 p.zero = undef; 01080 p.one = undef; 01081 01082 p.last_tex_stage = 0; 01083 release_temps(ctx, &p); 01084 01085 if (key->enabled_units) { 01086 /* First pass - to support texture_env_crossbar, first identify 01087 * all referenced texture sources and emit texld instructions 01088 * for each: 01089 */ 01090 for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++) 01091 if (key->unit[unit].enabled) { 01092 load_texunit_sources( &p, unit ); 01093 p.last_tex_stage = unit; 01094 } 01095 01096 /* Second pass - emit combine instructions to build final color: 01097 */ 01098 for (unit = 0 ; unit < ctx->Const.MaxTextureUnits; unit++) 01099 if (key->enabled_units & (1<<unit)) { 01100 p.src_previous = emit_texenv( &p, unit ); 01101 release_temps(ctx, &p); /* release all temps */ 01102 } 01103 } 01104 01105 cf = get_source( &p, SRC_PREVIOUS, 0 ); 01106 out = make_ureg( PROGRAM_OUTPUT, FRAG_RESULT_COLR ); 01107 01108 if (key->separate_specular) { 01109 /* Emit specular add. 01110 */ 01111 struct ureg s = register_input(&p, FRAG_ATTRIB_COL1); 01112 emit_arith( &p, OPCODE_ADD, out, WRITEMASK_XYZ, 0, cf, s, undef ); 01113 emit_arith( &p, OPCODE_MOV, out, WRITEMASK_W, 0, cf, undef, undef ); 01114 } 01115 else if (_mesa_memcmp(&cf, &out, sizeof(cf)) != 0) { 01116 /* Will wind up in here if no texture enabled or a couple of 01117 * other scenarios (GL_REPLACE for instance). 01118 */ 01119 emit_arith( &p, OPCODE_MOV, out, WRITEMASK_XYZW, 0, cf, undef, undef ); 01120 } 01121 01122 /* Finish up: 01123 */ 01124 emit_arith( &p, OPCODE_END, undef, WRITEMASK_XYZW, 0, undef, undef, undef); 01125 01126 if (key->fog_enabled) { 01127 /* Pull fog mode from GLcontext, the value in the state key is 01128 * a reduced value and not what is expected in FogOption 01129 */ 01130 p.program->FogOption = ctx->Fog.Mode; 01131 p.program->Base.InputsRead |= FRAG_BIT_FOGC; /* XXX new */ 01132 } else 01133 p.program->FogOption = GL_NONE; 01134 01135 if (p.program->Base.NumTexIndirections > ctx->Const.FragmentProgram.MaxTexIndirections) 01136 program_error(&p, "Exceeded max nr indirect texture lookups"); 01137 01138 if (p.program->Base.NumTexInstructions > ctx->Const.FragmentProgram.MaxTexInstructions) 01139 program_error(&p, "Exceeded max TEX instructions"); 01140 01141 if (p.program->Base.NumAluInstructions > ctx->Const.FragmentProgram.MaxAluInstructions) 01142 program_error(&p, "Exceeded max ALU instructions"); 01143 01144 ASSERT(p.program->Base.NumInstructions <= MAX_INSTRUCTIONS); 01145 01146 /* Allocate final instruction array */ 01147 p.program->Base.Instructions 01148 = _mesa_alloc_instructions(p.program->Base.NumInstructions); 01149 if (!p.program->Base.Instructions) { 01150 _mesa_error(ctx, GL_OUT_OF_MEMORY, 01151 "generating tex env program"); 01152 return; 01153 } 01154 _mesa_copy_instructions(p.program->Base.Instructions, instBuffer, 01155 p.program->Base.NumInstructions); 01156 01157 if (p.program->FogOption) { 01158 _mesa_append_fog_code(ctx, p.program); 01159 p.program->FogOption = GL_NONE; 01160 } 01161 01162 01163 /* Notify driver the fragment program has (actually) changed. 01164 */ 01165 if (ctx->Driver.ProgramStringNotify) { 01166 ctx->Driver.ProgramStringNotify( ctx, GL_FRAGMENT_PROGRAM_ARB, 01167 &p.program->Base ); 01168 } 01169 01170 if (DISASSEM) { 01171 _mesa_print_program(&p.program->Base); 01172 _mesa_printf("\n"); 01173 } 01174 } 01175 01176 01181 struct gl_fragment_program * 01182 _mesa_get_fixed_func_fragment_program(GLcontext *ctx) 01183 { 01184 struct gl_fragment_program *prog; 01185 struct state_key key; 01186 01187 make_state_key(ctx, &key); 01188 01189 prog = (struct gl_fragment_program *) 01190 _mesa_search_program_cache(ctx->FragmentProgram.Cache, 01191 &key, sizeof(key)); 01192 01193 if (!prog) { 01194 prog = (struct gl_fragment_program *) 01195 ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); 01196 01197 create_new_program(ctx, &key, prog); 01198 01199 _mesa_program_cache_insert(ctx, ctx->FragmentProgram.Cache, 01200 &key, sizeof(key), &prog->Base); 01201 } 01202 01203 return prog; 01204 } 01205 01206 01207 01213 void 01214 _mesa_UpdateTexEnvProgram( GLcontext *ctx ) 01215 { 01216 const struct gl_fragment_program *prev = ctx->FragmentProgram._Current; 01217 01218 ASSERT(ctx->FragmentProgram._MaintainTexEnvProgram); 01219 01220 /* If a conventional fragment program/shader isn't in effect... */ 01221 if (!ctx->FragmentProgram._Enabled && 01222 (!ctx->Shader.CurrentProgram || 01223 !ctx->Shader.CurrentProgram->FragmentProgram) ) 01224 { 01225 struct gl_fragment_program *newProg; 01226 01227 newProg = _mesa_get_fixed_func_fragment_program(ctx); 01228 01229 _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, newProg); 01230 _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram, newProg); 01231 } 01232 01233 /* Tell the driver about the change. Could define a new target for 01234 * this? 01235 */ 01236 if (ctx->FragmentProgram._Current != prev && ctx->Driver.BindProgram) { 01237 ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 01238 (struct gl_program *) ctx->FragmentProgram._Current); 01239 } 01240 } Generated on Fri May 25 2012 04:18:37 for ReactOS by
1.7.6.1
|