nir/vtn: Use return type rather than image type for tex ops
[mesa.git] / src / compiler / glsl / link_interface_blocks.cpp
index ce90d91607554364c02aa2219e6f669d45107277..4471b41cf0e9a0fbc36d33a07e4db474456983a2 100644 (file)
@@ -30,7 +30,9 @@
 #include "glsl_symbol_table.h"
 #include "linker.h"
 #include "main/macros.h"
+#include "main/mtypes.h"
 #include "util/hash_table.h"
+#include "util/u_string.h"
 
 
 namespace {
@@ -104,7 +106,8 @@ interstage_member_mismatch(struct gl_shader_program *prog,
 bool
 intrastage_match(ir_variable *a,
                  ir_variable *b,
-                 struct gl_shader_program *prog)
+                 struct gl_shader_program *prog,
+                 bool match_precision)
 {
    /* Types must match. */
    if (a->get_interface_type() != b->get_interface_type()) {
@@ -134,12 +137,16 @@ intrastage_match(ir_variable *a,
       return false;
    }
 
+   bool type_match = (match_precision ?
+                      a->type == b->type :
+                      a->type->compare_no_precision(b->type));
+
    /* 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()) &&
+   if (!type_match && (b->type->is_array() || a->type->is_array()) &&
        (b->is_interface_instance() || a->is_interface_instance()) &&
-       !validate_intrastage_arrays(prog, b, a))
+       !validate_intrastage_arrays(prog, b, a, match_precision))
       return false;
 
    return true;
@@ -213,7 +220,7 @@ class interface_block_definitions
 public:
    interface_block_definitions()
       : mem_ctx(ralloc_context(NULL)),
-        ht(_mesa_hash_table_create(NULL, _mesa_key_hash_string,
+        ht(_mesa_hash_table_create(NULL, _mesa_hash_string,
                                    _mesa_key_string_equal))
    {
    }
@@ -335,7 +342,8 @@ validate_intrastage_interface_blocks(struct gl_shader_program *prog,
              * it into the appropriate data structure.
              */
             definitions->store(var);
-         } else if (!intrastage_match(prev_def, var, prog)) {
+         } else if (!intrastage_match(prev_def, var, prog,
+                                      true /* match_precision */)) {
             linker_error(prog, "definitions of interface block `%s' do not"
                          " match\n", iface_type->name);
             return;
@@ -393,12 +401,56 @@ validate_interstage_inout_blocks(struct gl_shader_program *prog,
       return;
    }
 
+   /* Desktop OpenGL requires redeclaration of the built-in interfaces for
+    * SSO programs. Passes above implement following rules:
+    *
+    * From Section 7.4 (Program Pipeline Objects) of the OpenGL 4.6 Core
+    * spec:
+    *
+    *    "To use any built-in input or output in the gl_PerVertex and
+    *     gl_PerFragment blocks in separable program objects, shader code
+    *     must redeclare those blocks prior to use.  A separable program
+    *     will fail to link if:
+    *
+    *     it contains multiple shaders of a single type with different
+    *     redeclarations of these built-in input and output blocks; or
+    *
+    *     any shader uses a built-in block member not found in the
+    *     redeclaration of that block."
+    *
+    * ARB_separate_shader_objects issues section (issue #28) states that
+    * redeclaration is not required for GLSL shaders using #version 140 or
+    * earlier (since interface blocks are not possible with older versions).
+    *
+    * From Section 7.4.1 (Shader Interface Matching) of the OpenGL ES 3.1
+    * spec:
+    *
+    *    "Built-in inputs or outputs do not affect interface matching."
+    *
+    * GL_OES_shader_io_blocks adds following:
+    *
+    *    "When using any built-in input or output in the gl_PerVertex block
+    *     in separable program objects, shader code may redeclare that block
+    *     prior to use. If the shader does not redeclare the block, the
+    *     intrinsically declared definition of that block will be used."
+    */
+
    /* 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_out)
          continue;
 
+      /* Built-in interface redeclaration check. */
+      if (prog->SeparateShader && !prog->IsES && prog->data->Version >= 150 &&
+          var->data.how_declared == ir_var_declared_implicitly &&
+          var->data.used && !producer_iface) {
+         linker_error(prog, "missing output builtin block %s redeclaration "
+                      "in separable shader program",
+                      var->get_interface_type()->name);
+         return;
+      }
+
       definitions.store(var);
    }
 
@@ -410,14 +462,30 @@ validate_interstage_inout_blocks(struct gl_shader_program *prog,
 
       ir_variable *producer_def = definitions.lookup(var);
 
+      /* Built-in interface redeclaration check. */
+      if (prog->SeparateShader && !prog->IsES && prog->data->Version >= 150 &&
+          var->data.how_declared == ir_var_declared_implicitly &&
+          var->data.used && !producer_iface) {
+         linker_error(prog, "missing input builtin block %s redeclaration "
+                      "in separable shader program",
+                      var->get_interface_type()->name);
+         return;
+      }
+
       /* 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.
+       *
+       * From Section 4.3.4 (Inputs) of the GLSL 1.50 spec:
+       *
+       *    "Only the input variables that are actually read need to be written
+       *     by the previous stage; it is allowed to have superfluous
+       *     declarations of input variables."
        */
       if (producer_def == NULL &&
-          !is_builtin_gl_in_block(var, consumer->Stage)) {
+          !is_builtin_gl_in_block(var, consumer->Stage) && var->data.used) {
          linker_error(prog, "Input block `%s' is not an output of "
                       "the previous stage\n", var->get_interface_type()->name);
          return;
@@ -459,7 +527,7 @@ validate_interstage_uniform_blocks(struct gl_shader_program *prog,
              * uniform matchin rules (for uniforms, it is as though all
              * shaders are in the same shader stage).
              */
-            if (!intrastage_match(old_def, var, prog)) {
+            if (!intrastage_match(old_def, var, prog, false /* precision */)) {
                linker_error(prog, "definitions of uniform block `%s' do not "
                             "match\n", var->get_interface_type()->name);
                return;