summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Paul <[email protected]>2008-05-07 18:51:44 -0600
committerBrian Paul <[email protected]>2008-05-07 18:51:44 -0600
commit5b5c9315275752add1215dba0f86d5f5068d856b (patch)
tree90dec078e7417a98ae9be307ee5fb8f6a3705bff
parent12a317b93a635a623a8d0b9d0cb200ba8b3ae98b (diff)
fix refcounting bugs in tnl/tex program caches
-rw-r--r--src/mesa/main/mtypes.h12
-rw-r--r--src/mesa/main/texenvprogram.c59
-rw-r--r--src/mesa/shader/program.c6
-rw-r--r--src/mesa/tnl/t_context.h2
-rw-r--r--src/mesa/tnl/t_vp_build.c51
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);
}