diff options
author | Kenneth Graunke <[email protected]> | 2013-05-20 23:46:16 -0700 |
---|---|---|
committer | Jordan Justen <[email protected]> | 2013-05-23 09:37:12 -0700 |
commit | 3ddfccb303c571f83de7a0743021eda922c5c8a1 (patch) | |
tree | 47ea40b338cf8c2686748aedfcdebe994d5ff9ff | |
parent | 4a0bcd90cff6701aaf08d9bbcf6144b18c2d8284 (diff) |
glsl linker: compare interface blocks during interstage linking
Verify that interface blocks match when linking separate shader
stages into a program.
Fixes piglit glsl-1.50 tests:
* linker/interface-blocks-vs-fs-member-count-mismatch.shader_test
* linker/interface-blocks-vs-fs-member-order-mismatch.shader_test
Signed-off-by: Kenneth Graunke <[email protected]>
Signed-off-by: Jordan Justen <[email protected]>
-rw-r--r-- | src/glsl/link_interface_blocks.cpp | 39 | ||||
-rw-r--r-- | src/glsl/linker.cpp | 6 | ||||
-rw-r--r-- | src/glsl/linker.h | 4 |
3 files changed, 49 insertions, 0 deletions
diff --git a/src/glsl/link_interface_blocks.cpp b/src/glsl/link_interface_blocks.cpp index 4a4c5a14c72..b91860d0394 100644 --- a/src/glsl/link_interface_blocks.cpp +++ b/src/glsl/link_interface_blocks.cpp @@ -69,3 +69,42 @@ validate_intrastage_interface_blocks(const gl_shader **shader_list, return true; } + +bool +validate_interstage_interface_blocks(const gl_shader *producer, + const gl_shader *consumer) +{ + glsl_symbol_table interfaces; + + /* Add non-output interfaces from the consumer to the symbol table. */ + foreach_list(node, consumer->ir) { + ir_variable *var = ((ir_instruction *) node)->as_variable(); + if (!var || !var->interface_type || var->mode == ir_var_shader_out) + continue; + + interfaces.add_interface(var->interface_type->name, + var->interface_type, + (enum ir_variable_mode) var->mode); + } + + /* Verify that the producer's interfaces match. */ + foreach_list(node, producer->ir) { + ir_variable *var = ((ir_instruction *) node)->as_variable(); + if (!var || !var->interface_type || var->mode == ir_var_shader_in) + continue; + + enum ir_variable_mode consumer_mode = + var->mode == ir_var_uniform ? ir_var_uniform : ir_var_shader_in; + const glsl_type *expected_type = + interfaces.get_interface(var->interface_type->name, consumer_mode); + + /* The consumer doesn't use this output block. Ignore it. */ + if (expected_type == NULL) + continue; + + if (var->interface_type != expected_type) + return false; + } + + return true; +} diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 9a2243a4812..982fe46bd73 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -1728,6 +1728,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) if (prog->_LinkedShaders[i] == NULL) continue; + if (!validate_interstage_interface_blocks(prog->_LinkedShaders[prev], + prog->_LinkedShaders[i])) { + linker_error(prog, "interface block mismatch between shader stages\n"); + goto done; + } + if (!cross_validate_outputs_to_inputs(prog, prog->_LinkedShaders[prev], prog->_LinkedShaders[i])) diff --git a/src/glsl/linker.h b/src/glsl/linker.h index 936a1433359..2fe2410c220 100644 --- a/src/glsl/linker.h +++ b/src/glsl/linker.h @@ -64,6 +64,10 @@ bool validate_intrastage_interface_blocks(const gl_shader **shader_list, unsigned num_shaders); +bool +validate_interstage_interface_blocks(const gl_shader *producer, + const gl_shader *consumer); + /** * Class for processing all of the leaf fields of a variable that corresponds * to a program resource. |