diff options
Diffstat (limited to 'src/glsl/linker.cpp')
-rw-r--r-- | src/glsl/linker.cpp | 82 |
1 files changed, 78 insertions, 4 deletions
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. |