Mesa (master): glsl: Merge the lists of uniform blocks into the linked shader program.

Eric Anholt anholt at kemper.freedesktop.org
Fri Jul 20 17:50:58 UTC 2012


Module: Mesa
Branch: master
Commit: f609cf782ab5e90ddf045dc4b0da8cebf99be0d1
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=f609cf782ab5e90ddf045dc4b0da8cebf99be0d1

Author: Eric Anholt <eric at anholt.net>
Date:   Fri Apr 27 13:52:56 2012 -0700

glsl: Merge the lists of uniform blocks into the linked shader program.

This attempts error-checking, but the layout isn't done yet.

Reviewed-by: Ian Romanick <ian.d.romanick at intel.com>

---

 src/glsl/link_uniforms.cpp      |   61 +++++++++++++++++++++++++++++
 src/glsl/linker.cpp             |   82 +++++++++++++++++++++++++++++++++++++--
 src/glsl/linker.h               |    6 +++
 src/mesa/main/mtypes.h          |   34 ++++++++++++++++
 src/mesa/program/ir_to_mesa.cpp |    6 +++
 5 files changed, 185 insertions(+), 4 deletions(-)

diff --git a/src/glsl/link_uniforms.cpp b/src/glsl/link_uniforms.cpp
index 92e2a1f..dddac43 100644
--- a/src/glsl/link_uniforms.cpp
+++ b/src/glsl/link_uniforms.cpp
@@ -316,6 +316,67 @@ public:
    unsigned shader_shadow_samplers;
 };
 
+/**
+ * Merges a uniform block into an array of uniform blocks that may or
+ * may not already contain a copy of it.
+ *
+ * Returns the index of the new block in the array.
+ */
+int
+link_cross_validate_uniform_block(void *mem_ctx,
+				  struct gl_uniform_block **linked_blocks,
+				  unsigned int *num_linked_blocks,
+				  struct gl_uniform_block *new_block)
+{
+   for (unsigned int i = 0; i < *num_linked_blocks; i++) {
+      struct gl_uniform_block *old_block = &(*linked_blocks)[i];
+      if (strcmp(old_block->Name, new_block->Name) == 0) {
+	 if (old_block->NumUniforms != new_block->NumUniforms) {
+	    return -1;
+	 }
+
+	 for (unsigned j = 0; j < old_block->NumUniforms; j++) {
+	    if (strcmp(old_block->Uniforms[j].Name,
+		       new_block->Uniforms[j].Name) != 0)
+	       return -1;
+
+	    if (old_block->Uniforms[j].Offset !=
+		new_block->Uniforms[j].Offset)
+	       return -1;
+
+	    if (old_block->Uniforms[j].RowMajor !=
+		new_block->Uniforms[j].RowMajor)
+	       return -1;
+	 }
+	 return i;
+      }
+   }
+
+   *linked_blocks = reralloc(mem_ctx, *linked_blocks,
+			     struct gl_uniform_block,
+			     *num_linked_blocks + 1);
+   int linked_block_index = (*num_linked_blocks)++;
+   struct gl_uniform_block *linked_block = &(*linked_blocks)[linked_block_index];
+
+   memcpy(linked_block, new_block, sizeof(*new_block));
+   linked_block->Uniforms = ralloc_array(*linked_blocks,
+					 struct gl_uniform_buffer_variable,
+					 linked_block->NumUniforms);
+
+   memcpy(linked_block->Uniforms,
+	  new_block->Uniforms,
+	  sizeof(*linked_block->Uniforms) * linked_block->NumUniforms);
+
+   for (unsigned int i = 0; i < linked_block->NumUniforms; i++) {
+      struct gl_uniform_buffer_variable *ubo_var =
+	 &linked_block->Uniforms[i];
+
+      ubo_var->Name = ralloc_strdup(*linked_blocks, ubo_var->Name);
+   }
+
+   return linked_block_index;
+}
+
 void
 link_assign_uniform_locations(struct gl_shader_program *prog)
 {
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index f06298c..7fbd834 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -581,6 +581,48 @@ cross_validate_uniforms(struct gl_shader_program *prog)
 				 MESA_SHADER_TYPES, true);
 }
 
