glsl linker: compare interface blocks during interstage linking
authorKenneth Graunke <kenneth@whitecape.org>
Tue, 21 May 2013 06:46:16 +0000 (23:46 -0700)
committerJordan Justen <jordan.l.justen@intel.com>
Thu, 23 May 2013 16:37:12 +0000 (09:37 -0700)
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 <kenneth@whitecape.org>
Signed-off-by: Jordan Justen <jordan.l.justen@intel.com>
src/glsl/link_interface_blocks.cpp
src/glsl/linker.cpp
src/glsl/linker.h

index 4a4c5a14c7256e4d9b80c11dbb4314199974a4f9..b91860d039453502b0e1b82f8a70a4de7066104a 100644 (file)
@@ -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;
+}
index 9a2243a48129fc6f9ac6f46be142e369fe68203b..982fe46bd73b07112610c3cbabcc87b476bca45f 100644 (file)
@@ -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]))
index 936a1433359ac9a81ddb167f319142d6ef067ca4..2fe2410c220f18e9bdd2ee17b327f1a75a4fa595 100644 (file)
@@ -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.