aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenneth Graunke <[email protected]>2013-05-20 23:46:16 -0700
committerJordan Justen <[email protected]>2013-05-23 09:37:12 -0700
commit3ddfccb303c571f83de7a0743021eda922c5c8a1 (patch)
tree47ea40b338cf8c2686748aedfcdebe994d5ff9ff
parent4a0bcd90cff6701aaf08d9bbcf6144b18c2d8284 (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.cpp39
-rw-r--r--src/glsl/linker.cpp6
-rw-r--r--src/glsl/linker.h4
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.