+/**
+ * Accumulates the array of prog->UniformBlocks and checks that all
+ * definitons of blocks agree on their contents.
+ */
+static bool
+interstage_cross_validate_uniform_blocks(struct gl_shader_program *prog)
+{
+   unsigned max_num_uniform_blocks = 0;
+   for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+      if (prog->_LinkedShaders[i])
+	 max_num_uniform_blocks += prog->_LinkedShaders[i]->NumUniformBlocks;
+   }
+
+   for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+      struct gl_shader *sh = prog->_LinkedShaders[i];
+
+      prog->UniformBlockStageIndex[i] = ralloc_array(prog, int,
+						     max_num_uniform_blocks);
+      for (unsigned int j = 0; j < max_num_uniform_blocks; j++)
+	 prog->UniformBlockStageIndex[i][j] = -1;
+
+      if (sh == NULL)
+	 continue;
+
+      for (unsigned int j = 0; j < sh->NumUniformBlocks; j++) {
+	 int index = link_cross_validate_uniform_block(prog,
+						       &prog->UniformBlocks,
+						       &prog->NumUniformBlocks,
+						       &sh->UniformBlocks[j]);
+
+	 if (index == -1) {
+	    linker_error(prog, "uniform block `%s' has mismatching definitions",
+			 sh->UniformBlocks[j].Name);
+	    return false;
+	 }
+
+	 prog->UniformBlockStageIndex[i][index] = j;
+      }
+   }
+
+   return true;
+}
 
 /**
  * Validate that outputs from one stage match inputs of another
@@ -910,7 +952,6 @@ public:
    }
 };
 
-
 /**
  * Combine a group of shaders for a single stage to generate a linked shader
  *
@@ -925,11 +966,31 @@ link_intrastage_shaders(void *mem_ctx,
 			struct gl_shader **shader_list,
 			unsigned num_shaders)
 {
+   struct gl_uniform_block *uniform_blocks = NULL;
+   unsigned num_uniform_blocks = 0;
+
    /* Check that global variables defined in multiple shaders are consistent.
     */
    if (!cross_validate_globals(prog, shader_list, num_shaders, false))
       return NULL;
 
+   /* Check that uniform blocks between shaders for a stage agree. */
+   for (unsigned i = 0; i < num_shaders; i++) {
+      struct gl_shader *sh = shader_list[i];
+
+      for (unsigned j = 0; j < shader_list[i]->NumUniformBlocks; j++) {
+	 int index = link_cross_validate_uniform_block(mem_ctx,
+						       &uniform_blocks,
+						       &num_uniform_blocks,
+						       &sh->UniformBlocks[j]);
+	 if (index == -1) {
+	    linker_error(prog, "uniform block `%s' has mismatching definitions",
+			 sh->UniformBlocks[j].Name);
+	    return NULL;
+	 }
+      }
+   }
+
    /* Check that there is only a single definition of each function signature
     * across all shaders.
     */
@@ -997,6 +1058,10 @@ link_intrastage_shaders(void *mem_ctx,
    linked->ir = new(linked) exec_list;
    clone_ir_list(mem_ctx, linked->ir, main->ir);
 
+   linked->UniformBlocks = uniform_blocks;
+   linked->NumUniformBlocks = num_uniform_blocks;
+   ralloc_steal(linked, linked->UniformBlocks);
+
    populate_symbol_table(linked);
 
    /* The a pointer to the main function in the final linked shader (i.e., the
@@ -2289,11 +2354,17 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
    prog->Validated = false;
    prog->_Used = false;
 
-   if (prog->InfoLog != NULL)
-      ralloc_free(prog->InfoLog);
-
+   ralloc_free(prog->InfoLog);
    prog->InfoLog = ralloc_strdup(NULL, "");
 
+   ralloc_free(prog->UniformBlocks);
+   prog->UniformBlocks = NULL;
+   prog->NumUniformBlocks = 0;
+   for (int i = 0; i < MESA_SHADER_TYPES; i++) {
+      ralloc_free(prog->UniformBlockStageIndex[i]);
+      prog->UniformBlockStageIndex[i] = NULL;
+   }
+
    /* Separate the shaders into groups based on their type.
     */
    struct gl_shader **vert_shader_list;
@@ -2422,6 +2493,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
       }
    }
 
