/**************************************************************************
*
- * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
#include "glheader.h"
#include "macros.h"
#include "enums.h"
+#include "shader/prog_parameter.h"
+#include "shader/prog_cache.h"
+#include "shader/prog_instruction.h"
+#include "shader/prog_print.h"
+#include "shader/prog_statevars.h"
+#include "shader/programopt.h"
#include "texenvprogram.h"
-#include "shader/program.h"
-#include "shader/program_instruction.h"
-#include "shader/arbfragparse.h"
-
+/**
+ * This MAX is probably a bit generous, but that's OK. There can be
+ * up to four instructions per texture unit (TEX + 3 for combine),
+ * then there's fog and specular add.
+ */
+#define MAX_INSTRUCTIONS ((MAX_TEXTURE_UNITS * 4) + 12)
#define DISASSEM (MESA_VERBOSE & VERBOSE_DISASSEM)
struct mode_opt {
- unsigned Source:4;
- unsigned Operand:3;
+ GLuint Source:4;
+ GLuint Operand:3;
};
struct state_key {
- GLuint enabled_units;
- unsigned separate_specular:1;
- unsigned fog_enabled:1;
- unsigned fog_mode:2;
+ GLbitfield enabled_units;
+ GLuint separate_specular:1;
+ GLuint fog_enabled:1;
+ GLuint fog_mode:2;
struct {
- unsigned enabled:1;
- unsigned source_index:3;
- unsigned ScaleShiftRGB:2;
- unsigned ScaleShiftA:2;
+ GLuint enabled:1;
+ GLuint source_index:3; /* one of TEXTURE_1D/2D/3D/CUBE/RECT_INDEX */
+ GLuint ScaleShiftRGB:2;
+ GLuint ScaleShiftA:2;
- unsigned NumArgsRGB:2;
- unsigned ModeRGB:4;
+ GLuint NumArgsRGB:2;
+ GLuint ModeRGB:4;
struct mode_opt OptRGB[3];
- unsigned NumArgsA:2;
- unsigned ModeA:4;
+ GLuint NumArgsA:2;
+ GLuint ModeA:4;
struct mode_opt OptA[3];
} unit[8];
};
}
}
-static struct state_key *make_state_key( GLcontext *ctx )
+/**
+ * Examine current texture environment state and generate a unique
+ * key to identify it.
+ */
+static void make_state_key( GLcontext *ctx, struct state_key *key )
{
- struct state_key *key = CALLOC_STRUCT(state_key);
GLuint i, j;
+ memset(key, 0, sizeof(*key));
+
for (i=0;i<MAX_TEXTURE_UNITS;i++) {
- struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
if (!texUnit->_ReallyEnabled)
continue;
translate_mode(texUnit->_CurrentCombine->ModeA);
key->unit[i].ScaleShiftRGB = texUnit->_CurrentCombine->ScaleShiftRGB;
- key->unit[i].ScaleShiftA = texUnit->_CurrentCombine->ScaleShiftRGB;
+ key->unit[i].ScaleShiftA = texUnit->_CurrentCombine->ScaleShiftA;
for (j=0;j<3;j++) {
key->unit[i].OptRGB[j].Operand =
key->fog_enabled = 1;
key->fog_mode = translate_fog_mode(ctx->Fog.Mode);
}
-
- return key;
}
/* Use uregs to represent registers internally, translate to Mesa's
GLuint pad:5;
};
-const static struct ureg undef = {
- ~0,
+static const struct ureg undef = {
+ PROGRAM_UNDEFINED,
~0,
0,
0,
0
};
-#define X 0
-#define Y 1
-#define Z 2
-#define W 3
/* State used to build the fragment program:
*/
struct texenv_fragment_program {
- struct fragment_program *program;
+ struct gl_fragment_program *program;
GLcontext *ctx;
struct state_key *state;
- GLuint alu_temps; /* Track texture indirections, see spec. */
- GLuint temps_output; /* Track texture indirections, see spec. */
-
- GLuint temp_in_use; /* Tracks temporary regs which are in
- * use.
- */
-
-
+ GLbitfield alu_temps; /* Track texture indirections, see spec. */
+ GLbitfield temps_output; /* Track texture indirections, see spec. */
+ GLbitfield temp_in_use; /* Tracks temporary regs which are in use. */
GLboolean error;
struct ureg src_texture[MAX_TEXTURE_UNITS];
static GLboolean is_undef( struct ureg reg )
{
- return reg.file == 0xf;
+ return reg.file == PROGRAM_UNDEFINED;
}
static struct ureg get_temp( struct texenv_fragment_program *p )
{
- int bit;
+ GLint bit;
/* First try and reuse temps which have been used already:
*/
_mesa_exit(1);
}
- if (bit > p->program->Base.NumTemporaries)
+ if ((GLuint) bit > p->program->Base.NumTemporaries)
p->program->Base.NumTemporaries = bit;
p->temp_in_use |= 1<<(bit-1);
_mesa_exit(1);
}
- if (bit > p->program->Base.NumTemporaries)
+ if ((GLuint) bit > p->program->Base.NumTemporaries)
p->program->Base.NumTemporaries = bit;
p->temp_in_use |= 1<<(bit-1);
}
-static void release_temps( struct texenv_fragment_program *p )
+static void release_temps(GLcontext *ctx, struct texenv_fragment_program *p )
{
- GLuint max_temp = p->ctx->Const.FragmentProgram.MaxTemps;
+ GLuint max_temp = ctx->Const.FragmentProgram.MaxTemps;
/* KW: To support tex_env_crossbar, don't release the registers in
* temps_output.
}
-static struct ureg register_param6( struct texenv_fragment_program *p,
+static struct ureg register_param5( struct texenv_fragment_program *p,
GLint s0,
GLint s1,
GLint s2,
GLint s3,
- GLint s4,
- GLint s5)
+ GLint s4)
{
- GLint tokens[6];
+ gl_state_index tokens[STATE_LENGTH];
GLuint idx;
tokens[0] = s0;
tokens[1] = s1;
tokens[2] = s2;
tokens[3] = s3;
tokens[4] = s4;
- tokens[5] = s5;
idx = _mesa_add_state_reference( p->program->Base.Parameters, tokens );
return make_ureg(PROGRAM_STATE_VAR, idx);
}
-#define register_param1(p,s0) register_param6(p,s0,0,0,0,0,0)
-#define register_param2(p,s0,s1) register_param6(p,s0,s1,0,0,0,0)
-#define register_param3(p,s0,s1,s2) register_param6(p,s0,s1,s2,0,0,0)
-#define register_param4(p,s0,s1,s2,s3) register_param6(p,s0,s1,s2,s3,0,0)
+#define register_param1(p,s0) register_param5(p,s0,0,0,0,0)
+#define register_param2(p,s0,s1) register_param5(p,s0,s1,0,0,0)
+#define register_param3(p,s0,s1,s2) register_param5(p,s0,s1,s2,0,0)
+#define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0)
static struct ureg register_input( struct texenv_fragment_program *p, GLuint input )
dst->File = ureg.file;
dst->Index = ureg.idx;
dst->WriteMask = mask;
- dst->CondMask = 0;
- dst->CondSwizzle = 0;
+ dst->CondMask = COND_TR; /* always pass cond test */
+ dst->CondSwizzle = SWIZZLE_NOOP;
}
static struct prog_instruction *
emit_op(struct texenv_fragment_program *p,
- GLuint op,
+ enum prog_opcode op,
struct ureg dest,
GLuint mask,
- GLuint saturate,
+ GLboolean saturate,
struct ureg src0,
struct ureg src1,
struct ureg src2 )
GLuint nr = p->program->Base.NumInstructions++;
struct prog_instruction *inst = &p->program->Base.Instructions[nr];
- _mesa_memset(inst, 0, sizeof(*inst));
+ assert(nr < MAX_INSTRUCTIONS);
+
+ _mesa_init_instructions(inst, 1);
inst->Opcode = op;
emit_arg( &inst->SrcReg[0], src0 );
emit_arg( &inst->SrcReg[1], src1 );
emit_arg( &inst->SrcReg[2], src2 );
- inst->Saturate = saturate;
+ inst->SaturateMode = saturate ? SATURATE_ZERO_ONE : SATURATE_OFF;
emit_dst( &inst->DstReg, dest, mask );
static struct ureg emit_arith( struct texenv_fragment_program *p,
- GLuint op,
+ enum prog_opcode op,
struct ureg dest,
GLuint mask,
- GLuint saturate,
+ GLboolean saturate,
struct ureg src0,
struct ureg src1,
struct ureg src2 )
if (dest.file == PROGRAM_TEMPORARY)
p->alu_temps |= 1 << dest.idx;
- p->program->NumAluInstructions++;
+ p->program->Base.NumAluInstructions++;
return dest;
}
static struct ureg emit_texld( struct texenv_fragment_program *p,
- GLuint op,
+ enum prog_opcode op,
struct ureg dest,
GLuint destmask,
GLuint tex_unit,
{
struct prog_instruction *inst = emit_op( p, op,
dest, destmask,
- 0, /* don't saturate? */
+ GL_FALSE, /* don't saturate? */
coord, /* arg 0? */
undef,
undef);
inst->TexSrcTarget = tex_idx;
inst->TexSrcUnit = tex_unit;
- p->program->NumTexInstructions++;
+ p->program->Base.NumTexInstructions++;
/* Is this a texture indirection?
*/
(p->temps_output & (1<<coord.idx))) ||
(dest.file == PROGRAM_TEMPORARY &&
(p->alu_temps & (1<<dest.idx)))) {
- p->program->NumTexIndirections++;
+ p->program->Base.NumTexIndirections++;
p->temps_output = 1<<coord.idx;
p->alu_temps = 0;
assert(0); /* KW: texture env crossbar */
GLfloat s3)
{
GLfloat values[4];
- GLuint idx;
+ GLuint idx, swizzle;
values[0] = s0;
values[1] = s1;
values[2] = s2;
values[3] = s3;
- idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values );
- return make_ureg(PROGRAM_STATE_VAR, idx);
+ idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4,
+ &swizzle );
+ ASSERT(swizzle == SWIZZLE_NOOP);
+ return make_ureg(PROGRAM_CONSTANT, idx);
}
#define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0)
#define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1)
-
-
static struct ureg get_one( struct texenv_fragment_program *p )
{
if (is_undef(p->one))
static struct ureg get_half( struct texenv_fragment_program *p )
{
if (is_undef(p->half))
- p->one = register_scalar_const(p, 0.5);
+ p->half = register_scalar_const(p, 0.5);
return p->half;
}
static struct ureg get_zero( struct texenv_fragment_program *p )
{
if (is_undef(p->zero))
- p->one = register_scalar_const(p, 0.0);
+ p->zero = register_scalar_const(p, 0.0);
return p->zero;
}
-
-
-
static void program_error( struct texenv_fragment_program *p, const char *msg )
{
_mesa_problem(NULL, msg);
if (mask == WRITEMASK_W)
return src;
else
- return swizzle1( src, W );
+ return swizzle1( src, SWIZZLE_W );
case OPR_ONE_MINUS_SRC_ALPHA:
/* Get unused tmp,
* Emit tmp = 1.0 - arg.wwww
arg = get_temp(p);
one = get_one(p);
return emit_arith(p, OPCODE_SUB, arg, mask, 0,
- one, swizzle1(src, W), undef);
+ one, swizzle1(src, SWIZZLE_W), undef);
case OPR_ZERO:
return get_zero(p);
case OPR_ONE:
static GLboolean args_match( struct state_key *key, GLuint unit )
{
- int i, nr = key->unit[unit].NumArgsRGB;
+ GLuint i, nr = key->unit[unit].NumArgsRGB;
for (i = 0 ; i < nr ; i++) {
if (key->unit[unit].OptA[i].Source != key->unit[unit].OptRGB[i].Source)
static struct ureg emit_combine( struct texenv_fragment_program *p,
struct ureg dest,
GLuint mask,
- GLuint saturate,
+ GLboolean saturate,
GLuint unit,
GLuint nr,
GLuint mode,
- struct mode_opt *opt)
+ const struct mode_opt *opt)
{
struct ureg src[3];
struct ureg tmp, half;
- int i;
+ GLuint i;
+
+ tmp = undef; /* silence warning (bug 5318) */
for (i = 0; i < nr; i++)
src[i] = emit_combine_source( p, mask, unit, opt[i].Source, opt[i].Operand );
* result = tmp - .5
*/
half = get_half(p);
+ tmp = get_temp( p );
emit_arith( p, OPCODE_ADD, tmp, mask, 0, src[0], src[1], undef );
emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp, half, undef );
return dest;
}
-static struct ureg emit_texenv( struct texenv_fragment_program *p, int unit )
+/**
+ * Generate instructions for one texture unit's env/combiner mode.
+ */
+static struct ureg
+emit_texenv(struct texenv_fragment_program *p, GLuint unit)
{
struct state_key *key = p->state;
- GLuint saturate = (unit < p->last_tex_stage);
+ GLboolean saturate = (unit < p->last_tex_stage);
GLuint rgb_shift, alpha_shift;
struct ureg out, shift;
struct ureg dest;
key->unit[unit].OptRGB);
}
else if (key->unit[unit].ModeRGB == MODE_DOT3_RGBA_EXT ||
- key->unit[unit].ModeA == MODE_DOT3_RGBA) {
+ key->unit[unit].ModeRGB == MODE_DOT3_RGBA) {
out = emit_combine( p, dest, WRITEMASK_XYZW, saturate,
unit,
*/
if (alpha_shift || rgb_shift) {
if (rgb_shift == alpha_shift) {
- shift = register_scalar_const(p, 1<<rgb_shift);
+ shift = register_scalar_const(p, (GLfloat)(1<<rgb_shift));
}
else {
shift = register_const4f(p,
- 1<<rgb_shift,
- 1<<rgb_shift,
- 1<<rgb_shift,
- 1<<alpha_shift);
+ (GLfloat)(1<<rgb_shift),
+ (GLfloat)(1<<rgb_shift),
+ (GLfloat)(1<<rgb_shift),
+ (GLfloat)(1<<alpha_shift));
}
return emit_arith( p, OPCODE_MUL, dest, WRITEMASK_XYZW,
saturate, out, shift, undef );
}
-
+/**
+ * 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])) {
/* TODO: Use D0_MASK_XY where possible.
*/
- p->src_texture[unit] = emit_texld( p, OPCODE_TXP,
- tmp, WRITEMASK_XYZW,
- unit, dim, texcoord );
+ if (p->state->unit[unit].enabled) {
+ p->src_texture[unit] = emit_texld( p, OPCODE_TXP,
+ tmp, WRITEMASK_XYZW,
+ unit, dim, texcoord );
+ p->program->Base.SamplersUsed |= (1 << unit);
+ /* This identity mapping should already be in place
+ * (see _mesa_init_program_struct()) but let's be safe.
+ */
+ p->program->Base.SamplerUnits[unit] = unit;
+ }
+ else
+ p->src_texture[unit] = get_zero(p);
}
}
GLuint src, GLuint unit )
{
switch (src) {
- case SRC_TEXTURE:
+ case SRC_TEXTURE:
load_texture(p, unit);
break;
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;
return GL_TRUE;
}
-static GLboolean load_texunit_sources( struct texenv_fragment_program *p, int unit )
+
+/**
+ * Generate instructions for loading all texture source terms.
+ */
+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;
+ 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;
}
-static void create_new_program(struct state_key *key, GLcontext *ctx,
- struct fragment_program *program)
+
+/**
+ * Generate a new fragment program which implements the context's
+ * current texture env/combine mode.
+ */
+static void
+create_new_program(GLcontext *ctx, struct state_key *key,
+ struct gl_fragment_program *program)
{
+ struct prog_instruction instBuffer[MAX_INSTRUCTIONS];
struct texenv_fragment_program p;
GLuint unit;
struct ureg cf, out;
p.state = key;
p.program = program;
- p.program->Base.Instructions = MALLOC(sizeof(struct prog_instruction) * 100);
- p.program->Base.NumInstructions = 0;
+ /* During code generation, use locally-allocated instruction buffer,
+ * then alloc dynamic storage below.
+ */
+ p.program->Base.Instructions = instBuffer;
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.NumTexIndirections = 1; /* correct? */
+ p.program->Base.NumTexInstructions = 0;
+ p.program->Base.NumAluInstructions = 0;
+ p.program->Base.String = NULL;
p.program->Base.NumInstructions =
- p.program->Base.NumTemporaries =
- p.program->Base.NumParameters =
- p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0;
+ 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.src_texture[unit] = undef;
p.src_previous = undef;
+ p.half = undef;
+ p.zero = undef;
+ p.one = undef;
+
p.last_tex_stage = 0;
- release_temps(&p);
+ release_temps(ctx, &p);
if (key->enabled_units) {
/* First pass - to support texture_env_crossbar, first identify
*/
for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++)
if (key->unit[unit].enabled) {
- if (load_texunit_sources( &p, unit ))
- p.last_tex_stage = unit;
+ 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 */
+ release_temps(ctx, &p); /* release all temps */
}
}
* a reduced value and not what is expected in FogOption
*/
p.program->FogOption = ctx->Fog.Mode;
+ p.program->Base.InputsRead |= FRAG_BIT_FOGC; /* XXX new */
} else
p.program->FogOption = GL_NONE;
- if (p.program->NumTexIndirections > ctx->Const.FragmentProgram.MaxTexIndirections)
+ if (p.program->Base.NumTexIndirections > ctx->Const.FragmentProgram.MaxTexIndirections)
program_error(&p, "Exceeded max nr indirect texture lookups");
- if (p.program->NumTexInstructions > ctx->Const.FragmentProgram.MaxTexInstructions)
+ if (p.program->Base.NumTexInstructions > ctx->Const.FragmentProgram.MaxTexInstructions)
program_error(&p, "Exceeded max TEX instructions");
- if (p.program->NumAluInstructions > ctx->Const.FragmentProgram.MaxAluInstructions)
+ if (p.program->Base.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");
- }
-
+ /* Allocate final instruction array */
+ p.program->Base.Instructions
+ = _mesa_alloc_instructions(p.program->Base.NumInstructions);
+ if (!p.program->Base.Instructions) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY,
+ "generating tex env program");
+ return;
}
+ _mesa_copy_instructions(p.program->Base.Instructions, instBuffer,
+ p.program->Base.NumInstructions);
-}
+ if (p.program->FogOption) {
+ _mesa_append_fog_code(ctx, p.program);
+ p.program->FogOption = GL_NONE;
+ }
-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;
+ /* Notify driver the fragment program has (actually) changed.
+ */
+ if (ctx->Driver.ProgramStringNotify) {
+ ctx->Driver.ProgramStringNotify( ctx, GL_FRAGMENT_PROGRAM_ARB,
+ &p.program->Base );
}
- return NULL;
+ if (DISASSEM) {
+ _mesa_print_program(&p.program->Base);
+ _mesa_printf("\n");
+ }
}
-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 )
+/**
+ * Return a fragment program which implements the current
+ * fixed-function texture, fog and color-sum operations.
+ */
+struct gl_fragment_program *
+_mesa_get_fixed_func_fragment_program(GLcontext *ctx)
{
- GLuint *ikey = (GLuint *)key;
- GLuint hash = 0, i;
+ struct gl_fragment_program *prog;
+ struct state_key key;
+
+ make_state_key(ctx, &key);
+
+ prog = (struct gl_fragment_program *)
+ _mesa_search_program_cache(ctx->FragmentProgram.Cache,
+ &key, sizeof(key));
- /* I'm sure this can be improved on, but speed is important:
- */
- for (i = 0; i < sizeof(*key)/sizeof(GLuint); i++)
- hash ^= ikey[i];
+ if (!prog) {
+ prog = (struct gl_fragment_program *)
+ ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
+
+ create_new_program(ctx, &key, prog);
- return hash;
+ _mesa_program_cache_insert(ctx, ctx->FragmentProgram.Cache,
+ &key, sizeof(key), &prog->Base);
+ }
+
+ return prog;
}
-void _mesa_UpdateTexEnvProgram( GLcontext *ctx )
+
+
+/**
+ * If _MaintainTexEnvProgram is set we'll generate a fragment program that
+ * implements the current texture env/combine mode.
+ * This function generates that program and puts it into effect.
+ */
+void
+_mesa_UpdateTexEnvProgram( GLcontext *ctx )
{
- struct state_key *key;
- GLuint hash;
- struct fragment_program *prev = ctx->FragmentProgram._Current;
+ const struct gl_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 (1) _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);
+ ASSERT(ctx->FragmentProgram._MaintainTexEnvProgram);
- cache_item(&ctx->Texture.env_fp_cache, hash, key, ctx->_TexEnvProgram);
- } else {
- FREE(key);
- if (1) _mesa_printf("Found existing texenv program for key %x\n", hash);
- }
+ /* If a conventional fragment program/shader isn't in effect... */
+ if (!ctx->FragmentProgram._Enabled &&
+ (!ctx->Shader.CurrentProgram ||
+ !ctx->Shader.CurrentProgram->FragmentProgram) ) {
+
+ ctx->FragmentProgram._Current
+ = ctx->FragmentProgram._TexEnvProgram
+ = _mesa_get_fixed_func_fragment_program(ctx);
}
- 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, 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;
- FREE(a->key);
- FREE(a->data);
- FREE(a);
+ if (ctx->FragmentProgram._Current != prev && ctx->Driver.BindProgram) {
+ ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB,
+ (struct gl_program *) ctx->FragmentProgram._Current);
}
}
-