diff options
Diffstat (limited to 'src/glsl')
-rw-r--r-- | src/glsl/link_uniforms.cpp | 61 | ||||
-rw-r--r-- | src/glsl/linker.cpp | 82 | ||||
-rw-r--r-- | src/glsl/linker.h | 6 |
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 * |