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

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

Generated on Fri May 25 2012 04:18:37 for ReactOS by doxygen 1.7.6.1

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