📄 texenvprogram.c
字号:
case MODE_MODULATE_SIGNED_ADD_ATI: { /* Arg0 * Arg2 + Arg1 - 0.5 */ struct ureg tmp0 = get_temp(p); half = get_half(p); emit_arith( p, OPCODE_MAD, tmp0, mask, 0, src[0], src[2], src[1] ); emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp0, half, undef ); return dest; } case MODE_MODULATE_SUBTRACT_ATI: /* Arg0 * Arg2 - Arg1 */ emit_arith( p, OPCODE_MAD, dest, mask, 0, src[0], src[2], negate(src[1]) ); return dest; default: return src[0]; }}/** * Generate instructions for one texture unit's env/combiner mode. */static struct uregemit_texenv(struct texenv_fragment_program *p, GLuint unit){ struct state_key *key = p->state; GLboolean saturate = (unit < p->last_tex_stage); GLuint rgb_shift, alpha_shift; struct ureg out, shift; struct ureg dest; if (!key->unit[unit].enabled) { return get_source(p, SRC_PREVIOUS, 0); } switch (key->unit[unit].ModeRGB) { case MODE_DOT3_RGB_EXT: alpha_shift = key->unit[unit].ScaleShiftA; rgb_shift = 0; break; case MODE_DOT3_RGBA_EXT: alpha_shift = 0; rgb_shift = 0; break; default: rgb_shift = key->unit[unit].ScaleShiftRGB; alpha_shift = key->unit[unit].ScaleShiftA; break; } /* If this is the very last calculation, emit direct to output reg: */ if (key->separate_specular || unit != p->last_tex_stage || alpha_shift || rgb_shift) dest = get_temp( p ); else dest = make_ureg(PROGRAM_OUTPUT, FRAG_RESULT_COLR); /* Emit the RGB and A combine ops */ if (key->unit[unit].ModeRGB == key->unit[unit].ModeA && args_match(key, unit)) { out = emit_combine( p, dest, WRITEMASK_XYZW, saturate, unit, key->unit[unit].NumArgsRGB, key->unit[unit].ModeRGB, key->unit[unit].OptRGB); } else if (key->unit[unit].ModeRGB == MODE_DOT3_RGBA_EXT || key->unit[unit].ModeA == MODE_DOT3_RGBA) { out = emit_combine( p, dest, WRITEMASK_XYZW, saturate, unit, key->unit[unit].NumArgsRGB, key->unit[unit].ModeRGB, key->unit[unit].OptRGB); } else { /* Need to do something to stop from re-emitting identical * argument calculations here: */ out = emit_combine( p, dest, WRITEMASK_XYZ, saturate, unit, key->unit[unit].NumArgsRGB, key->unit[unit].ModeRGB, key->unit[unit].OptRGB); out = emit_combine( p, dest, WRITEMASK_W, saturate, unit, key->unit[unit].NumArgsA, key->unit[unit].ModeA, key->unit[unit].OptA); } /* Deal with the final shift: */ if (alpha_shift || rgb_shift) { if (rgb_shift == alpha_shift) { shift = register_scalar_const(p, 1<<rgb_shift); } else { shift = register_const4f(p, 1<<rgb_shift, 1<<rgb_shift, 1<<rgb_shift, 1<<alpha_shift); } return emit_arith( p, OPCODE_MUL, dest, WRITEMASK_XYZW, saturate, out, shift, undef ); } else return out;}/** * Generate instruction for getting a texture source term. */static void load_texture( struct texenv_fragment_program *p, GLuint unit ){ if (is_undef(p->src_texture[unit])) { GLuint dim = p->state->unit[unit].source_index; struct ureg texcoord = register_input(p, FRAG_ATTRIB_TEX0+unit); struct ureg tmp = get_tex_temp( p ); if (dim == TEXTURE_UNKNOWN_INDEX) program_error(p, "TexSrcBit"); /* TODO: Use D0_MASK_XY where possible. */ if (p->state->unit[unit].enabled) p->src_texture[unit] = emit_texld( p, OPCODE_TXP, tmp, WRITEMASK_XYZW, unit, dim, texcoord ); else p->src_texture[unit] = get_zero(p); }}static GLboolean load_texenv_source( struct texenv_fragment_program *p, GLuint src, GLuint unit ){ switch (src) { case SRC_TEXTURE: load_texture(p, unit); break; case SRC_TEXTURE0: case SRC_TEXTURE1: case SRC_TEXTURE2: case SRC_TEXTURE3: case SRC_TEXTURE4: case SRC_TEXTURE5: case SRC_TEXTURE6: case SRC_TEXTURE7: load_texture(p, src - SRC_TEXTURE0); break; default: break; } return GL_TRUE;}/** * Generate instructions for loading all texture source terms. */static GLbooleanload_texunit_sources( struct texenv_fragment_program *p, int unit ){ struct state_key *key = p->state; GLuint i; for (i = 0; i < key->unit[unit].NumArgsRGB; i++) { load_texenv_source( p, key->unit[unit].OptRGB[i].Source, unit); } for (i = 0; i < key->unit[unit].NumArgsA; i++) { load_texenv_source( p, key->unit[unit].OptA[i].Source, unit ); } return GL_TRUE;}/** * Generate a new fragment program which implements the context's * current texture env/combine mode. */static voidcreate_new_program(struct state_key *key, GLcontext *ctx, struct fragment_program *program){ struct texenv_fragment_program p; GLuint unit; struct ureg cf, out; _mesa_memset(&p, 0, sizeof(p)); p.ctx = ctx; p.state = key; p.program = program; p.program->Base.Instructions = (struct prog_instruction*) _mesa_malloc(sizeof(struct prog_instruction) * MAX_INSTRUCTIONS); p.program->Base.NumInstructions = 0; p.program->Base.Target = GL_FRAGMENT_PROGRAM_ARB; p.program->NumTexIndirections = 1; /* correct? */ p.program->NumTexInstructions = 0; p.program->NumAluInstructions = 0; p.program->Base.String = 0; p.program->Base.NumInstructions = p.program->Base.NumTemporaries = p.program->Base.NumParameters = p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0; p.program->Base.Parameters = _mesa_new_parameter_list(); p.program->Base.InputsRead = 0; p.program->Base.OutputsWritten = 1 << FRAG_RESULT_COLR; for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) p.src_texture[unit] = undef; p.src_previous = undef; p.last_tex_stage = 0; release_temps(&p); if (key->enabled_units) { /* First pass - to support texture_env_crossbar, first identify * all referenced texture sources and emit texld instructions * for each: */ for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++) if (key->unit[unit].enabled) { load_texunit_sources( &p, unit ); p.last_tex_stage = unit; } /* Second pass - emit combine instructions to build final color: */ for (unit = 0 ; unit < ctx->Const.MaxTextureUnits; unit++) if (key->enabled_units & (1<<unit)) { p.src_previous = emit_texenv( &p, unit ); release_temps(&p); /* release all temps */ } } cf = get_source( &p, SRC_PREVIOUS, 0 ); out = make_ureg( PROGRAM_OUTPUT, FRAG_RESULT_COLR ); if (key->separate_specular) { /* Emit specular add. */ struct ureg s = register_input(&p, FRAG_ATTRIB_COL1); emit_arith( &p, OPCODE_ADD, out, WRITEMASK_XYZ, 0, cf, s, undef ); emit_arith( &p, OPCODE_MOV, out, WRITEMASK_W, 0, cf, undef, undef ); } else if (_mesa_memcmp(&cf, &out, sizeof(cf)) != 0) { /* Will wind up in here if no texture enabled or a couple of * other scenarios (GL_REPLACE for instance). */ emit_arith( &p, OPCODE_MOV, out, WRITEMASK_XYZW, 0, cf, undef, undef ); } /* Finish up: */ emit_arith( &p, OPCODE_END, undef, WRITEMASK_XYZW, 0, undef, undef, undef); if (key->fog_enabled) { /* Pull fog mode from GLcontext, the value in the state key is * a reduced value and not what is expected in FogOption */ p.program->FogOption = ctx->Fog.Mode; } else p.program->FogOption = GL_NONE; if (p.program->NumTexIndirections > ctx->Const.FragmentProgram.MaxTexIndirections) program_error(&p, "Exceeded max nr indirect texture lookups"); if (p.program->NumTexInstructions > ctx->Const.FragmentProgram.MaxTexInstructions) program_error(&p, "Exceeded max TEX instructions"); if (p.program->NumAluInstructions > ctx->Const.FragmentProgram.MaxAluInstructions) program_error(&p, "Exceeded max ALU instructions"); ASSERT(p.program->Base.NumInstructions <= MAX_INSTRUCTIONS); /* Notify driver the fragment program has (actually) changed. */ if (ctx->Driver.ProgramStringNotify || DISASSEM) { if (ctx->Driver.ProgramStringNotify) ctx->Driver.ProgramStringNotify( ctx, GL_FRAGMENT_PROGRAM_ARB, &p.program->Base ); if (DISASSEM) { _mesa_print_program(&p.program->Base); _mesa_printf("\n"); } }}static void *search_cache( struct texenvprog_cache *cache, GLuint hash, const void *key, GLuint keysize){ struct texenvprog_cache *c; for (c = cache; c; c = c->next) { if (c->hash == hash && _mesa_memcmp(c->key, key, keysize) == 0) return c->data; } return NULL;}static void cache_item( struct texenvprog_cache **cache, GLuint hash, void *key, void *data ){ struct texenvprog_cache *c = CALLOC_STRUCT(texenvprog_cache); c->hash = hash; c->key = key; c->data = data; c->next = *cache; *cache = c;}static GLuint hash_key( struct state_key *key ){ GLuint *ikey = (GLuint *)key; GLuint hash = 0, i; /* I'm sure this can be improved on, but speed is important: */ for (i = 0; i < sizeof(*key)/sizeof(GLuint); i++) hash ^= ikey[i]; return hash;}void _mesa_UpdateTexEnvProgram( GLcontext *ctx ){ struct state_key *key; GLuint hash; struct fragment_program *prev = ctx->FragmentProgram._Current; if (!ctx->FragmentProgram._Enabled) { key = make_state_key(ctx); hash = hash_key(key); ctx->FragmentProgram._Current = ctx->_TexEnvProgram = (struct fragment_program *) search_cache(ctx->Texture.env_fp_cache, hash, key, sizeof(*key)); if (!ctx->_TexEnvProgram) { if (0) _mesa_printf("Building new texenv proggy for key %x\n", hash); ctx->FragmentProgram._Current = ctx->_TexEnvProgram = (struct fragment_program *) ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); create_new_program(key, ctx, ctx->_TexEnvProgram); cache_item(&ctx->Texture.env_fp_cache, hash, key, ctx->_TexEnvProgram); } else { _mesa_free(key); if (0) _mesa_printf("Found existing texenv program for key %x\n", hash); } } else { ctx->FragmentProgram._Current = ctx->FragmentProgram.Current; } /* Tell the driver about the change. Could define a new target for * this? */ if (ctx->FragmentProgram._Current != prev && ctx->Driver.BindProgram) { ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, (struct program *) ctx->FragmentProgram._Current); }}void _mesa_TexEnvProgramCacheDestroy( GLcontext *ctx ){ struct texenvprog_cache *a, *tmp; for (a = ctx->Texture.env_fp_cache; a; a = tmp) { tmp = a->next; _mesa_free(a->key); ctx->Driver.DeleteProgram(ctx, (struct program *) a->data); _mesa_free(a); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -