glsl: give all unnamed structs the same name
[mesa.git] / src / compiler / glsl / link_interface_blocks.cpp
index 4c6fb56f8912447949221a5f9c36151582c4b8f4..7037c7776de6f20ee68b981ca92f004368eb74a0 100644 (file)
 
 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 +64,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 +83,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 +96,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 || prog->data->Version != 310 ||
+           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->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.
@@ -154,12 +157,6 @@ static bool
 interstage_match(struct gl_shader_program *prog, ir_variable *producer,
                  ir_variable *consumer, bool extra_array_level)
 {
-   /* Unsized arrays should not occur during interstage linking.  They
-    * should have all been assigned a size by link_intrastage_shaders.
-    */
-   assert(!consumer->type->is_unsized_array());
-   assert(!producer->type->is_unsized_array());
-
    /* Types must match. */
    if (consumer->get_interface_type() != producer->get_interface_type()) {
       /* Exception: if both the interface blocks are implicitly declared,
@@ -242,7 +239,8 @@ public:
          return entry ? (ir_variable *) entry->data : NULL;
       } else {
          const struct hash_entry *entry =
-            _mesa_hash_table_search(ht, var->get_interface_type()->name);
+            _mesa_hash_table_search(ht,
+               var->get_interface_type()->without_array()->name);
          return entry ? (ir_variable *) entry->data : NULL;
       }
    }
@@ -263,7 +261,8 @@ public:
          snprintf(location_str, 11, "%d", var->data.location);
          _mesa_hash_table_insert(ht, ralloc_strdup(mem_ctx, location_str), var);
       } else {
-         _mesa_hash_table_insert(ht, var->get_interface_type()->name, var);
+         _mesa_hash_table_insert(ht,
+            var->get_interface_type()->without_array()->name, var);
       }
    }
 
@@ -345,10 +344,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 */
@@ -356,28 +364,38 @@ 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) {
+   /* 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;
@@ -388,15 +406,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() ||
@@ -413,7 +431,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;
             }