mesa: include mtypes.h less
[mesa.git] / src / compiler / glsl / link_interface_blocks.cpp
index 4eda09774efc5d8c78ccff63b942d074314b496c..7c3037e89754567a8da40208764bba9194bd30b9 100644 (file)
 #include "glsl_symbol_table.h"
 #include "linker.h"
 #include "main/macros.h"
+#include "main/mtypes.h"
 #include "util/hash_table.h"
 
 
 namespace {
 
-/**
- * Check if two interfaces match, according to intrastage interface matching
- * rules.  If they do, and the first interface uses an unsized array, it will
- * be updated to reflect the array size declared in the second interface.
- */
-bool
-intrastage_match(ir_variable *a,
-                 ir_variable *b,
-                 struct gl_shader_program *prog)
-{
-   /* Types must match. */
-   if (a->get_interface_type() != b->get_interface_type()) {
-      /* Exception: if both the interface blocks are implicitly declared,
-       * don't force their types to match.  They might mismatch due to the two
-       * shaders using different GLSL versions, and that's ok.
-       */
-      if (a->data.how_declared != ir_var_declared_implicitly ||
-          b->data.how_declared != ir_var_declared_implicitly)
-         return false;
-   }
-
-   /* Presence/absence of interface names must match. */
-   if (a->is_interface_instance() != b->is_interface_instance())
-      return false;
-
-   /* For uniforms, instance names need not match.  For shader ins/outs,
-    * it's not clear from the spec whether they need to match, but
-    * Mesa's implementation relies on them matching.
-    */
-   if (a->is_interface_instance() && b->data.mode != ir_var_uniform &&
-       b->data.mode != ir_var_shader_storage &&
-       strcmp(a->name, b->name) != 0) {
-      return false;
-   }
-
-   /* If a block is an array then it must match across the shader.
-    * Unsized arrays are also processed and matched agaist sized arrays.
-    */
-   if (b->type != a->type &&
-       (b->is_interface_instance() || a->is_interface_instance()) &&
-       !validate_intrastage_arrays(prog, b, a))
-      return false;
-
-   return true;
-}
-
 /**
  * Return true if interface members mismatch and its not allowed by GLSL.
  */
@@ -110,7 +65,7 @@ interstage_member_mismatch(struct gl_shader_program *prog,
        *    interpolation qualifiers of variables of the same name do not
        *    match."
        */
-      if (prog->IsES || prog->Version < 440)
+      if (prog->IsES || prog->data->Version < 440)
          if (c->fields.structure[i].interpolation !=
              p->fields.structure[i].interpolation)
             return true;
@@ -129,7 +84,7 @@ interstage_member_mismatch(struct gl_shader_program *prog,
        * The table in Section 9.2.1 Linked Shaders of the GLSL ES 3.2 spec
        * says that sample need not match for varyings.
        */
-      if (!prog->IsES || prog->Version < 310)
+      if (!prog->IsES || prog->data->Version < 310)
          if (c->fields.structure[i].centroid !=
              p->fields.structure[i].centroid)
             return true;
@@ -142,6 +97,55 @@ interstage_member_mismatch(struct gl_shader_program *prog,
    return false;
 }
 
+/**
+ * Check if two interfaces match, according to intrastage interface matching
+ * rules.  If they do, and the first interface uses an unsized array, it will
+ * be updated to reflect the array size declared in the second interface.
+ */
+bool
+intrastage_match(ir_variable *a,
+                 ir_variable *b,
+                 struct gl_shader_program *prog)
+{
+   /* Types must match. */
+   if (a->get_interface_type() != b->get_interface_type()) {
+      /* Exception: if both the interface blocks are implicitly declared,
+       * don't force their types to match.  They might mismatch due to the two
+       * shaders using different GLSL versions, and that's ok.
+       */
+      if ((a->data.how_declared != ir_var_declared_implicitly ||
+           b->data.how_declared != ir_var_declared_implicitly) &&
+          (!prog->IsES ||
+           interstage_member_mismatch(prog, a->get_interface_type(),
+                                      b->get_interface_type())))
+         return false;
+   }
+
+   /* Presence/absence of interface names must match. */
+   if (a->is_interface_instance() != b->is_interface_instance())
+      return false;
+
+   /* For uniforms, instance names need not match.  For shader ins/outs,
+    * it's not clear from the spec whether they need to match, but
+    * Mesa's implementation relies on them matching.
+    */
+   if (a->is_interface_instance() && b->data.mode != ir_var_uniform &&
+       b->data.mode != ir_var_shader_storage &&
+       strcmp(a->name, b->name) != 0) {
+      return false;
+   }
+
+   /* If a block is an array then it must match across the shader.
+    * Unsized arrays are also processed and matched agaist sized arrays.
+    */
+   if (b->type != a->type && (b->type->is_array() || a->type->is_array()) &&
+       (b->is_interface_instance() || a->is_interface_instance()) &&
+       !validate_intrastage_arrays(prog, b, a))
+      return false;
+
+   return true;
+}
+
 /**
  * Check if two interfaces match, according to interstage (in/out) interface
  * matching rules.
@@ -341,10 +345,19 @@ validate_intrastage_interface_blocks(struct gl_shader_program *prog,
    }
 }
 
+static bool
+is_builtin_gl_in_block(ir_variable *var, int consumer_stage)
+{
+   return !strcmp(var->name, "gl_in") &&
+          (consumer_stage == MESA_SHADER_TESS_CTRL ||
+           consumer_stage == MESA_SHADER_TESS_EVAL ||
+           consumer_stage == MESA_SHADER_GEOMETRY);
+}
+
 void
 validate_interstage_inout_blocks(struct gl_shader_program *prog,
-                                 const gl_shader *producer,
-                                 const gl_shader *consumer)
+                                 const gl_linked_shader *producer,
+                                 const gl_linked_shader *consumer)
 {
    interface_block_definitions definitions;
    /* VS -> GS, VS -> TCS, VS -> TES, TES -> GS */
@@ -352,28 +365,67 @@ validate_interstage_inout_blocks(struct gl_shader_program *prog,
                                    consumer->Stage != MESA_SHADER_FRAGMENT) ||
                                   consumer->Stage == MESA_SHADER_GEOMETRY;
 
-   /* Add input interfaces from the consumer to the symbol table. */
-   foreach_in_list(ir_instruction, node, consumer->ir) {
+   /* Check that block re-declarations of gl_PerVertex are compatible
+    * across shaders: From OpenGL Shading Language 4.5, section
+    * "7.1 Built-In Language Variables", page 130 of the PDF:
+    *
+    *    "If multiple shaders using members of a built-in block belonging
+    *     to the same interface are linked together in the same program,
+    *     they must all redeclare the built-in block in the same way, as
+    *     described in section 4.3.9 “Interface Blocks” for interface-block
+    *     matching, or a link-time error will result."
+    *
+    * This is done explicitly outside of iterating the member variable
+    * declarations because it is possible that the variables are not used and
+    * so they would have been optimised out.
+    */
+   const glsl_type *consumer_iface =
+      consumer->symbols->get_interface("gl_PerVertex",
+                                       ir_var_shader_in);
+
+   const glsl_type *producer_iface =
+      producer->symbols->get_interface("gl_PerVertex",
+                                       ir_var_shader_out);
+
+   if (producer_iface && consumer_iface &&
+       interstage_member_mismatch(prog, consumer_iface, producer_iface)) {
+      linker_error(prog, "Incompatible or missing gl_PerVertex re-declaration "
+                   "in consecutive shaders");
+      return;
+   }
+
+   /* Add output interfaces from the producer to the symbol table. */
+   foreach_in_list(ir_instruction, node, producer->ir) {
       ir_variable *var = node->as_variable();
-      if (!var || !var->get_interface_type() || var->data.mode != ir_var_shader_in)
+      if (!var || !var->get_interface_type() || var->data.mode != ir_var_shader_out)
          continue;
 
       definitions.store(var);
    }
 
-   /* Verify that the producer's output interfaces match. */
-   foreach_in_list(ir_instruction, node, producer->ir) {
+   /* Verify that the consumer's input interfaces match. */
+   foreach_in_list(ir_instruction, node, consumer->ir) {
       ir_variable *var = node->as_variable();
-      if (!var || !var->get_interface_type() || var->data.mode != ir_var_shader_out)
+      if (!var || !var->get_interface_type() || var->data.mode != ir_var_shader_in)
          continue;
 
-      ir_variable *consumer_def = definitions.lookup(var);
+      ir_variable *producer_def = definitions.lookup(var);
 
-      /* The consumer doesn't use this output block.  Ignore it. */
-      if (consumer_def == NULL)
-         continue;
+      /* The producer doesn't generate this input: fail to link. Skip built-in
+       * 'gl_in[]' since that may not be present if the producer does not
+       * write to any of the pre-defined outputs (e.g. if the vertex shader
+       * does not write to gl_Position, etc), which is allowed and results in
+       * undefined behavior.
+       */
+      if (producer_def == NULL &&
+          !is_builtin_gl_in_block(var, consumer->Stage)) {
+         linker_error(prog, "Input block `%s' is not an output of "
+                      "the previous stage\n", var->get_interface_type()->name);
+         return;
+      }
 
-      if (!interstage_match(prog, var, consumer_def, extra_array_level)) {
+      if (producer_def &&
+          !interstage_match(prog, producer_def, var, extra_array_level)) {
          linker_error(prog, "definitions of interface block `%s' do not "
                       "match\n", var->get_interface_type()->name);
          return;
@@ -384,15 +436,15 @@ validate_interstage_inout_blocks(struct gl_shader_program *prog,
 
 void
 validate_interstage_uniform_blocks(struct gl_shader_program *prog,
-                                   gl_shader **stages, int num_stages)
+                                   gl_linked_shader **stages)
 {
    interface_block_definitions definitions;
 
-   for (int i = 0; i < num_stages; i++) {
+   for (int i = 0; i < MESA_SHADER_STAGES; i++) {
       if (stages[i] == NULL)
          continue;
 
-      const gl_shader *stage = stages[i];
+      const gl_linked_shader *stage = stages[i];
       foreach_in_list(ir_instruction, node, stage->ir) {
          ir_variable *var = node->as_variable();
          if (!var || !var->get_interface_type() ||
@@ -409,7 +461,7 @@ validate_interstage_uniform_blocks(struct gl_shader_program *prog,
              * shaders are in the same shader stage).
              */
             if (!intrastage_match(old_def, var, prog)) {
-               linker_error(prog, "definitions of interface block `%s' do not "
+               linker_error(prog, "definitions of uniform block `%s' do not "
                             "match\n", var->get_interface_type()->name);
                return;
             }