From 9e4bae9ccac5a76a2361c5c3cbe377a3c6b6a95b Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 20 Dec 2006 09:27:42 -0700 Subject: [PATCH] Fix shader object reference counting and hash table deallocation. --- src/mesa/main/context.c | 26 ++++++++------ src/mesa/main/mtypes.h | 20 ++++++----- src/mesa/main/shaders.h | 5 --- src/mesa/shader/shader_api.c | 69 ++++++++++++++++++++++++++++++++---- src/mesa/shader/shader_api.h | 5 ++- 5 files changed, 94 insertions(+), 31 deletions(-) diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index 2196591ba26..0e2a7804769 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -131,7 +131,7 @@ #include "math/m_xform.h" #include "math/mathmod.h" #endif -#include "shaders.h" +#include "shader_api.h" #ifdef USE_SPARC_ASM #include "sparc/sparc.h" @@ -877,13 +877,22 @@ delete_arrayobj_cb(GLuint id, void *data, void *userData) } /** - * Callback for deleting an shader object. Called by _mesa_HashDeleteAll(). + * Callback for deleting shader and shader programs objects. + * Called by _mesa_HashDeleteAll(). */ static void -delete_shaderobj_cb(GLuint id, void *data, void *userData) +delete_shader_cb(GLuint id, void *data, void *userData) { - /* XXX probably need to fix this */ - _mesa_free(data); + GLcontext *ctx = (GLcontext *) userData; + struct gl_shader *sh = (struct gl_shader *) data; + if (sh->Type == GL_FRAGMENT_SHADER || sh->Type == GL_VERTEX_SHADER) { + _mesa_free_shader(ctx, sh); + } + else { + struct gl_shader_program *shProg = (struct gl_shader_program *) data; + ASSERT(shProg->Type == GL_SHADER_PROGRAM); + _mesa_free_shader_program(ctx, shProg); + } } @@ -948,11 +957,8 @@ free_shared_state( GLcontext *ctx, struct gl_shared_state *ss ) _mesa_DeleteHashTable(ss->ArrayObjects); #if FEATURE_ARB_shader_objects - /* XXX SLANG TO-DO */ - /* - struct _mesa_HashTable *ShaderObjects; - struct _mesa_HashTable *ProgramObjects; - */ + _mesa_HashDeleteAll(ss->ShaderObjects, delete_shader_cb, ctx); + _mesa_DeleteHashTable(ss->ShaderObjects); #endif #if FEATURE_EXT_framebuffer_object diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 57f174a7d47..e73c625a825 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2049,16 +2049,17 @@ struct gl_query_state /** - * A GLSL shader object + * A GLSL shader object. */ struct gl_shader { GLenum Type; /**< GL_FRAGMENT_SHADER || GL_VERTEX_SHADER (first field!) */ GLuint Name; /**< AKA the handle */ - GLint RefCount; + GLint RefCount; /**< Reference count */ + GLboolean DeletePending; + const GLchar *Source; /**< Source code string */ GLboolean CompileStatus; - GLboolean DeletePending; GLuint NumPrograms; /**< size of Programs[] array */ struct gl_program **Programs; /**< Post-compile assembly code */ GLchar *InfoLog; @@ -2066,15 +2067,19 @@ struct gl_shader /** - * This corresponds to a GLSL "program" and is basically a linked collection - * of "shaders". + * A GLSL program object. Basically a linked collection of "shaders". */ struct gl_shader_program { GLenum Type; /**< Always GL_SHADER_PROGRAM (internal token) */ GLuint Name; /**< aka handle or ID */ - GLuint NumShaders; /**< total number of shaders in this program */ - struct gl_shader **Shaders; /**< List of the shaders */ + GLint RefCount; /**< Reference count */ + GLboolean DeletePending; + + GLuint NumShaders; /**< number of attached shaders */ + struct gl_shader **Shaders; /**< List of attached the shaders */ + + /* post-link info: */ struct gl_vertex_program *VertexProgram; /**< Linked vertex program */ struct gl_fragment_program *FragmentProgram; /**< Linked fragment prog */ struct gl_program_parameter_list *Uniforms; /**< Plus constants, etc */ @@ -2082,7 +2087,6 @@ struct gl_shader_program struct gl_program_parameter_list *Attributes; /**< Vertex attributes */ GLboolean LinkStatus; /**< GL_LINK_STATUS */ GLboolean Validated; - GLboolean DeletePending; GLchar *InfoLog; }; diff --git a/src/mesa/main/shaders.h b/src/mesa/main/shaders.h index a098c4c3315..17339ccf623 100644 --- a/src/mesa/main/shaders.h +++ b/src/mesa/main/shaders.h @@ -233,9 +233,4 @@ _mesa_UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -/*** XXXX temporary here ! */ -extern void -_mesa_init_shader_state(GLcontext *ctx); - - #endif /* SHADERS_H */ diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c index e49feea3d86..2d1056e6674 100644 --- a/src/mesa/shader/shader_api.c +++ b/src/mesa/shader/shader_api.c @@ -126,6 +126,15 @@ _mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index, return; } + if (!name) + return; + + if (strncmp(name, "gl_", 3) == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindAttribLocation(illegal name)"); + return; + } + #if 0 /* XXXX */ if (name == NULL || index >= MAX_VERTEX_ATTRIBS) _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocationARB"); @@ -188,20 +197,32 @@ _mesa_delete_program2(GLcontext *ctx, GLuint name) return; } - /* XXX refcounting! */ + /* always remove from hash table */ _mesa_HashRemove(ctx->Shared->ShaderObjects, name); - _mesa_delete_shader_program(ctx, shProg); + + shProg->DeletePending = GL_TRUE; + + /* decrement refcount, delete if zero */ + shProg->RefCount--; + if (shProg->RefCount <= 0) { + _mesa_free_shader_program(ctx, shProg); + } } void _mesa_delete_shader(GLcontext *ctx, GLuint shader) { - /* XXX refcounting! */ + struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); + if (!sh) { + return; + } - /* - _mesa_DeleteObjectARB(shader); - */ + sh->DeletePending = GL_TRUE; + sh->RefCount--; + if (sh->RefCount <= 0) { + _mesa_free_shader(ctx, sh); + } } @@ -223,6 +244,9 @@ _mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader) if (shProg->Shaders[i]->Name == shader) { struct gl_shader **newList; /* found it */ + + shProg->Shaders[i]->RefCount--; + /* alloc new, smaller array */ newList = (struct gl_shader **) _mesa_malloc((n - 1) * sizeof(struct gl_shader *)); @@ -602,6 +626,7 @@ _mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source) _mesa_free((void *) sh->Source); } sh->Source = source; + sh->CompileStatus = GL_FALSE; } @@ -667,6 +692,15 @@ _mesa_link_program(GLcontext *ctx, GLuint program) void _mesa_use_program(GLcontext *ctx, GLuint program) { + /* unbind old */ + if (ctx->Shader.CurrentProgram) { + ctx->Shader.CurrentProgram->RefCount--; + if (ctx->Shader.CurrentProgram->RefCount <= 0) { + _mesa_free_shader_program(ctx, ctx->Shader.CurrentProgram); + } + ctx->Shader.CurrentProgram = NULL; + } + /* XXXX need to handle reference counting here! */ if (program) { struct gl_shader_program *shProg; @@ -677,6 +711,7 @@ _mesa_use_program(GLcontext *ctx, GLuint program) return; } ctx->Shader.CurrentProgram = shProg; + shProg->RefCount++; } else { /* don't use a shader program */ @@ -817,6 +852,7 @@ _mesa_new_shader_program(GLcontext *ctx, GLuint name) if (shProg) { shProg->Type = GL_SHADER_PROGRAM; shProg->Name = name; + shProg->RefCount = 1; } return shProg; } @@ -861,7 +897,7 @@ _mesa_free_shader_program_data(GLcontext *ctx, void -_mesa_delete_shader_program(GLcontext *ctx, struct gl_shader_program *shProg) +_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg) { _mesa_free_shader_program_data(ctx, shProg); _mesa_free(shProg); @@ -903,11 +939,30 @@ _mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type) if (shader) { shader->Type = type; shader->Name = name; + shader->RefCount = 1; } return shader; } +void +_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh) +{ + GLuint i; + if (sh->Source) + _mesa_free((void *) sh->Source); + if (sh->InfoLog) + _mesa_free(sh->InfoLog); + for (i = 0; i < sh->NumPrograms; i++) { + assert(sh->Programs[i]); + _mesa_delete_program(ctx, sh->Programs[i]); + } + if (sh->Programs) + _mesa_free(sh->Programs); + _mesa_free(sh); +} + + /** * Lookup a GLSL shader object. */ diff --git a/src/mesa/shader/shader_api.h b/src/mesa/shader/shader_api.h index 2f73bb88871..315f60a35f7 100644 --- a/src/mesa/shader/shader_api.h +++ b/src/mesa/shader/shader_api.h @@ -46,7 +46,7 @@ _mesa_free_shader_program_data(GLcontext *ctx, struct gl_shader_program *shProg); extern void -_mesa_delete_shader_program(GLcontext *ctx, struct gl_shader_program *shProg); +_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg); extern struct gl_shader_program * _mesa_lookup_shader_program(GLcontext *ctx, GLuint name); @@ -55,6 +55,9 @@ _mesa_lookup_shader_program(GLcontext *ctx, GLuint name); extern struct gl_shader * _mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type); +extern void +_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh); + extern struct gl_shader * _mesa_lookup_shader(GLcontext *ctx, GLuint name); -- 2.30.2