* 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];
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
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 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,
{
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;
- if (++cache->n_items > cache->size * 1.5)
- rehash(cache);
+ 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;
}
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;
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));
+ 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);
(struct 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);
}
}
void _mesa_TexEnvProgramCacheInit( GLcontext *ctx )
{
+ 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 **)
void _mesa_TexEnvProgramCacheDestroy( GLcontext *ctx )
{
- struct texenvprog_cache_item *c, *next;
- GLuint i;
-
- for (i = 0; i < ctx->Texture.env_fp_cache.size; i++)
- for (c = ctx->Texture.env_fp_cache.items[i]; c; c = next) {
- next = c->next;
- _mesa_free(c->key);
- _mesa_free(c->data);
- _mesa_free(c);
- }
-
+ clear_cache(&ctx->Texture.env_fp_cache);
_mesa_free(ctx->Texture.env_fp_cache.items);
}