Browse Source

fix refcounting bugs in tnl/tex program caches

tags/mesa_7_1_rc1
Brian Paul 18 years ago
parent
commit
5b5c931527

+ 5
- 7
src/mesa/main/mtypes.h View File

@@ -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).
*/

+ 33
- 26
src/mesa/main/texenvprogram.c View File

@@ -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);
}

+ 3
- 3
src/mesa/shader/program.c View File

@@ -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

+ 1
- 1
src/mesa/tnl/t_context.h View File

@@ -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;
};


+ 26
- 25
src/mesa/tnl/t_vp_build.c View File

@@ -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);
}


Loading…
Cancel
Save