+   if (!interstage_cross_validate_uniform_blocks(prog))
+      goto done;
+
    /* Do common optimization before assigning storage for attributes,
     * uniforms, and varyings.  Later optimization could possibly make
     * some of that unused.
diff --git a/src/glsl/linker.h b/src/glsl/linker.h
index d0aaf3e..5c54437 100644
--- a/src/glsl/linker.h
+++ b/src/glsl/linker.h
@@ -40,6 +40,12 @@ link_assign_uniform_locations(struct gl_shader_program *prog);
 extern void
 link_set_uniform_initializers(struct gl_shader_program *prog);
 
+extern int
+link_cross_validate_uniform_block(void *mem_ctx,
+				  struct gl_uniform_block **linked_blocks,
+				  unsigned int *num_linked_blocks,
+				  struct gl_uniform_block *new_block);
+
 /**
  * Class for processing all of the leaf fields of an uniform
  *
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index b39a8dc..3d59dc6 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -2216,6 +2216,15 @@ struct gl_shader
     */
    unsigned num_uniform_components;
 
+   /**
+    * This shader's uniform block information.
+    *
+    * The offsets of the variables are assigned only for shaders in a program's
+    * _LinkedShaders[].
+    */
+   struct gl_uniform_block *UniformBlocks;
+   unsigned NumUniformBlocks;
+
    struct exec_list *ir;
    struct glsl_symbol_table *symbols;
 
@@ -2254,6 +2263,19 @@ struct gl_uniform_block
    /** Array of supplemental information about UBO ir_variables. */
    struct gl_uniform_buffer_variable *Uniforms;
    GLuint NumUniforms;
+
+   /**
+    * Index (GL_UNIFORM_BLOCK_BINDING) into ctx->UniformBufferBindings[] to use
+    * with glBindBufferBase to bind a buffer object to this uniform block.  When
+    * updated in the program, _NEW_BUFFER_OBJECT will be set.
+    */
+   GLuint Binding;
+
+   /**
+    * Minimum size of a buffer object to back this uniform buffer
+    * (GL_UNIFORM_BLOCK_DATA_SIZE).
+    */
+   GLuint UniformBufferSize;
 };
 
 /**
@@ -2338,6 +2360,18 @@ struct gl_shader_program
    unsigned NumUserUniformStorage;
    struct gl_uniform_storage *UniformStorage;
 
+   struct gl_uniform_block *UniformBlocks;
+   unsigned NumUniformBlocks;
+
+   /**
+    * Indices into the _LinkedShaders's UniformBlocks[] array for each stage
+    * they're used in, or -1.
+    *
+    * This is used to maintain the Binding values of the stage's UniformBlocks[]
+    * and to answer the GL_UNIFORM_BLOCK_REFERENCED_BY_*_SHADER queries.
+    */
+   int *UniformBlockStageIndex[MESA_SHADER_TYPES];
+
    /**
     * Map of active uniform names to locations
     *
diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp
index 8a4f311..baa3172 100644
--- a/src/mesa/program/ir_to_mesa.cpp
+++ b/src/mesa/program/ir_to_mesa.cpp
@@ -3115,6 +3115,12 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader)
       }
    }
 
+   if (shader->UniformBlocks)
+      ralloc_free(shader->UniformBlocks);
+   shader->NumUniformBlocks = state->num_uniform_blocks;
+   shader->UniformBlocks = state->uniform_blocks;
+   ralloc_steal(shader, shader->UniformBlocks);
+
    /* Retain any live IR, but trash the rest. */
    reparent_ir(shader->ir, shader->ir);
 




More information about the mesa-commit mailing list