* 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
};
static const struct ureg undef = {
- ~0,
+ 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;
}
GLuint unit,
GLuint nr,
GLuint mode,
- struct mode_opt *opt)
+ const struct mode_opt *opt)
{
struct ureg src[3];
struct ureg tmp, half;
*/
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);
}
-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);
}