📄 texenvprogram.c
字号:
struct ureg two = register_scalar_const(p, 2);
/* tmp0 = 2*src0 - 1
* tmp1 = 2*src1 - 1
*
* dst = tmp0 dot3 tmp1
*/
emit_arith( p, FP_OPCODE_MAD, tmp0, WRITEMASK_XYZW, 0,
two, src[0], neg1);
if (memcmp(&src[0], &src[1], sizeof(struct ureg)) == 0)
tmp1 = tmp0;
else
emit_arith( p, FP_OPCODE_MAD, tmp1, WRITEMASK_XYZW, 0,
two, src[1], neg1);
emit_arith( p, FP_OPCODE_DP3, dest, mask, saturate, tmp0, tmp1, undef);
return dest;
}
case MODE_MODULATE_ADD_ATI:
/* Arg0 * Arg2 + Arg1 */
return emit_arith( p, FP_OPCODE_MAD, dest, mask, saturate,
src[0], src[2], src[1] );
case MODE_MODULATE_SIGNED_ADD_ATI: {
/* Arg0 * Arg2 + Arg1 - 0.5 */
struct ureg tmp0 = get_temp(p);
half = get_half(p);
emit_arith( p, FP_OPCODE_MAD, tmp0, mask, 0, src[0], src[2], src[1] );
emit_arith( p, FP_OPCODE_SUB, dest, mask, saturate, tmp0, half, undef );
return dest;
}
case MODE_MODULATE_SUBTRACT_ATI:
/* Arg0 * Arg2 - Arg1 */
emit_arith( p, FP_OPCODE_MAD, dest, mask, 0, src[0], src[2], negate(src[1]) );
return dest;
default:
return src[0];
}
}
static struct ureg emit_texenv( struct texenv_fragment_program *p, int unit )
{
struct state_key *key = p->state;
GLuint 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_OUTPUT_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, FP_OPCODE_MUL, dest, WRITEMASK_XYZW,
saturate, out, shift, undef );
}
else
return out;
}
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.
*/
p->src_texture[unit] = emit_texld( p, FP_OPCODE_TXP,
tmp, WRITEMASK_XYZW,
unit, dim, texcoord );
}
}
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:
if (!p->state->unit[src - SRC_TEXTURE0].enabled)
return GL_FALSE;
load_texture(p, src - SRC_TEXTURE0);
break;
default:
break;
}
return GL_TRUE;
}
static GLboolean load_texunit_sources( struct texenv_fragment_program *p, int unit )
{
struct state_key *key = p->state;
int i, nr = key->unit[unit].NumArgsRGB;
for (i = 0; i < nr; i++) {
if (!load_texenv_source( p, key->unit[unit].OptRGB[i].Source, unit) ||
!load_texenv_source( p, key->unit[unit].OptA[i].Source, unit ))
return GL_FALSE;
}
return GL_TRUE;
}
static void create_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->Instructions = MALLOC(sizeof(struct fp_instruction) * 100);
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->Parameters = _mesa_new_parameter_list();
p.program->InputsRead = 0;
p.program->OutputsWritten = 1 << FRAG_OUTPUT_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) {
if (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_OUTPUT_COLR );
if (key->separate_specular) {
/* Emit specular add.
*/
struct ureg s = register_input(&p, FRAG_ATTRIB_COL1);
emit_arith( &p, FP_OPCODE_ADD, out, WRITEMASK_XYZ, 0, cf, s, undef );
}
else if (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, FP_OPCODE_MOV, out, WRITEMASK_XYZW, 0, cf, undef, undef );
}
/* Finish up:
*/
emit_arith( &p, FP_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.MaxFragmentProgramTexIndirections)
program_error(&p, "Exceeded max nr indirect texture lookups");
if (p.program->NumTexInstructions > ctx->Const.MaxFragmentProgramTexInstructions)
program_error(&p, "Exceeded max TEX instructions");
if (p.program->NumAluInstructions > ctx->Const.MaxFragmentProgramAluInstructions)
program_error(&p, "Exceeded max ALU 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_debug_fp_inst(p.program->NumTexInstructions + p.program->NumAluInstructions,
p.program->Instructions);
_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 && 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 = MALLOC(sizeof(*c));
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;
if (ctx->FragmentProgram._Enabled)
return;
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 {
FREE(key);
if (0) _mesa_printf("Found existing texenv program for key %x\n", hash);
}
}
void _mesa_TexEnvProgramCacheDestroy( GLcontext *ctx )
{
struct texenvprog_cache *a, *tmp;
for (a = ctx->Texture.env_fp_cache; a; a = tmp) {
tmp = a->next;
FREE(a->key);
FREE(a->data);
FREE(a);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -