Fix shader object reference counting and hash table deallocation.
authorBrian <brian@yutani.localnet.net>
Wed, 20 Dec 2006 16:27:42 +0000 (09:27 -0700)
committerBrian <brian@yutani.localnet.net>
Wed, 20 Dec 2006 16:27:42 +0000 (09:27 -0700)
src/mesa/main/context.c
src/mesa/main/mtypes.h
src/mesa/main/shaders.h
src/mesa/shader/shader_api.c
src/mesa/shader/shader_api.h

index 2196591ba26569baa5c5f65f6f342c6f86386500..0e2a780476967d40222c929f5ffa2220caac6a73 100644 (file)
 #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
index 57f174a7d47b8995c1aed50a0235483b569f6f11..e73c625a825bb36c18ab33a3bed0b92cf83519e5 100644 (file)
@@ -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;
 };   
 
index a098c4c3315621be757145d0d067d4e967920cf5..17339ccf623d0f2d8c2f683c15c1a30390ed1351 100644 (file)
@@ -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 */
index e49feea3d86eb5338cfe99020c4b1911ade6651a..2d1056e667426101eff446e6ee6ced84d08cdf58 100644 (file)
@@ -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.
  */
index 2f73bb8887147ca90e65b98640264f8787737e25..315f60a35f7ba832ab2f50586419cafff9da2dce 100644 (file)
@@ -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);