From 3ddfccb303c571f83de7a0743021eda922c5c8a1 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Mon, 20 May 2013 23:46:16 -0700 Subject: [PATCH] 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 Signed-off-by: Jordan Justen --- src/glsl/link_interface_blocks.cpp | 39 ++++++++++++++++++++++++++++++ src/glsl/linker.cpp | 6 +++++ src/glsl/linker.h | 4 +++ 3 files changed, 49 insertions(+) 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. -- 2.30.2