summaryrefslogtreecommitdiffstats
path: root/src/glsl
diff options
context:
space:
mode:
authorEric Anholt <[email protected]>2012-04-27 13:52:56 -0700
committerEric Anholt <[email protected]>2012-07-20 10:43:28 -0700
commitf609cf782ab5e90ddf045dc4b0da8cebf99be0d1 (patch)
tree7f54da76e408a733a9bb82e8242ada78fb6063f4 /src/glsl
parentb3c093c79c2ec49c36af37aa290d5ae452149f6e (diff)
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 <[email protected]>
Diffstat (limited to 'src/glsl')
-rw-r--r--src/glsl/link_uniforms.cpp61
-rw-r--r--src/glsl/linker.cpp82
-rw-r--r--src/glsl/linker.h6
3 files changed, 145 insertions, 4 deletions
diff --git a/src/glsl/link_uniforms.cpp b/src/glsl/link_uniforms.cpp
index 92e2a1fa548..dddac43c316 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 f06298cf6e9..7fbd834ab66 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 d0aaf3e1e7d..5c54437a9ea 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
*