From 5b5c9315275752add1215dba0f86d5f5068d856b Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 7 May 2008 18:51:44 -0600 Subject: [PATCH] fix refcounting bugs in tnl/tex program caches --- src/mesa/main/mtypes.h | 12 +++---- src/mesa/main/texenvprogram.c | 59 ++++++++++++++++++++--------------- src/mesa/shader/program.c | 6 ++-- src/mesa/tnl/t_context.h | 2 +- src/mesa/tnl/t_vp_build.c | 51 +++++++++++++++--------------- 5 files changed, 68 insertions(+), 62 deletions(-) diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 98fab69fd82..001240a14f5 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1544,19 +1544,17 @@ struct gl_texture_unit /*@}*/ }; -struct texenvprog_cache_item { - GLuint hash; - void *key; - struct gl_fragment_program *data; - struct texenvprog_cache_item *next; -}; -struct texenvprog_cache { +struct texenvprog_cache_item; + +struct texenvprog_cache +{ struct texenvprog_cache_item **items; GLuint size, n_items; GLcontext *ctx; }; + /** * Texture attribute group (GL_TEXTURE_BIT). */ diff --git a/src/mesa/main/texenvprogram.c b/src/mesa/main/texenvprogram.c index fb68bf0720e..68a4db91974 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); } diff --git a/src/mesa/shader/program.c b/src/mesa/shader/program.c index 8166e7e935c..39784a14161 100644 --- a/src/mesa/shader/program.c +++ b/src/mesa/shader/program.c @@ -303,7 +303,7 @@ void _mesa_delete_program(GLcontext *ctx, struct gl_program *prog) { (void) ctx; - ASSERT(prog); + ASSERT(prog); assert(prog->RefCount==0); if (prog == &_mesa_DummyProgram) return; @@ -378,7 +378,7 @@ _mesa_reference_program(GLcontext *ctx, GLboolean deleteFlag; /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/ -#if 0 +#if 01 printf("Program %p %u 0x%x Refcount-- to %d\n", *ptr, (*ptr)->Id, (*ptr)->Target, (*ptr)->RefCount - 1); #endif @@ -400,7 +400,7 @@ _mesa_reference_program(GLcontext *ctx, if (prog) { /*_glthread_LOCK_MUTEX(prog->Mutex);*/ prog->RefCount++; -#if 0 +#if 01 printf("Program %p %u 0x%x Refcount++ to %d\n", prog, prog->Id, prog->Target, prog->RefCount); #endif diff --git a/src/mesa/tnl/t_context.h b/src/mesa/tnl/t_context.h index baf283ef0f6..1ac508f0330 100644 --- a/src/mesa/tnl/t_context.h +++ b/src/mesa/tnl/t_context.h @@ -388,7 +388,7 @@ struct tnl_clipspace struct tnl_cache_item { GLuint hash; void *key; - void *data; + struct gl_vertex_program *prog; struct tnl_cache_item *next; }; diff --git a/src/mesa/tnl/t_vp_build.c b/src/mesa/tnl/t_vp_build.c index f254a4d7a4d..2b1eefe8098 100644 --- a/src/mesa/tnl/t_vp_build.c +++ b/src/mesa/tnl/t_vp_build.c @@ -1464,21 +1464,22 @@ create_new_program( const struct state_key *key, build_tnl_program( &p ); } -static void *search_cache( struct tnl_cache *cache, - GLuint hash, - const void *key, - GLuint keysize) + +static struct gl_vertex_program * +search_cache(struct tnl_cache *cache, GLuint hash, + const void *key, GLuint keysize) { struct tnl_cache_item *c; for (c = cache->items[hash % cache->size]; c; c = c->next) { if (c->hash == hash && _mesa_memcmp(c->key, key, keysize) == 0) - return c->data; + return c->prog; } return NULL; } + static void rehash( struct tnl_cache *cache ) { struct tnl_cache_item **items; @@ -1501,15 +1502,16 @@ static void rehash( struct tnl_cache *cache ) cache->size = size; } -static void cache_item( struct tnl_cache *cache, +static void cache_item( GLcontext *ctx, + struct tnl_cache *cache, GLuint hash, void *key, - void *data ) + struct gl_vertex_program *prog ) { - struct tnl_cache_item *c = (struct tnl_cache_item*) _mesa_malloc(sizeof(*c)); + struct tnl_cache_item *c = CALLOC_STRUCT(tnl_cache_item); c->hash = hash; c->key = key; - c->data = data; + _mesa_reference_vertprog(ctx, &c->prog, prog); if (++cache->n_items > cache->size * 1.5) rehash(cache); @@ -1540,6 +1542,8 @@ void _tnl_UpdateFixedFunctionProgram( GLcontext *ctx ) if (!ctx->VertexProgram._Current || ctx->VertexProgram._Current == ctx->VertexProgram._TnlProgram) { + struct gl_vertex_program *newProg; + /* Grab all the relevent state and put it in a single structure: */ key = make_state_key(ctx); @@ -1547,34 +1551,31 @@ void _tnl_UpdateFixedFunctionProgram( GLcontext *ctx ) /* Look for an already-prepared program for this state: */ - ctx->VertexProgram._TnlProgram = (struct gl_vertex_program *) - search_cache( tnl->vp_cache, hash, key, sizeof(*key) ); + newProg = search_cache( tnl->vp_cache, hash, key, sizeof(*key)); /* OK, we'll have to build a new one: */ - if (!ctx->VertexProgram._TnlProgram) { + if (!newProg) { + if (0) _mesa_printf("Build new TNL program\n"); - ctx->VertexProgram._TnlProgram = (struct gl_vertex_program *) + newProg = (struct gl_vertex_program *) ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0); - create_new_program( key, ctx->VertexProgram._TnlProgram, - ctx->Const.VertexProgram.MaxTemps ); + create_new_program( key, newProg, ctx->Const.VertexProgram.MaxTemps ); if (ctx->Driver.ProgramStringNotify) ctx->Driver.ProgramStringNotify( ctx, GL_VERTEX_PROGRAM_ARB, - &ctx->VertexProgram._TnlProgram->Base ); + &newProg->Base ); - cache_item(tnl->vp_cache, hash, key, ctx->VertexProgram._TnlProgram ); - } - else { - FREE(key); - if (0) - _mesa_printf("Found existing TNL program for key %x\n", hash); + cache_item(ctx, tnl->vp_cache, hash, key, newProg); + + _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram, newProg); } - _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, - ctx->VertexProgram._TnlProgram); + + _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram, newProg); + _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, newProg); } /* Tell the driver about the change. Could define a new target for @@ -1607,7 +1608,7 @@ void _tnl_ProgramCacheDestroy( GLcontext *ctx ) for (c = tnl->vp_cache->items[i]; c; c = next) { next = c->next; FREE(c->key); - FREE(c->data); + _mesa_reference_vertprog(ctx, &c->prog, NULL); FREE(c); } -- 2.30.2