ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

ffvertex_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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.