Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenffvertex_prog.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 00036 #include "main/glheader.h" 00037 #include "main/mtypes.h" 00038 #include "main/macros.h" 00039 #include "main/enums.h" 00040 #include "main/ffvertex_prog.h" 00041 #include "shader/program.h" 00042 #include "shader/prog_cache.h" 00043 #include "shader/prog_instruction.h" 00044 #include "shader/prog_parameter.h" 00045 #include "shader/prog_print.h" 00046 #include "shader/prog_statevars.h" 00047 00048 00049 struct state_key { 00050 unsigned light_global_enabled:1; 00051 unsigned light_local_viewer:1; 00052 unsigned light_twoside:1; 00053 unsigned light_color_material:1; 00054 unsigned light_color_material_mask:12; 00055 unsigned light_material_mask:12; 00056 unsigned material_shininess_is_zero:1; 00057 00058 unsigned need_eye_coords:1; 00059 unsigned normalize:1; 00060 unsigned rescale_normals:1; 00061 unsigned fog_source_is_depth:1; 00062 unsigned tnl_do_vertex_fog:1; 00063 unsigned separate_specular:1; 00064 unsigned fog_mode:2; 00065 unsigned point_attenuated:1; 00066 unsigned point_array:1; 00067 unsigned texture_enabled_global:1; 00068 unsigned fragprog_inputs_read:12; 00069 00070 struct { 00071 unsigned light_enabled:1; 00072 unsigned light_eyepos3_is_zero:1; 00073 unsigned light_spotcutoff_is_180:1; 00074 unsigned light_attenuated:1; 00075 unsigned texunit_really_enabled:1; 00076 unsigned texmat_enabled:1; 00077 unsigned texgen_enabled:4; 00078 unsigned texgen_mode0:4; 00079 unsigned texgen_mode1:4; 00080 unsigned texgen_mode2:4; 00081 unsigned texgen_mode3:4; 00082 } unit[8]; 00083 }; 00084 00085 00086 00087 #define FOG_NONE 0 00088 #define FOG_LINEAR 1 00089 #define FOG_EXP 2 00090 #define FOG_EXP2 3 00091 00092 static GLuint translate_fog_mode( GLenum mode ) 00093 { 00094 switch (mode) { 00095 case GL_LINEAR: return FOG_LINEAR; 00096 case GL_EXP: return FOG_EXP; 00097 case GL_EXP2: return FOG_EXP2; 00098 default: return FOG_NONE; 00099 } 00100 } 00101 00102 00103 #define TXG_NONE 0 00104 #define TXG_OBJ_LINEAR 1 00105 #define TXG_EYE_LINEAR 2 00106 #define TXG_SPHERE_MAP 3 00107 #define TXG_REFLECTION_MAP 4 00108 #define TXG_NORMAL_MAP 5 00109 00110 static GLuint translate_texgen( GLboolean enabled, GLenum mode ) 00111 { 00112 if (!enabled) 00113 return TXG_NONE; 00114 00115 switch (mode) { 00116 case GL_OBJECT_LINEAR: return TXG_OBJ_LINEAR; 00117 case GL_EYE_LINEAR: return TXG_EYE_LINEAR; 00118 case GL_SPHERE_MAP: return TXG_SPHERE_MAP; 00119 case GL_REFLECTION_MAP_NV: return TXG_REFLECTION_MAP; 00120 case GL_NORMAL_MAP_NV: return TXG_NORMAL_MAP; 00121 default: return TXG_NONE; 00122 } 00123 } 00124 00125 00131 static GLbitfield 00132 tnl_get_per_vertex_materials(GLcontext *ctx) 00133 { 00134 GLbitfield mask = 0x0; 00135 #if 0 00136 TNLcontext *tnl = TNL_CONTEXT(ctx); 00137 struct vertex_buffer *VB = &tnl->vb; 00138 GLuint i; 00139 00140 for (i = _TNL_FIRST_MAT; i <= _TNL_LAST_MAT; i++) 00141 if (VB->AttribPtr[i] && VB->AttribPtr[i]->stride) 00142 mask |= 1 << (i - _TNL_FIRST_MAT); 00143 #endif 00144 return mask; 00145 } 00146 00147 00151 static GLboolean 00152 tnl_get_per_vertex_fog(GLcontext *ctx) 00153 { 00154 #if 0 00155 TNLcontext *tnl = TNL_CONTEXT(ctx); 00156 return tnl->_DoVertexFog; 00157 #else 00158 return GL_FALSE; 00159 #endif 00160 } 00161 00162 00163 static GLboolean check_active_shininess( GLcontext *ctx, 00164 const struct state_key *key, 00165 GLuint side ) 00166 { 00167 GLuint bit = 1 << (MAT_ATTRIB_FRONT_SHININESS + side); 00168 00169 if (key->light_color_material_mask & bit) 00170 return GL_TRUE; 00171 00172 if (key->light_material_mask & bit) 00173 return GL_TRUE; 00174 00175 if (ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS + side][0] != 0.0F) 00176 return GL_TRUE; 00177 00178 return GL_FALSE; 00179 } 00180 00181 00182 static void make_state_key( GLcontext *ctx, struct state_key *key ) 00183 { 00184 const struct gl_fragment_program *fp; 00185 GLuint i; 00186 00187 memset(key, 0, sizeof(struct state_key)); 00188 fp = ctx->FragmentProgram._Current; 00189 00190 /* This now relies on texenvprogram.c being active: 00191 */ 00192 assert(fp); 00193 00194 key->need_eye_coords = ctx->_NeedEyeCoords; 00195 00196 key->fragprog_inputs_read = fp->Base.InputsRead; 00197 00198 if (ctx->RenderMode == GL_FEEDBACK) { 00199 /* make sure the vertprog emits color and tex0 */ 00200 key->fragprog_inputs_read |= (FRAG_BIT_COL0 | FRAG_BIT_TEX0); 00201 } 00202 00203 key->separate_specular = (ctx->Light.Model.ColorControl == 00204 GL_SEPARATE_SPECULAR_COLOR); 00205 00206 if (ctx->Light.Enabled) { 00207 key->light_global_enabled = 1; 00208 00209 if (ctx->Light.Model.LocalViewer) 00210 key->light_local_viewer = 1; 00211 00212 if (ctx->Light.Model.TwoSide) 00213 key->light_twoside = 1; 00214 00215 if (ctx->Light.ColorMaterialEnabled) { 00216 key->light_color_material = 1; 00217 key->light_color_material_mask = ctx->Light.ColorMaterialBitmask; 00218 } 00219 00220 key->light_material_mask = tnl_get_per_vertex_materials(ctx); 00221 00222 for (i = 0; i < MAX_LIGHTS; i++) { 00223 struct gl_light *light = &ctx->Light.Light[i]; 00224 00225 if (light->Enabled) { 00226 key->unit[i].light_enabled = 1; 00227 00228 if (light->EyePosition[3] == 0.0) 00229 key->unit[i].light_eyepos3_is_zero = 1; 00230 00231 if (light->SpotCutoff == 180.0) 00232 key->unit[i].light_spotcutoff_is_180 = 1; 00233 00234 if (light->ConstantAttenuation != 1.0 || 00235 light->LinearAttenuation != 0.0 || 00236 light->QuadraticAttenuation != 0.0) 00237 key->unit[i].light_attenuated = 1; 00238 } 00239 } 00240 00241 if (check_active_shininess(ctx, key, 0)) { 00242 key->material_shininess_is_zero = 0; 00243 } 00244 else if (key->light_twoside && 00245 check_active_shininess(ctx, key, 1)) { 00246 key->material_shininess_is_zero = 0; 00247 } 00248 else { 00249 key->material_shininess_is_zero = 1; 00250 } 00251 } 00252 00253 if (ctx->Transform.Normalize) 00254 key->normalize = 1; 00255 00256 if (ctx->Transform.RescaleNormals) 00257 key->rescale_normals = 1; 00258 00259 key->fog_mode = translate_fog_mode(fp->FogOption); 00260 00261 if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) 00262 key->fog_source_is_depth = 1; 00263 00264 key->tnl_do_vertex_fog = tnl_get_per_vertex_fog(ctx); 00265 00266 if (ctx->Point._Attenuated) 00267 key->point_attenuated = 1; 00268 00269 #if FEATURE_point_size_array 00270 if (ctx->Array.ArrayObj->PointSize.Enabled) 00271 key->point_array = 1; 00272 #endif 00273 00274 if (ctx->Texture._TexGenEnabled || 00275 ctx->Texture._TexMatEnabled || 00276 ctx->Texture._EnabledUnits) 00277 key->texture_enabled_global = 1; 00278 00279 for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { 00280 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; 00281 00282 if (texUnit->_ReallyEnabled) 00283 key->unit[i].texunit_really_enabled = 1; 00284 00285 if (ctx->Texture._TexMatEnabled & ENABLE_TEXMAT(i)) 00286 key->unit[i].texmat_enabled = 1; 00287 00288 if (texUnit->TexGenEnabled) { 00289 key->unit[i].texgen_enabled = 1; 00290 00291 key->unit[i].texgen_mode0 = 00292 translate_texgen( texUnit->TexGenEnabled & (1<<0), 00293 texUnit->GenModeS ); 00294 key->unit[i].texgen_mode1 = 00295 translate_texgen( texUnit->TexGenEnabled & (1<<1), 00296 texUnit->GenModeT ); 00297 key->unit[i].texgen_mode2 = 00298 translate_texgen( texUnit->TexGenEnabled & (1<<2), 00299 texUnit->GenModeR ); 00300 key->unit[i].texgen_mode3 = 00301 translate_texgen( texUnit->TexGenEnabled & (1<<3), 00302 texUnit->GenModeQ ); 00303 } 00304 } 00305 } 00306 00307 00308 00309 /* Very useful debugging tool - produces annotated listing of 00310 * generated program with line/function references for each 00311 * instruction back into this file: 00312 */ 00313 #define DISASSEM 0 00314 00315 /* Should be tunable by the driver - do we want to do matrix 00316 * multiplications with DP4's or with MUL/MAD's? SSE works better 00317 * with the latter, drivers may differ. 00318 */ 00319 #define PREFER_DP4 0 00320 00321 00322 /* Use uregs to represent registers internally, translate to Mesa's 00323 * expected formats on emit. 00324 * 00325 * NOTE: These are passed by value extensively in this file rather 00326 * than as usual by pointer reference. If this disturbs you, try 00327 * remembering they are just 32bits in size. 00328 * 00329 * GCC is smart enough to deal with these dword-sized structures in 00330 * much the same way as if I had defined them as dwords and was using 00331 * macros to access and set the fields. This is much nicer and easier 00332 * to evolve. 00333 */ 00334 struct ureg { 00335 GLuint file:4; 00336 GLint idx:9; /* relative addressing may be negative */ 00337 /* sizeof(idx) should == sizeof(prog_src_reg::Index) */ 00338 GLuint negate:1; 00339 GLuint swz:12; 00340 GLuint pad:6; 00341 }; 00342 00343 00344 struct tnl_program { 00345 const struct state_key *state; 00346 struct gl_vertex_program *program; 00347 GLint max_inst; 00349 GLuint temp_in_use; 00350 GLuint temp_reserved; 00351 00352 struct ureg eye_position; 00353 struct ureg eye_position_z; 00354 struct ureg eye_position_normalized; 00355 struct ureg transformed_normal; 00356 struct ureg identity; 00357 00358 GLuint materials; 00359 GLuint color_materials; 00360 }; 00361 00362 00363 static const struct ureg undef = { 00364 PROGRAM_UNDEFINED, 00365 0, 00366 0, 00367 0, 00368 0 00369 }; 00370 00371 /* Local shorthand: 00372 */ 00373 #define X SWIZZLE_X 00374 #define Y SWIZZLE_Y 00375 #define Z SWIZZLE_Z 00376 #define W SWIZZLE_W 00377 00378 00379 /* Construct a ureg: 00380 */ 00381 static struct ureg make_ureg(GLuint file, GLint idx) 00382 { 00383 struct ureg reg; 00384 reg.file = file; 00385 reg.idx = idx; 00386 reg.negate = 0; 00387 reg.swz = SWIZZLE_NOOP; 00388 reg.pad = 0; 00389 return reg; 00390 } 00391 00392 00393 00394 static struct ureg negate( struct ureg reg ) 00395 { 00396 reg.negate ^= 1; 00397 return reg; 00398 } 00399 00400 00401 static struct ureg swizzle( struct ureg reg, int x, int y, int z, int w ) 00402 { 00403 reg.swz = MAKE_SWIZZLE4(GET_SWZ(reg.swz, x), 00404 GET_SWZ(reg.swz, y), 00405 GET_SWZ(reg.swz, z), 00406 GET_SWZ(reg.swz, w)); 00407 00408 return reg; 00409 } 00410 00411 00412 static struct ureg swizzle1( struct ureg reg, int x ) 00413 { 00414 return swizzle(reg, x, x, x, x); 00415 } 00416 00417 00418 static struct ureg get_temp( struct tnl_program *p ) 00419 { 00420 int bit = _mesa_ffs( ~p->temp_in_use ); 00421 if (!bit) { 00422 _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__); 00423 _mesa_exit(1); 00424 } 00425 00426 if ((GLuint) bit > p->program->Base.NumTemporaries) 00427 p->program->Base.NumTemporaries = bit; 00428 00429 p->temp_in_use |= 1<<(bit-1); 00430 return make_ureg(PROGRAM_TEMPORARY, bit-1); 00431 } 00432 00433 00434 static struct ureg reserve_temp( struct tnl_program *p ) 00435 { 00436 struct ureg temp = get_temp( p ); 00437 p->temp_reserved |= 1<<temp.idx; 00438 return temp; 00439 } 00440 00441 00442 static void release_temp( struct tnl_program *p, struct ureg reg ) 00443 { 00444 if (reg.file == PROGRAM_TEMPORARY) { 00445 p->temp_in_use &= ~(1<<reg.idx); 00446 p->temp_in_use |= p->temp_reserved; /* can't release reserved temps */ 00447 } 00448 } 00449 00450 00451 static void release_temps( struct tnl_program *p ) 00452 { 00453 p->temp_in_use = p->temp_reserved; 00454 } 00455 00456 00460 static struct ureg register_input( struct tnl_program *p, GLuint input ) 00461 { 00462 p->program->Base.InputsRead |= (1<<input); 00463 return make_ureg(PROGRAM_INPUT, input); 00464 } 00465 00466 00470 static struct ureg register_output( struct tnl_program *p, GLuint output ) 00471 { 00472 p->program->Base.OutputsWritten |= (1<<output); 00473 return make_ureg(PROGRAM_OUTPUT, output); 00474 } 00475 00476 00477 static struct ureg register_const4f( struct tnl_program *p, 00478 GLfloat s0, 00479 GLfloat s1, 00480 GLfloat s2, 00481 GLfloat s3) 00482 { 00483 GLfloat values[4]; 00484 GLint idx; 00485 GLuint swizzle; 00486 values[0] = s0; 00487 values[1] = s1; 00488 values[2] = s2; 00489 values[3] = s3; 00490 idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4, 00491 &swizzle ); 00492 ASSERT(swizzle == SWIZZLE_NOOP); 00493 return make_ureg(PROGRAM_CONSTANT, idx); 00494 } 00495 00496 00497 #define register_const1f(p, s0) register_const4f(p, s0, 0, 0, 1) 00498 #define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0) 00499 #define register_const2f(p, s0, s1) register_const4f(p, s0, s1, 0, 1) 00500 #define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1) 00501 00502 static GLboolean is_undef( struct ureg reg ) 00503 { 00504 return reg.file == PROGRAM_UNDEFINED; 00505 } 00506 00507 00508 static struct ureg get_identity_param( struct tnl_program *p ) 00509 { 00510 if (is_undef(p->identity)) 00511 p->identity = register_const4f(p, 0,0,0,1); 00512 00513 return p->identity; 00514 } 00515 00516 00517 static struct ureg register_param5(struct tnl_program *p, 00518 GLint s0, 00519 GLint s1, 00520 GLint s2, 00521 GLint s3, 00522 GLint s4) 00523 { 00524 gl_state_index tokens[STATE_LENGTH]; 00525 GLint idx; 00526 tokens[0] = s0; 00527 tokens[1] = s1; 00528 tokens[2] = s2; 00529 tokens[3] = s3; 00530 tokens[4] = s4; 00531 idx = _mesa_add_state_reference( p->program->Base.Parameters, tokens ); 00532 return make_ureg(PROGRAM_STATE_VAR, idx); 00533 } 00534 00535 00536 #define register_param1(p,s0) register_param5(p,s0,0,0,0,0) 00537 #define register_param2(p,s0,s1) register_param5(p,s0,s1,0,0,0) 00538 #define register_param3(p,s0,s1,s2) register_param5(p,s0,s1,s2,0,0) 00539 #define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0) 00540 00541 00542 static void register_matrix_param5( struct tnl_program *p, 00543 GLint s0, /* modelview, projection, etc */ 00544 GLint s1, /* texture matrix number */ 00545 GLint s2, /* first row */ 00546 GLint s3, /* last row */ 00547 GLint s4, /* inverse, transpose, etc */ 00548 struct ureg *matrix ) 00549 { 00550 GLint i; 00551 00552 /* This is a bit sad as the support is there to pull the whole 00553 * matrix out in one go: 00554 */ 00555 for (i = 0; i <= s3 - s2; i++) 00556 matrix[i] = register_param5( p, s0, s1, i, i, s4 ); 00557 } 00558 00559 00560 static void emit_arg( struct prog_src_register *src, 00561 struct ureg reg ) 00562 { 00563 src->File = reg.file; 00564 src->Index = reg.idx; 00565 src->Swizzle = reg.swz; 00566 src->NegateBase = reg.negate ? NEGATE_XYZW : 0; 00567 src->Abs = 0; 00568 src->NegateAbs = 0; 00569 src->RelAddr = 0; 00570 /* Check that bitfield sizes aren't exceeded */ 00571 ASSERT(src->Index == reg.idx); 00572 } 00573 00574 00575 static void emit_dst( struct prog_dst_register *dst, 00576 struct ureg reg, GLuint mask ) 00577 { 00578 dst->File = reg.file; 00579 dst->Index = reg.idx; 00580 /* allow zero as a shorthand for xyzw */ 00581 dst->WriteMask = mask ? mask : WRITEMASK_XYZW; 00582 dst->CondMask = COND_TR; /* always pass cond test */ 00583 dst->CondSwizzle = SWIZZLE_NOOP; 00584 dst->CondSrc = 0; 00585 dst->pad = 0; 00586 /* Check that bitfield sizes aren't exceeded */ 00587 ASSERT(dst->Index == reg.idx); 00588 } 00589 00590 00591 static void debug_insn( struct prog_instruction *inst, const char *fn, 00592 GLuint line ) 00593 { 00594 if (DISASSEM) { 00595 static const char *last_fn; 00596 00597 if (fn != last_fn) { 00598 last_fn = fn; 00599 _mesa_printf("%s:\n", fn); 00600 } 00601 00602 _mesa_printf("%d:\t", line); 00603 _mesa_print_instruction(inst); 00604 } 00605 } 00606 00607 00608 static void emit_op3fn(struct tnl_program *p, 00609 enum prog_opcode op, 00610 struct ureg dest, 00611 GLuint mask, 00612 struct ureg src0, 00613 struct ureg src1, 00614 struct ureg src2, 00615 const char *fn, 00616 GLuint line) 00617 { 00618 GLuint nr; 00619 struct prog_instruction *inst; 00620 00621 assert((GLint) p->program->Base.NumInstructions <= p->max_inst); 00622 00623 if (p->program->Base.NumInstructions == p->max_inst) { 00624 /* need to extend the program's instruction array */ 00625 struct prog_instruction *newInst; 00626 00627 /* double the size */ 00628 p->max_inst *= 2; 00629 00630 newInst = _mesa_alloc_instructions(p->max_inst); 00631 if (!newInst) { 00632 _mesa_error(NULL, GL_OUT_OF_MEMORY, "vertex program build"); 00633 return; 00634 } 00635 00636 _mesa_copy_instructions(newInst, 00637 p->program->Base.Instructions, 00638 p->program->Base.NumInstructions); 00639 00640 _mesa_free_instructions(p->program->Base.Instructions, 00641 p->program->Base.NumInstructions); 00642 00643 p->program->Base.Instructions = newInst; 00644 } 00645 00646 nr = p->program->Base.NumInstructions++; 00647 00648 inst = &p->program->Base.Instructions[nr]; 00649 inst->Opcode = (enum prog_opcode) op; 00650 inst->StringPos = 0; 00651 inst->Data = 0; 00652 00653 emit_arg( &inst->SrcReg[0], src0 ); 00654 emit_arg( &inst->SrcReg[1], src1 ); 00655 emit_arg( &inst->SrcReg[2], src2 ); 00656 00657 emit_dst( &inst->DstReg, dest, mask ); 00658 00659 debug_insn(inst, fn, line); 00660 } 00661 00662 00663 #define emit_op3(p, op, dst, mask, src0, src1, src2) \ 00664 emit_op3fn(p, op, dst, mask, src0, src1, src2, __FUNCTION__, __LINE__) 00665 00666 #define emit_op2(p, op, dst, mask, src0, src1) \ 00667 emit_op3fn(p, op, dst, mask, src0, src1, undef, __FUNCTION__, __LINE__) 00668 00669 #define emit_op1(p, op, dst, mask, src0) \ 00670 emit_op3fn(p, op, dst, mask, src0, undef, undef, __FUNCTION__, __LINE__) 00671 00672 00673 static struct ureg make_temp( struct tnl_program *p, struct ureg reg ) 00674 { 00675 if (reg.file == PROGRAM_TEMPORARY && 00676 !(p->temp_reserved & (1<<reg.idx))) 00677 return reg; 00678 else { 00679 struct ureg temp = get_temp(p); 00680 emit_op1(p, OPCODE_MOV, temp, 0, reg); 00681 return temp; 00682 } 00683 } 00684 00685 00686 /* Currently no tracking performed of input/output/register size or 00687 * active elements. Could be used to reduce these operations, as 00688 * could the matrix type. 00689 */ 00690 static void emit_matrix_transform_vec4( struct tnl_program *p, 00691 struct ureg dest, 00692 const struct ureg *mat, 00693 struct ureg src) 00694 { 00695 emit_op2(p, OPCODE_DP4, dest, WRITEMASK_X, src, mat[0]); 00696 emit_op2(p, OPCODE_DP4, dest, WRITEMASK_Y, src, mat[1]); 00697 emit_op2(p, OPCODE_DP4, dest, WRITEMASK_Z, src, mat[2]); 00698 emit_op2(p, OPCODE_DP4, dest, WRITEMASK_W, src, mat[3]); 00699 } 00700 00701 00702 /* This version is much easier to implement if writemasks are not 00703 * supported natively on the target or (like SSE), the target doesn't 00704 * have a clean/obvious dotproduct implementation. 00705 */ 00706 static void emit_transpose_matrix_transform_vec4( struct tnl_program *p, 00707 struct ureg dest, 00708 const struct ureg *mat, 00709 struct ureg src) 00710 { 00711 struct ureg tmp; 00712 00713 if (dest.file != PROGRAM_TEMPORARY) 00714 tmp = get_temp(p); 00715 else 00716 tmp = dest; 00717 00718 emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]); 00719 emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp); 00720 emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp); 00721 emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp); 00722 00723 if (dest.file != PROGRAM_TEMPORARY) 00724 release_temp(p, tmp); 00725 } 00726 00727 00728 static void emit_matrix_transform_vec3( struct tnl_program *p, 00729 struct ureg dest, 00730 const struct ureg *mat, 00731 struct ureg src) 00732 { 00733 emit_op2(p, OPCODE_DP3, dest, WRITEMASK_X, src, mat[0]); 00734 emit_op2(p, OPCODE_DP3, dest, WRITEMASK_Y, src, mat[1]); 00735 emit_op2(p, OPCODE_DP3, dest, WRITEMASK_Z, src, mat[2]); 00736 } 00737 00738 00739 static void emit_normalize_vec3( struct tnl_program *p, 00740 struct ureg dest, 00741 struct ureg src ) 00742 { 00743 #if 0 00744 /* XXX use this when drivers are ready for NRM3 */ 00745 emit_op1(p, OPCODE_NRM3, dest, WRITEMASK_XYZ, src); 00746 #else 00747 struct ureg tmp = get_temp(p); 00748 emit_op2(p, OPCODE_DP3, tmp, WRITEMASK_X, src, src); 00749 emit_op1(p, OPCODE_RSQ, tmp, WRITEMASK_X, tmp); 00750 emit_op2(p, OPCODE_MUL, dest, 0, src, swizzle1(tmp, X)); 00751 release_temp(p, tmp); 00752 #endif 00753 } 00754 00755 00756 static void emit_passthrough( struct tnl_program *p, 00757 GLuint input, 00758 GLuint output ) 00759 { 00760 struct ureg out = register_output(p, output); 00761 emit_op1(p, OPCODE_MOV, out, 0, register_input(p, input)); 00762 } 00763 00764 00765 static struct ureg get_eye_position( struct tnl_program *p ) 00766 { 00767 if (is_undef(p->eye_position)) { 00768 struct ureg pos = register_input( p, VERT_ATTRIB_POS ); 00769 struct ureg modelview[4]; 00770 00771 p->eye_position = reserve_temp(p); 00772 00773 if (PREFER_DP4) { 00774 register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3, 00775 0, modelview ); 00776 00777 emit_matrix_transform_vec4(p, p->eye_position, modelview, pos); 00778 } 00779 else { 00780 register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3, 00781 STATE_MATRIX_TRANSPOSE, modelview ); 00782 00783 emit_transpose_matrix_transform_vec4(p, p->eye_position, modelview, pos); 00784 } 00785 } 00786 00787 return p->eye_position; 00788 } 00789 00790 00791 static struct ureg get_eye_position_z( struct tnl_program *p ) 00792 { 00793 if (!is_undef(p->eye_position)) 00794 return swizzle1(p->eye_position, Z); 00795 00796 if (is_undef(p->eye_position_z)) { 00797 struct ureg pos = register_input( p, VERT_ATTRIB_POS ); 00798 struct ureg modelview[4]; 00799 00800 p->eye_position_z = reserve_temp(p); 00801 00802 register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3, 00803 0, modelview ); 00804 00805 emit_op2(p, OPCODE_DP4, p->eye_position_z, 0, pos, modelview[2]); 00806 } 00807 00808 return p->eye_position_z; 00809 } 00810 00811 00812 static struct ureg get_eye_position_normalized( struct tnl_program *p ) 00813 { 00814 if (is_undef(p->eye_position_normalized)) { 00815 struct ureg eye = get_eye_position(p); 00816 p->eye_position_normalized = reserve_temp(p); 00817 emit_normalize_vec3(p, p->eye_position_normalized, eye); 00818 } 00819 00820 return p->eye_position_normalized; 00821 } 00822 00823 00824 static struct ureg get_transformed_normal( struct tnl_program *p ) 00825 { 00826 if (is_undef(p->transformed_normal) && 00827 !p->state->need_eye_coords && 00828 !p->state->normalize && 00829 !(p->state->need_eye_coords == p->state->rescale_normals)) 00830 { 00831 p->transformed_normal = register_input(p, VERT_ATTRIB_NORMAL ); 00832 } 00833 else if (is_undef(p->transformed_normal)) 00834 { 00835 struct ureg normal = register_input(p, VERT_ATTRIB_NORMAL ); 00836 struct ureg mvinv[3]; 00837 struct ureg transformed_normal = reserve_temp(p); 00838 00839 if (p->state->need_eye_coords) { 00840 register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 2, 00841 STATE_MATRIX_INVTRANS, mvinv ); 00842 00843 /* Transform to eye space: 00844 */ 00845 emit_matrix_transform_vec3( p, transformed_normal, mvinv, normal ); 00846 normal = transformed_normal; 00847 } 00848 00849 /* Normalize/Rescale: 00850 */ 00851 if (p->state->normalize) { 00852 emit_normalize_vec3( p, transformed_normal, normal ); 00853 normal = transformed_normal; 00854 } 00855 else if (p->state->need_eye_coords == p->state->rescale_normals) { 00856 /* This is already adjusted for eye/non-eye rendering: 00857 */ 00858 struct ureg rescale = register_param2(p, STATE_INTERNAL, 00859 STATE_NORMAL_SCALE); 00860 00861 emit_op2( p, OPCODE_MUL, transformed_normal, 0, normal, rescale ); 00862 normal = transformed_normal; 00863 } 00864 00865 assert(normal.file == PROGRAM_TEMPORARY); 00866 p->transformed_normal = normal; 00867 } 00868 00869 return p->transformed_normal; 00870 } 00871 00872 00873 static void build_hpos( struct tnl_program *p ) 00874 { 00875 struct ureg pos = register_input( p, VERT_ATTRIB_POS ); 00876 struct ureg hpos = register_output( p, VERT_RESULT_HPOS ); 00877 struct ureg mvp[4]; 00878 00879 if (PREFER_DP4) { 00880 register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3, 00881 0, mvp ); 00882 emit_matrix_transform_vec4( p, hpos, mvp, pos ); 00883 } 00884 else { 00885 register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3, 00886 STATE_MATRIX_TRANSPOSE, mvp ); 00887 emit_transpose_matrix_transform_vec4( p, hpos, mvp, pos ); 00888 } 00889 } 00890 00891 00892 static GLuint material_attrib( GLuint side, GLuint property ) 00893 { 00894 return ((property - STATE_AMBIENT) * 2 + 00895 side); 00896 } 00897 00898 00902 static void set_material_flags( struct tnl_program *p ) 00903 { 00904 p->color_materials = 0; 00905 p->materials = 0; 00906 00907 if (p->state->light_color_material) { 00908 p->materials = 00909 p->color_materials = p->state->light_color_material_mask; 00910 } 00911 00912 p->materials |= p->state->light_material_mask; 00913 } 00914 00915 00916 /* XXX temporary!!! */ 00917 #define _TNL_ATTRIB_MAT_FRONT_AMBIENT 32 00918 00919 static struct ureg get_material( struct tnl_program *p, GLuint side, 00920 GLuint property ) 00921 { 00922 GLuint attrib = material_attrib(side, property); 00923 00924 if (p->color_materials & (1<<attrib)) 00925 return register_input(p, VERT_ATTRIB_COLOR0); 00926 else if (p->materials & (1<<attrib)) 00927 return register_input( p, attrib + _TNL_ATTRIB_MAT_FRONT_AMBIENT ); 00928 else 00929 return register_param3( p, STATE_MATERIAL, side, property ); 00930 } 00931 00932 #define SCENE_COLOR_BITS(side) (( MAT_BIT_FRONT_EMISSION | \ 00933 MAT_BIT_FRONT_AMBIENT | \ 00934 MAT_BIT_FRONT_DIFFUSE) << (side)) 00935 00936 00948 static struct ureg get_scenecolor( struct tnl_program *p, GLuint side ) 00949 { 00950 if (p->materials & SCENE_COLOR_BITS(side)) { 00951 struct ureg lm_ambient = register_param1(p, STATE_LIGHTMODEL_AMBIENT); 00952 struct ureg material_emission = get_material(p, side, STATE_EMISSION); 00953 struct ureg material_ambient = get_material(p, side, STATE_AMBIENT); 00954 struct ureg material_diffuse = get_material(p, side, STATE_DIFFUSE); 00955 struct ureg tmp = make_temp(p, material_diffuse); 00956 emit_op3(p, OPCODE_MAD, tmp, WRITEMASK_XYZ, lm_ambient, 00957 material_ambient, material_emission); 00958 return tmp; 00959 } 00960 else 00961 return register_param2( p, STATE_LIGHTMODEL_SCENECOLOR, side ); 00962 } 00963 00964 00965 static struct ureg get_lightprod( struct tnl_program *p, GLuint light, 00966 GLuint side, GLuint property ) 00967 { 00968 GLuint attrib = material_attrib(side, property); 00969 if (p->materials & (1<<attrib)) { 00970 struct ureg light_value = 00971 register_param3(p, STATE_LIGHT, light, property); 00972 struct ureg material_value = get_material(p, side, property); 00973 struct ureg tmp = get_temp(p); 00974 emit_op2(p, OPCODE_MUL, tmp, 0, light_value, material_value); 00975 return tmp; 00976 } 00977 else 00978 return register_param4(p, STATE_LIGHTPROD, light, side, property); 00979 } 00980 00981 00982 static struct ureg calculate_light_attenuation( struct tnl_program *p, 00983 GLuint i, 00984 struct ureg VPpli, 00985 struct ureg dist ) 00986 { 00987 struct ureg attenuation = register_param3(p, STATE_LIGHT, i, 00988 STATE_ATTENUATION); 00989 struct ureg att = get_temp(p); 00990 00991 /* Calculate spot attenuation: 00992 */ 00993 if (!p->state->unit[i].light_spotcutoff_is_180) { 00994 struct ureg spot_dir_norm = register_param3(p, STATE_INTERNAL, 00995 STATE_LIGHT_SPOT_DIR_NORMALIZED, i); 00996 struct ureg spot = get_temp(p); 00997 struct ureg slt = get_temp(p); 00998 00999 emit_op2(p, OPCODE_DP3, spot, 0, negate(VPpli), spot_dir_norm); 01000 emit_op2(p, OPCODE_SLT, slt, 0, swizzle1(spot_dir_norm,W), spot); 01001 emit_op2(p, OPCODE_POW, spot, 0, spot, swizzle1(attenuation, W)); 01002 emit_op2(p, OPCODE_MUL, att, 0, slt, spot); 01003 01004 release_temp(p, spot); 01005 release_temp(p, slt); 01006 } 01007 01008 /* Calculate distance attenuation: 01009 */ 01010 if (p->state->unit[i].light_attenuated) { 01011 01012 /* 1/d,d,d,1/d */ 01013 emit_op1(p, OPCODE_RCP, dist, WRITEMASK_YZ, dist); 01014 /* 1,d,d*d,1/d */ 01015 emit_op2(p, OPCODE_MUL, dist, WRITEMASK_XZ, dist, swizzle1(dist,Y)); 01016 /* 1/dist-atten */ 01017 emit_op2(p, OPCODE_DP3, dist, 0, attenuation, dist); 01018 01019 if (!p->state->unit[i].light_spotcutoff_is_180) { 01020 /* dist-atten */ 01021 emit_op1(p, OPCODE_RCP, dist, 0, dist); 01022 /* spot-atten * dist-atten */ 01023 emit_op2(p, OPCODE_MUL, att, 0, dist, att); 01024 } else { 01025 /* dist-atten */ 01026 emit_op1(p, OPCODE_RCP, att, 0, dist); 01027 } 01028 } 01029 01030 return att; 01031 } 01032 01033 01039 static void emit_degenerate_lit( struct tnl_program *p, 01040 struct ureg lit, 01041 struct ureg dots ) 01042 { 01043 struct ureg id = get_identity_param(p); /* id = {0,0,0,1} */ 01044 01045 /* Note that lit.x & lit.w will not be examined. Note also that 01046 * dots.xyzw == dots.xxxx. 01047 */ 01048 01049 /* MAX lit, id, dots; 01050 */ 01051 emit_op2(p, OPCODE_MAX, lit, WRITEMASK_XYZW, id, dots); 01052 01053 /* result[2] = (in > 0 ? 1 : 0) 01054 * SLT lit.z, id.z, dots; # lit.z = (0 < dots.z) ? 1 : 0 01055 */ 01056 emit_op2(p, OPCODE_SLT, lit, WRITEMASK_Z, swizzle1(id,Z), dots); 01057 } 01058 01059 01060 /* Need to add some addtional parameters to allow lighting in object 01061 * space - STATE_SPOT_DIRECTION and STATE_HALF_VECTOR implicitly assume eye 01062 * space lighting. 01063 */ 01064 static void build_lighting( struct tnl_program *p ) 01065 { 01066 const GLboolean twoside = p->state->light_twoside; 01067 const GLboolean separate = p->state->separate_specular; 01068 GLuint nr_lights = 0, count = 0; 01069 struct ureg normal = get_transformed_normal(p); 01070 struct ureg lit = get_temp(p); 01071 struct ureg dots = get_temp(p); 01072 struct ureg _col0 = undef, _col1 = undef; 01073 struct ureg _bfc0 = undef, _bfc1 = undef; 01074 GLuint i; 01075 01076 /* 01077 * NOTE: 01078 * dot.x = dot(normal, VPpli) 01079 * dot.y = dot(normal, halfAngle) 01080 * dot.z = back.shininess 01081 * dot.w = front.shininess 01082 */ 01083 01084 for (i = 0; i < MAX_LIGHTS; i++) 01085 if (p->state->unit[i].light_enabled) 01086 nr_lights++; 01087 01088 set_material_flags(p); 01089 01090 { 01091 if (!p->state->material_shininess_is_zero) { 01092 struct ureg shininess = get_material(p, 0, STATE_SHININESS); 01093 emit_op1(p, OPCODE_MOV, dots, WRITEMASK_W, swizzle1(shininess,X)); 01094 release_temp(p, shininess); 01095 } 01096 01097 _col0 = make_temp(p, get_scenecolor(p, 0)); 01098 if (separate) 01099 _col1 = make_temp(p, get_identity_param(p)); 01100 else 01101 _col1 = _col0; 01102 01103 } 01104 01105 if (twoside) { 01106 if (!p->state->material_shininess_is_zero) { 01107 struct ureg shininess = get_material(p, 1, STATE_SHININESS); 01108 emit_op1(p, OPCODE_MOV, dots, WRITEMASK_Z, 01109 negate(swizzle1(shininess,X))); 01110 release_temp(p, shininess); 01111 } 01112 01113 _bfc0 = make_temp(p, get_scenecolor(p, 1)); 01114 if (separate) 01115 _bfc1 = make_temp(p, get_identity_param(p)); 01116 else 01117 _bfc1 = _bfc0; 01118 } 01119 01120 /* If no lights, still need to emit the scenecolor. 01121 */ 01122 { 01123 struct ureg res0 = register_output( p, VERT_RESULT_COL0 ); 01124 emit_op1(p, OPCODE_MOV, res0, 0, _col0); 01125 } 01126 01127 if (separate) { 01128 struct ureg res1 = register_output( p, VERT_RESULT_COL1 ); 01129 emit_op1(p, OPCODE_MOV, res1, 0, _col1); 01130 } 01131 01132 if (twoside) { 01133 struct ureg res0 = register_output( p, VERT_RESULT_BFC0 ); 01134 emit_op1(p, OPCODE_MOV, res0, 0, _bfc0); 01135 } 01136 01137 if (twoside && separate) { 01138 struct ureg res1 = register_output( p, VERT_RESULT_BFC1 ); 01139 emit_op1(p, OPCODE_MOV, res1, 0, _bfc1); 01140 } 01141 01142 if (nr_lights == 0) { 01143 release_temps(p); 01144 return; 01145 } 01146 01147 for (i = 0; i < MAX_LIGHTS; i++) { 01148 if (p->state->unit[i].light_enabled) { 01149 struct ureg half = undef; 01150 struct ureg att = undef, VPpli = undef; 01151 01152 count++; 01153 01154 if (p->state->unit[i].light_eyepos3_is_zero) { 01155 /* Can used precomputed constants in this case. 01156 * Attenuation never applies to infinite lights. 01157 */ 01158 VPpli = register_param3(p, STATE_INTERNAL, 01159 STATE_LIGHT_POSITION_NORMALIZED, i); 01160 01161 if (!p->state->material_shininess_is_zero) { 01162 if (p->state->light_local_viewer) { 01163 struct ureg eye_hat = get_eye_position_normalized(p); 01164 half = get_temp(p); 01165 emit_op2(p, OPCODE_SUB, half, 0, VPpli, eye_hat); 01166 emit_normalize_vec3(p, half, half); 01167 } else { 01168 half = register_param3(p, STATE_INTERNAL, 01169 STATE_LIGHT_HALF_VECTOR, i); 01170 } 01171 } 01172 } 01173 else { 01174 struct ureg Ppli = register_param3(p, STATE_INTERNAL, 01175 STATE_LIGHT_POSITION, i); 01176 struct ureg V = get_eye_position(p); 01177 struct ureg dist = get_temp(p); 01178 01179 VPpli = get_temp(p); 01180 01181 /* Calculate VPpli vector 01182 */ 01183 emit_op2(p, OPCODE_SUB, VPpli, 0, Ppli, V); 01184 01185 /* Normalize VPpli. The dist value also used in 01186 * attenuation below. 01187 */ 01188 emit_op2(p, OPCODE_DP3, dist, 0, VPpli, VPpli); 01189 emit_op1(p, OPCODE_RSQ, dist, 0, dist); 01190 emit_op2(p, OPCODE_MUL, VPpli, 0, VPpli, dist); 01191 01192 /* Calculate attenuation: 01193 */ 01194 if (!p->state->unit[i].light_spotcutoff_is_180 || 01195 p->state->unit[i].light_attenuated) { 01196 att = calculate_light_attenuation(p, i, VPpli, dist); 01197 } 01198 01199 /* Calculate viewer direction, or use infinite viewer: 01200 */ 01201 if (!p->state->material_shininess_is_zero) { 01202 half = get_temp(p); 01203 01204 if (p->state->light_local_viewer) { 01205 struct ureg eye_hat = get_eye_position_normalized(p); 01206 emit_op2(p, OPCODE_SUB, half, 0, VPpli, eye_hat); 01207 } 01208 else { 01209 struct ureg z_dir = swizzle(get_identity_param(p),X,Y,W,Z); 01210 emit_op2(p, OPCODE_ADD, half, 0, VPpli, z_dir); 01211 } 01212 01213 emit_normalize_vec3(p, half, half); 01214 } 01215 01216 release_temp(p, dist); 01217 } 01218 01219 /* Calculate dot products: 01220 */ 01221 if (p->state->material_shininess_is_zero) { 01222 emit_op2(p, OPCODE_DP3, dots, 0, normal, VPpli); 01223 } 01224 else { 01225 emit_op2(p, OPCODE_DP3, dots, WRITEMASK_X, normal, VPpli); 01226 emit_op2(p, OPCODE_DP3, dots, WRITEMASK_Y, normal, half); 01227 } 01228 01229 /* Front face lighting: 01230 */ 01231 { 01232 struct ureg ambient = get_lightprod(p, i, 0, STATE_AMBIENT); 01233 struct ureg diffuse = get_lightprod(p, i, 0, STATE_DIFFUSE); 01234 struct ureg specular = get_lightprod(p, i, 0, STATE_SPECULAR); 01235 struct ureg res0, res1; 01236 GLuint mask0, mask1; 01237 01238 if (count == nr_lights) { 01239 if (separate) { 01240 mask0 = WRITEMASK_XYZ; 01241 mask1 = WRITEMASK_XYZ; 01242 res0 = register_output( p, VERT_RESULT_COL0 ); 01243 res1 = register_output( p, VERT_RESULT_COL1 ); 01244 } 01245 else { 01246 mask0 = 0; 01247 mask1 = WRITEMASK_XYZ; 01248 res0 = _col0; 01249 res1 = register_output( p, VERT_RESULT_COL0 ); 01250 } 01251 } else { 01252 mask0 = 0; 01253 mask1 = 0; 01254 res0 = _col0; 01255 res1 = _col1; 01256 } 01257 01258 if (!is_undef(att)) { 01259 /* light is attenuated by distance */ 01260 emit_op1(p, OPCODE_LIT, lit, 0, dots); 01261 emit_op2(p, OPCODE_MUL, lit, 0, lit, att); 01262 emit_op3(p, OPCODE_MAD, _col0, 0, swizzle1(lit,X), ambient, _col0); 01263 } 01264 else if (!p->state->material_shininess_is_zero) { 01265 /* there's a non-zero specular term */ 01266 emit_op1(p, OPCODE_LIT, lit, 0, dots); 01267 emit_op2(p, OPCODE_ADD, _col0, 0, ambient, _col0); 01268 } 01269 else { 01270 /* no attenutation, no specular */ 01271 emit_degenerate_lit(p, lit, dots); 01272 emit_op2(p, OPCODE_ADD, _col0, 0, ambient, _col0); 01273 } 01274 01275 emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _col0); 01276 emit_op3(p, OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _col1); 01277 01278 release_temp(p, ambient); 01279 release_temp(p, diffuse); 01280 release_temp(p, specular); 01281 } 01282 01283 /* Back face lighting: 01284 */ 01285 if (twoside) { 01286 struct ureg ambient = get_lightprod(p, i, 1, STATE_AMBIENT); 01287 struct ureg diffuse = get_lightprod(p, i, 1, STATE_DIFFUSE); 01288 struct ureg specular = get_lightprod(p, i, 1, STATE_SPECULAR); 01289 struct ureg res0, res1; 01290 GLuint mask0, mask1; 01291 01292 if (count == nr_lights) { 01293 if (separate) { 01294 mask0 = WRITEMASK_XYZ; 01295 mask1 = WRITEMASK_XYZ; 01296 res0 = register_output( p, VERT_RESULT_BFC0 ); 01297 res1 = register_output( p, VERT_RESULT_BFC1 ); 01298 } 01299 else { 01300 mask0 = 0; 01301 mask1 = WRITEMASK_XYZ; 01302 res0 = _bfc0; 01303 res1 = register_output( p, VERT_RESULT_BFC0 ); 01304 } 01305 } else { 01306 res0 = _bfc0; 01307 res1 = _bfc1; 01308 mask0 = 0; 01309 mask1 = 0; 01310 } 01311 01312 dots = negate(swizzle(dots,X,Y,W,Z)); 01313 01314 if (!is_undef(att)) { 01315 emit_op1(p, OPCODE_LIT, lit, 0, dots); 01316 emit_op2(p, OPCODE_MUL, lit, 0, lit, att); 01317 emit_op3(p, OPCODE_MAD, _bfc0, 0, swizzle1(lit,X), ambient, _bfc0); 01318 } 01319 else if (!p->state->material_shininess_is_zero) { 01320 emit_op1(p, OPCODE_LIT, lit, 0, dots); 01321 emit_op2(p, OPCODE_ADD, _bfc0, 0, ambient, _bfc0); 01322 } 01323 else { 01324 emit_degenerate_lit(p, lit, dots); 01325 emit_op2(p, OPCODE_ADD, _bfc0, 0, ambient, _bfc0); 01326 } 01327 01328 emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _bfc0); 01329 emit_op3(p, OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _bfc1); 01330 /* restore negate flag for next lighting */ 01331 dots = negate(dots); 01332 01333 release_temp(p, ambient); 01334 release_temp(p, diffuse); 01335 release_temp(p, specular); 01336 } 01337 01338 release_temp(p, half); 01339 release_temp(p, VPpli); 01340 release_temp(p, att); 01341 } 01342 } 01343 01344 release_temps( p ); 01345 } 01346 01347 01348 static void build_fog( struct tnl_program *p ) 01349 { 01350 struct ureg fog = register_output(p, VERT_RESULT_FOGC); 01351 struct ureg input; 01352 01353 if (p->state->fog_source_is_depth) { 01354 input = get_eye_position_z(p); 01355 } 01356 else { 01357 input = swizzle1(register_input(p, VERT_ATTRIB_FOG), X); 01358 } 01359 01360 if (p->state->fog_mode && p->state->tnl_do_vertex_fog) { 01361 struct ureg params = register_param2(p, STATE_INTERNAL, 01362 STATE_FOG_PARAMS_OPTIMIZED); 01363 struct ureg tmp = get_temp(p); 01364 GLboolean useabs = (p->state->fog_mode != FOG_EXP2); 01365 01366 if (useabs) { 01367 emit_op1(p, OPCODE_ABS, tmp, 0, input); 01368 } 01369 01370 switch (p->state->fog_mode) { 01371 case FOG_LINEAR: { 01372 struct ureg id = get_identity_param(p); 01373 emit_op3(p, OPCODE_MAD, tmp, 0, useabs ? tmp : input, 01374 swizzle1(params,X), swizzle1(params,Y)); 01375 emit_op2(p, OPCODE_MAX, tmp, 0, tmp, swizzle1(id,X)); /* saturate */ 01376 emit_op2(p, OPCODE_MIN, fog, WRITEMASK_X, tmp, swizzle1(id,W)); 01377 break; 01378 } 01379 case FOG_EXP: 01380 emit_op2(p, OPCODE_MUL, tmp, 0, useabs ? tmp : input, 01381 swizzle1(params,Z)); 01382 emit_op1(p, OPCODE_EX2, fog, WRITEMASK_X, negate(tmp)); 01383 break; 01384 case FOG_EXP2: 01385 emit_op2(p, OPCODE_MUL, tmp, 0, input, swizzle1(params,W)); 01386 emit_op2(p, OPCODE_MUL, tmp, 0, tmp, tmp); 01387 emit_op1(p, OPCODE_EX2, fog, WRITEMASK_X, negate(tmp)); 01388 break; 01389 } 01390 01391 release_temp(p, tmp); 01392 } 01393 else { 01394 /* results = incoming fog coords (compute fog per-fragment later) 01395 * 01396 * KW: Is it really necessary to do anything in this case? 01397 * BP: Yes, we always need to compute the absolute value, unless 01398 * we want to push that down into the fragment program... 01399 */ 01400 GLboolean useabs = GL_TRUE; 01401 emit_op1(p, useabs ? OPCODE_ABS : OPCODE_MOV, fog, WRITEMASK_X, input); 01402 } 01403 } 01404 01405 01406 static void build_reflect_texgen( struct tnl_program *p, 01407 struct ureg dest, 01408 GLuint writemask ) 01409 { 01410 struct ureg normal = get_transformed_normal(p); 01411 struct ureg eye_hat = get_eye_position_normalized(p); 01412 struct ureg tmp = get_temp(p); 01413 01414 /* n.u */ 01415 emit_op2(p, OPCODE_DP3, tmp, 0, normal, eye_hat); 01416 /* 2n.u */ 01417 emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp); 01418 /* (-2n.u)n + u */ 01419 emit_op3(p, OPCODE_MAD, dest, writemask, negate(tmp), normal, eye_hat); 01420 01421 release_temp(p, tmp); 01422 } 01423 01424 01425 static void build_sphere_texgen( struct tnl_program *p, 01426 struct ureg dest, 01427 GLuint writemask ) 01428 { 01429 struct ureg normal = get_transformed_normal(p); 01430 struct ureg eye_hat = get_eye_position_normalized(p); 01431 struct ureg tmp = get_temp(p); 01432 struct ureg half = register_scalar_const(p, .5); 01433 struct ureg r = get_temp(p); 01434 struct ureg inv_m = get_temp(p); 01435 struct ureg id = get_identity_param(p); 01436 01437 /* Could share the above calculations, but it would be 01438 * a fairly odd state for someone to set (both sphere and 01439 * reflection active for different texture coordinate 01440 * components. Of course - if two texture units enable 01441 * reflect and/or sphere, things start to tilt in favour 01442 * of seperating this out: 01443 */ 01444 01445 /* n.u */ 01446 emit_op2(p, OPCODE_DP3, tmp, 0, normal, eye_hat); 01447 /* 2n.u */ 01448 emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp); 01449 /* (-2n.u)n + u */ 01450 emit_op3(p, OPCODE_MAD, r, 0, negate(tmp), normal, eye_hat); 01451 /* r + 0,0,1 */ 01452 emit_op2(p, OPCODE_ADD, tmp, 0, r, swizzle(id,X,Y,W,Z)); 01453 /* rx^2 + ry^2 + (rz+1)^2 */ 01454 emit_op2(p, OPCODE_DP3, tmp, 0, tmp, tmp); 01455 /* 2/m */ 01456 emit_op1(p, OPCODE_RSQ, tmp, 0, tmp); 01457 /* 1/m */ 01458 emit_op2(p, OPCODE_MUL, inv_m, 0, tmp, half); 01459 /* r/m + 1/2 */ 01460 emit_op3(p, OPCODE_MAD, dest, writemask, r, inv_m, half); 01461 01462 release_temp(p, tmp); 01463 release_temp(p, r); 01464 release_temp(p, inv_m); 01465 } 01466 01467 01468 static void build_texture_transform( struct tnl_program *p ) 01469 { 01470 GLuint i, j; 01471 01472 for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { 01473 01474 if (!(p->state->fragprog_inputs_read & FRAG_BIT_TEX(i))) 01475 continue; 01476 01477 if (p->state->unit[i].texgen_enabled || 01478 p->state->unit[i].texmat_enabled) { 01479 01480 GLuint texmat_enabled = p->state->unit[i].texmat_enabled; 01481 struct ureg out = register_output(p, VERT_RESULT_TEX0 + i); 01482 struct ureg out_texgen = undef; 01483 01484 if (p->state->unit[i].texgen_enabled) { 01485 GLuint copy_mask = 0; 01486 GLuint sphere_mask = 0; 01487 GLuint reflect_mask = 0; 01488 GLuint normal_mask = 0; 01489 GLuint modes[4]; 01490 01491 if (texmat_enabled) 01492 out_texgen = get_temp(p); 01493 else 01494 out_texgen = out; 01495 01496 modes[0] = p->state->unit[i].texgen_mode0; 01497 modes[1] = p->state->unit[i].texgen_mode1; 01498 modes[2] = p->state->unit[i].texgen_mode2; 01499 modes[3] = p->state->unit[i].texgen_mode3; 01500 01501 for (j = 0; j < 4; j++) { 01502 switch (modes[j]) { 01503 case TXG_OBJ_LINEAR: { 01504 struct ureg obj = register_input(p, VERT_ATTRIB_POS); 01505 struct ureg plane = 01506 register_param3(p, STATE_TEXGEN, i, 01507 STATE_TEXGEN_OBJECT_S + j); 01508 01509 emit_op2(p, OPCODE_DP4, out_texgen, WRITEMASK_X << j, 01510 obj, plane ); 01511 break; 01512 } 01513 case TXG_EYE_LINEAR: { 01514 struct ureg eye = get_eye_position(p); 01515 struct ureg plane = 01516 register_param3(p, STATE_TEXGEN, i, 01517 STATE_TEXGEN_EYE_S + j); 01518 01519 emit_op2(p, OPCODE_DP4, out_texgen, WRITEMASK_X << j, 01520 eye, plane ); 01521 break; 01522 } 01523 case TXG_SPHERE_MAP: 01524 sphere_mask |= WRITEMASK_X << j; 01525 break; 01526 case TXG_REFLECTION_MAP: 01527 reflect_mask |= WRITEMASK_X << j; 01528 break; 01529 case TXG_NORMAL_MAP: 01530 normal_mask |= WRITEMASK_X << j; 01531 break; 01532 case TXG_NONE: 01533 copy_mask |= WRITEMASK_X << j; 01534 } 01535 } 01536 01537 if (sphere_mask) { 01538 build_sphere_texgen(p, out_texgen, sphere_mask); 01539 } 01540 01541 if (reflect_mask) { 01542 build_reflect_texgen(p, out_texgen, reflect_mask); 01543 } 01544 01545 if (normal_mask) { 01546 struct ureg normal = get_transformed_normal(p); 01547 emit_op1(p, OPCODE_MOV, out_texgen, normal_mask, normal ); 01548 } 01549 01550 if (copy_mask) { 01551 struct ureg in = register_input(p, VERT_ATTRIB_TEX0+i); 01552 emit_op1(p, OPCODE_MOV, out_texgen, copy_mask, in ); 01553 } 01554 } 01555 01556 if (texmat_enabled) { 01557 struct ureg texmat[4]; 01558 struct ureg in = (!is_undef(out_texgen) ? 01559 out_texgen : 01560 register_input(p, VERT_ATTRIB_TEX0+i)); 01561 if (PREFER_DP4) { 01562 register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3, 01563 0, texmat ); 01564 emit_matrix_transform_vec4( p, out, texmat, in ); 01565 } 01566 else { 01567 register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3, 01568 STATE_MATRIX_TRANSPOSE, texmat ); 01569 emit_transpose_matrix_transform_vec4( p, out, texmat, in ); 01570 } 01571 } 01572 01573 release_temps(p); 01574 } 01575 else { 01576 emit_passthrough(p, VERT_ATTRIB_TEX0+i, VERT_RESULT_TEX0+i); 01577 } 01578 } 01579 } 01580 01581 01585 static void build_atten_pointsize( struct tnl_program *p ) 01586 { 01587 struct ureg eye = get_eye_position_z(p); 01588 struct ureg state_size = register_param1(p, STATE_POINT_SIZE); 01589 struct ureg state_attenuation = register_param1(p, STATE_POINT_ATTENUATION); 01590 struct ureg out = register_output(p, VERT_RESULT_PSIZ); 01591 struct ureg ut = get_temp(p); 01592 01593 /* dist = |eyez| */ 01594 emit_op1(p, OPCODE_ABS, ut, WRITEMASK_Y, swizzle1(eye, Z)); 01595 /* p1 + dist * (p2 + dist * p3); */ 01596 emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y), 01597 swizzle1(state_attenuation, Z), swizzle1(state_attenuation, Y)); 01598 emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y), 01599 ut, swizzle1(state_attenuation, X)); 01600 01601 /* 1 / sqrt(factor) */ 01602 emit_op1(p, OPCODE_RSQ, ut, WRITEMASK_X, ut ); 01603 01604 #if 0 01605 /* out = pointSize / sqrt(factor) */ 01606 emit_op2(p, OPCODE_MUL, out, WRITEMASK_X, ut, state_size); 01607 #else 01608 /* this is a good place to clamp the point size since there's likely 01609 * no hardware registers to clamp point size at rasterization time. 01610 */ 01611 emit_op2(p, OPCODE_MUL, ut, WRITEMASK_X, ut, state_size); 01612 emit_op2(p, OPCODE_MAX, ut, WRITEMASK_X, ut, swizzle1(state_size, Y)); 01613 emit_op2(p, OPCODE_MIN, out, WRITEMASK_X, ut, swizzle1(state_size, Z)); 01614 #endif 01615 01616 release_temp(p, ut); 01617 } 01618 01619 01623 static void build_constant_pointsize( struct tnl_program *p ) 01624 { 01625 struct ureg state_size = register_param1(p, STATE_POINT_SIZE); 01626 struct ureg out = register_output(p, VERT_RESULT_PSIZ); 01627 emit_op1(p, OPCODE_MOV, out, WRITEMASK_X, state_size); 01628 } 01629 01630 01634 static void build_array_pointsize( struct tnl_program *p ) 01635 { 01636 struct ureg in = register_input(p, VERT_ATTRIB_POINT_SIZE); 01637 struct ureg out = register_output(p, VERT_RESULT_PSIZ); 01638 emit_op1(p, OPCODE_MOV, out, WRITEMASK_X, in); 01639 } 01640 01641 01642 static void build_tnl_program( struct tnl_program *p ) 01643 { /* Emit the program, starting with modelviewproject: 01644 */ 01645 build_hpos(p); 01646 01647 /* Lighting calculations: 01648 */ 01649 if (p->state->fragprog_inputs_read & (FRAG_BIT_COL0|FRAG_BIT_COL1)) { 01650 if (p->state->light_global_enabled) 01651 build_lighting(p); 01652 else { 01653 if (p->state->fragprog_inputs_read & FRAG_BIT_COL0) 01654 emit_passthrough(p, VERT_ATTRIB_COLOR0, VERT_RESULT_COL0); 01655 01656 if (p->state->fragprog_inputs_read & FRAG_BIT_COL1) 01657 emit_passthrough(p, VERT_ATTRIB_COLOR1, VERT_RESULT_COL1); 01658 } 01659 } 01660 01661 if ((p->state->fragprog_inputs_read & FRAG_BIT_FOGC) || 01662 p->state->fog_mode != FOG_NONE) 01663 build_fog(p); 01664 01665 if (p->state->fragprog_inputs_read & FRAG_BITS_TEX_ANY) 01666 build_texture_transform(p); 01667 01668 if (p->state->point_attenuated) 01669 build_atten_pointsize(p); 01670 else if (p->state->point_array) 01671 build_array_pointsize(p); 01672 #if 0 01673 else 01674 build_constant_pointsize(p); 01675 #else 01676 (void) build_constant_pointsize; 01677 #endif 01678 01679 /* Finish up: 01680 */ 01681 emit_op1(p, OPCODE_END, undef, 0, undef); 01682 01683 /* Disassemble: 01684 */ 01685 if (DISASSEM) { 01686 _mesa_printf ("\n"); 01687 } 01688 } 01689 01690 01691 static void 01692 create_new_program( const struct state_key *key, 01693 struct gl_vertex_program *program, 01694 GLuint max_temps) 01695 { 01696 struct tnl_program p; 01697 01698 _mesa_memset(&p, 0, sizeof(p)); 01699 p.state = key; 01700 p.program = program; 01701 p.eye_position = undef; 01702 p.eye_position_z = undef; 01703 p.eye_position_normalized = undef; 01704 p.transformed_normal = undef; 01705 p.identity = undef; 01706 p.temp_in_use = 0; 01707 01708 if (max_temps >= sizeof(int) * 8) 01709 p.temp_reserved = 0; 01710 else 01711 p.temp_reserved = ~((1<<max_temps)-1); 01712 01713 /* Start by allocating 32 instructions. 01714 * If we need more, we'll grow the instruction array as needed. 01715 */ 01716 p.max_inst = 32; 01717 p.program->Base.Instructions = _mesa_alloc_instructions(p.max_inst); 01718 p.program->Base.String = NULL; 01719 p.program->Base.NumInstructions = 01720 p.program->Base.NumTemporaries = 01721 p.program->Base.NumParameters = 01722 p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0; 01723 p.program->Base.Parameters = _mesa_new_parameter_list(); 01724 p.program->Base.InputsRead = 0; 01725 p.program->Base.OutputsWritten = 0; 01726 01727 build_tnl_program( &p ); 01728 } 01729 01730 01736 struct gl_vertex_program * 01737 _mesa_get_fixed_func_vertex_program(GLcontext *ctx) 01738 { 01739 struct gl_vertex_program *prog; 01740 struct state_key key; 01741 01742 /* Grab all the relevent state and put it in a single structure: 01743 */ 01744 make_state_key(ctx, &key); 01745 01746 /* Look for an already-prepared program for this state: 01747 */ 01748 prog = (struct gl_vertex_program *) 01749 _mesa_search_program_cache(ctx->VertexProgram.Cache, &key, sizeof(key)); 01750 01751 if (!prog) { 01752 /* OK, we'll have to build a new one */ 01753 if (0) 01754 _mesa_printf("Build new TNL program\n"); 01755 01756 prog = (struct gl_vertex_program *) 01757 ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0); 01758 if (!prog) 01759 return NULL; 01760 01761 create_new_program( &key, prog, 01762 ctx->Const.VertexProgram.MaxTemps ); 01763 01764 #if 0 01765 if (ctx->Driver.ProgramStringNotify) 01766 ctx->Driver.ProgramStringNotify( ctx, GL_VERTEX_PROGRAM_ARB, 01767 &prog->Base ); 01768 #endif 01769 _mesa_program_cache_insert(ctx, ctx->VertexProgram.Cache, 01770 &key, sizeof(key), &prog->Base); 01771 } 01772 01773 return prog; 01774 } Generated on Sat May 26 2012 04:19:03 for ReactOS by
1.7.6.1
|