From 5b5c9315275752add1215dba0f86d5f5068d856b Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 7 May 2008 18:51:44 -0600 Subject: fix refcounting bugs in tnl/tex program caches --- src/mesa/main/texenvprogram.c | 59 ++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 26 deletions(-) (limited to 'src/mesa/main/texenvprogram.c') diff --git a/src/mesa/main/texenvprogram.c b/src/mesa/main/texenvprogram.c index fb68bf0720..68a4db9197 100644 --- a/src/mesa/main/texenvprogram.c +++ b/src/mesa/main/texenvprogram.c @@ -28,12 +28,23 @@ #include "glheader.h" #include "macros.h" #include "enums.h" +#include "shader/program.h" #include "shader/prog_parameter.h" #include "shader/prog_instruction.h" #include "shader/prog_print.h" #include "shader/prog_statevars.h" #include "texenvprogram.h" + +struct texenvprog_cache_item +{ + GLuint hash; + void *key; + struct gl_fragment_program *data; + struct texenvprog_cache_item *next; +}; + + /** * 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), @@ -1133,7 +1144,7 @@ search_cache(const struct texenvprog_cache *cache, 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 c->data; } return NULL; @@ -1161,7 +1172,7 @@ static void rehash( struct texenvprog_cache *cache ) cache->size = size; } -static void clear_cache( struct texenvprog_cache *cache ) +static void clear_cache(GLcontext *ctx, struct texenvprog_cache *cache) { struct texenvprog_cache_item *c, *next; GLuint i; @@ -1170,8 +1181,7 @@ static void clear_cache( struct texenvprog_cache *cache ) 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_reference_fragprog(ctx, &c->data, NULL); _mesa_free(c); } cache->items[i] = NULL; @@ -1182,25 +1192,25 @@ static void clear_cache( struct texenvprog_cache *cache ) } -static void cache_item( struct texenvprog_cache *cache, +static void cache_item( GLcontext *ctx, + struct texenvprog_cache *cache, GLuint hash, const struct state_key *key, - void *data ) + struct gl_fragment_program *prog) { - struct texenvprog_cache_item *c - = (struct texenvprog_cache_item *) MALLOC(sizeof(*c)); + struct texenvprog_cache_item *c = CALLOC_STRUCT(texenvprog_cache_item); c->hash = hash; c->key = _mesa_malloc(sizeof(*key)); memcpy(c->key, key, sizeof(*key)); - c->data = (struct gl_fragment_program *) data; + _mesa_reference_fragprog(ctx, &c->data, prog); if (cache->n_items > cache->size * 1.5) { if (cache->size < 1000) rehash(cache); else - clear_cache(cache); + clear_cache(ctx, cache); } cache->n_items++; @@ -1243,32 +1253,29 @@ _mesa_UpdateTexEnvProgram( GLcontext *ctx ) /* If a conventional fragment program/shader isn't in effect... */ if (!ctx->FragmentProgram._Enabled && (!ctx->Shader.CurrentProgram || !ctx->Shader.CurrentProgram->FragmentProgram)) { + struct gl_fragment_program *newProg; + make_state_key(ctx, &key); hash = hash_key(&key); - ctx->FragmentProgram._Current = - ctx->FragmentProgram._TexEnvProgram = - search_cache(&ctx->Texture.env_fp_cache, hash, &key, sizeof(key)); + newProg = search_cache(&ctx->Texture.env_fp_cache, hash, &key, sizeof(key)); + + if (!newProg) { + /* create new tex env program */ - if (!ctx->FragmentProgram._TexEnvProgram) { if (0) _mesa_printf("Building new texenv proggy for key %x\n", hash); - /* create new tex env program */ - ctx->FragmentProgram._Current = - ctx->FragmentProgram._TexEnvProgram = - (struct gl_fragment_program *) + newProg = (struct gl_fragment_program *) ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); - create_new_program(ctx, &key, ctx->FragmentProgram._TexEnvProgram); + create_new_program(ctx, &key, newProg); - cache_item(&ctx->Texture.env_fp_cache, hash, &key, - ctx->FragmentProgram._TexEnvProgram); - } - else { - if (0) - _mesa_printf("Found existing texenv program for key %x\n", hash); + cache_item(ctx, &ctx->Texture.env_fp_cache, hash, &key, newProg); } + + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, newProg); + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram, newProg); } else { /* _Current pointer has been updated in update_program */ @@ -1298,6 +1305,6 @@ void _mesa_TexEnvProgramCacheInit( GLcontext *ctx ) void _mesa_TexEnvProgramCacheDestroy( GLcontext *ctx ) { - clear_cache(&ctx->Texture.env_fp_cache); + clear_cache(ctx, &ctx->Texture.env_fp_cache); _mesa_free(ctx->Texture.env_fp_cache.items); } -- cgit v1.2.3