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