* Examine current texture environment state and generate a unique
* key to identify it.
*/
-static struct state_key *
-make_state_key(GLcontext *ctx)
+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,
/* 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;
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 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;
}
GLuint unit,
GLuint nr,
GLuint mode,
- struct mode_opt *opt)
+ const struct mode_opt *opt)
{
struct ureg src[3];
struct ureg tmp, half;
* 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;
/* 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 );
+ 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;
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)
+ struct gl_fragment_program *program)
{
struct texenv_fragment_program p;
GLuint unit;
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);
*/
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:
}
-static void *search_cache( struct texenvprog_cache *cache,
- GLuint hash,
- const void *key,
- GLuint keysize)
+static struct gl_fragment_program *
+search_cache(const struct texenvprog_cache *cache,
+ GLuint hash,
+ const void *key,
+ GLuint keysize)
{
- struct texenvprog_cache *c;
+ struct texenvprog_cache_item *c;
- for (c = cache; c; c = c->next) {
- if (c->hash == hash && _mesa_memcmp(c->key, key, keysize) == 0)
- return c->data;
+ for (c = cache->items[hash % cache->size]; c; c = c->next) {
+ if (c->hash == hash && memcmp(c->key, key, keysize) == 0)
+ return (struct gl_fragment_program *) c->data;
}
return NULL;
}
-static void cache_item( struct texenvprog_cache **cache,
+static void rehash( struct texenvprog_cache *cache )
+{
+ struct texenvprog_cache_item **items;
+ struct texenvprog_cache_item *c, *next;
+ GLuint size, i;
+
+ size = cache->size * 3;
+ items = (struct texenvprog_cache_item**) _mesa_malloc(size * sizeof(*items));
+ _mesa_memset(items, 0, size * sizeof(*items));
+
+ for (i = 0; i < cache->size; i++)
+ for (c = cache->items[i]; c; c = next) {
+ next = c->next;
+ c->next = items[c->hash % size];
+ items[c->hash % size] = c;
+ }
+
+ _mesa_free(cache->items);
+ cache->items = items;
+ cache->size = size;
+}
+
+static void clear_cache( struct texenvprog_cache *cache )
+{
+ struct texenvprog_cache_item *c, *next;
+ GLuint i;
+
+ for (i = 0; i < cache->size; i++) {
+ for (c = cache->items[i]; c; c = next) {
+ next = c->next;
+ _mesa_free(c->key);
+ cache->ctx->Driver.DeleteProgram(cache->ctx,
+ (struct gl_program *) c->data);
+ _mesa_free(c);
+ }
+ cache->items[i] = NULL;
+ }
+
+
+ cache->n_items = 0;
+}
+
+
+static void cache_item( struct texenvprog_cache *cache,
GLuint hash,
- void *key,
+ const struct state_key *key,
void *data )
{
- struct texenvprog_cache *c = CALLOC_STRUCT(texenvprog_cache);
+ struct texenvprog_cache_item *c = MALLOC(sizeof(*c));
c->hash = hash;
- c->key = key;
+
+ c->key = _mesa_malloc(sizeof(*key));
+ memcpy(c->key, key, sizeof(*key));
+
c->data = data;
- c->next = *cache;
- *cache = c;
+
+ if (cache->n_items > cache->size * 1.5) {
+ if (cache->size < 1000)
+ rehash(cache);
+ else
+ clear_cache(cache);
+ }
+
+ cache->n_items++;
+ c->next = cache->items[hash % cache->size];
+ cache->items[hash % cache->size] = c;
}
-static GLuint hash_key( struct state_key *key )
+static GLuint hash_key( const struct state_key *key )
{
GLuint *ikey = (GLuint *)key;
GLuint hash = 0, i;
- /* I'm sure this can be improved on, but speed is important:
+ /* Make a slightly better attempt at a hash function:
*/
- for (i = 0; i < sizeof(*key)/sizeof(GLuint); i++)
- hash ^= ikey[i];
+ for (i = 0; i < sizeof(*key)/sizeof(*ikey); i++)
+ {
+ hash += ikey[i];
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
return hash;
}
void _mesa_UpdateTexEnvProgram( GLcontext *ctx )
{
- struct state_key *key;
+ 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);
+ make_state_key(ctx, &key);
+ hash = hash_key(&key);
- ctx->FragmentProgram._Current = ctx->_TexEnvProgram =
- (struct fragment_program *)
- search_cache(ctx->Texture.env_fp_cache, hash, key, sizeof(*key));
+ ctx->FragmentProgram._Current =
+ ctx->_TexEnvProgram =
+ 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 *)
+ (struct gl_fragment_program *)
ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
- create_new_program(key, ctx, ctx->_TexEnvProgram);
+ create_new_program(&key, ctx, ctx->_TexEnvProgram);
- cache_item(&ctx->Texture.env_fp_cache, hash, key, 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);
}
}
*/
if (ctx->FragmentProgram._Current != prev && ctx->Driver.BindProgram) {
ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB,
- (struct program *) ctx->FragmentProgram._Current);
+ (struct gl_program *) ctx->FragmentProgram._Current);
}
}
-void _mesa_TexEnvProgramCacheDestroy( GLcontext *ctx )
+
+void _mesa_TexEnvProgramCacheInit( GLcontext *ctx )
{
- struct texenvprog_cache *a, *tmp;
+ ctx->Texture.env_fp_cache.ctx = ctx;
+ ctx->Texture.env_fp_cache.size = 17;
+ ctx->Texture.env_fp_cache.n_items = 0;
+ ctx->Texture.env_fp_cache.items = (struct texenvprog_cache_item **)
+ _mesa_calloc(ctx->Texture.env_fp_cache.size *
+ sizeof(struct texenvprog_cache_item));
+}
- 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);
- }
+
+void _mesa_TexEnvProgramCacheDestroy( GLcontext *ctx )
+{
+ clear_cache(&ctx->Texture.env_fp_cache);
+ _mesa_free(ctx->Texture.env_fp_cache.items);
}