glsl: Checks for interpolation into its own function.
authorAndres Gomez <agomez@igalia.com>
Wed, 23 Mar 2016 23:13:26 +0000 (01:13 +0200)
committerSamuel Iglesias Gonsálvez <siglesias@igalia.com>
Fri, 29 Apr 2016 06:03:00 +0000 (08:03 +0200)
This generalizes the validation also to be done for variables inside
interface blocks, which, for some cases, was missing.

For a discussion about the additional validation cases included see
https://lists.freedesktop.org/archives/mesa-dev/2016-March/109117.html
and Khronos bug #15671.

Reviewed-by: Samuel Iglesias Gonsálvez <siglesias@igalia.com>
Signed-off-by: Andres Gomez <agomez@igalia.com>
src/compiler/glsl/ast_to_hir.cpp

index 82eb22a..dd8e4e0 100644 (file)
@@ -2792,8 +2792,164 @@ apply_explicit_binding(struct _mesa_glsl_parse_state *state,
 }
 
 
+static void
+validate_interpolation_qualifier(struct _mesa_glsl_parse_state *state,
+                                 YYLTYPE *loc,
+                                 const glsl_interp_qualifier interpolation,
+                                 const struct ast_type_qualifier *qual,
+                                 const struct glsl_type *var_type,
+                                 ir_variable_mode mode)
+{
+   /* Interpolation qualifiers can only apply to shader inputs or outputs, but
+    * not to vertex shader inputs nor fragment shader outputs.
+    *
+    * From section 4.3 ("Storage Qualifiers") of the GLSL 1.30 spec:
+    *    "Outputs from a vertex shader (out) and inputs to a fragment
+    *    shader (in) can be further qualified with one or more of these
+    *    interpolation qualifiers"
+    *    ...
+    *    "These interpolation qualifiers may only precede the qualifiers in,
+    *    centroid in, out, or centroid out in a declaration. They do not apply
+    *    to the deprecated storage qualifiers varying or centroid
+    *    varying. They also do not apply to inputs into a vertex shader or
+    *    outputs from a fragment shader."
+    *
+    * From section 4.3 ("Storage Qualifiers") of the GLSL ES 3.00 spec:
+    *    "Outputs from a shader (out) and inputs to a shader (in) can be
+    *    further qualified with one of these interpolation qualifiers."
+    *    ...
+    *    "These interpolation qualifiers may only precede the qualifiers
+    *    in, centroid in, out, or centroid out in a declaration. They do
+    *    not apply to inputs into a vertex shader or outputs from a
+    *    fragment shader."
+    */
+   if (state->is_version(130, 300)
+       && interpolation != INTERP_QUALIFIER_NONE) {
+      const char *i = interpolation_string(interpolation);
+      if (mode != ir_var_shader_in && mode != ir_var_shader_out)
+         _mesa_glsl_error(loc, state,
+                          "interpolation qualifier `%s' can only be applied to "
+                          "shader inputs or outputs.", i);
+
+      switch (state->stage) {
+      case MESA_SHADER_VERTEX:
+         if (mode == ir_var_shader_in) {
+            _mesa_glsl_error(loc, state,
+                             "interpolation qualifier '%s' cannot be applied to "
+                             "vertex shader inputs", i);
+         }
+         break;
+      case MESA_SHADER_FRAGMENT:
+         if (mode == ir_var_shader_out) {
+            _mesa_glsl_error(loc, state,
+                             "interpolation qualifier '%s' cannot be applied to "
+                             "fragment shader outputs", i);
+         }
+         break;
+      default:
+         break;
+      }
+   }
+
+   /* Interpolation qualifiers cannot be applied to 'centroid' and
+    * 'centroid varying'.
+    *
+    * From section 4.3 ("Storage Qualifiers") of the GLSL 1.30 spec:
+    *    "interpolation qualifiers may only precede the qualifiers in,
+    *    centroid in, out, or centroid out in a declaration. They do not apply
+    *    to the deprecated storage qualifiers varying or centroid varying."
+    *
+    * These deprecated storage qualifiers do not exist in GLSL ES 3.00.
+    */
+   if (state->is_version(130, 0)
+       && interpolation != INTERP_QUALIFIER_NONE
+       && qual->flags.q.varying) {
+
+      const char *i = interpolation_string(interpolation);
+      const char *s;
+      if (qual->flags.q.centroid)
+         s = "centroid varying";
+      else
+         s = "varying";
+
+      _mesa_glsl_error(loc, state,
+                       "qualifier '%s' cannot be applied to the "
+                       "deprecated storage qualifier '%s'", i, s);
+   }
+
+   /* Integer fragment inputs must be qualified with 'flat'.  In GLSL ES,
+    * so must integer vertex outputs.
+    *
+    * From section 4.3.4 ("Inputs") of the GLSL 1.50 spec:
+    *    "Fragment shader inputs that are signed or unsigned integers or
+    *    integer vectors must be qualified with the interpolation qualifier
+    *    flat."
+    *
+    * From section 4.3.4 ("Input Variables") of the GLSL 3.00 ES spec:
+    *    "Fragment shader inputs that are, or contain, signed or unsigned
+    *    integers or integer vectors must be qualified with the
+    *    interpolation qualifier flat."
+    *
+    * From section 4.3.6 ("Output Variables") of the GLSL 3.00 ES spec:
+    *    "Vertex shader outputs that are, or contain, signed or unsigned
+    *    integers or integer vectors must be qualified with the
+    *    interpolation qualifier flat."
+    *
+    * Note that prior to GLSL 1.50, this requirement applied to vertex
+    * outputs rather than fragment inputs.  That creates problems in the
+    * presence of geometry shaders, so we adopt the GLSL 1.50 rule for all
+    * desktop GL shaders.  For GLSL ES shaders, we follow the spec and
+    * apply the restriction to both vertex outputs and fragment inputs.
+    *
+    * Note also that the desktop GLSL specs are missing the text "or
+    * contain"; this is presumably an oversight, since there is no
+    * reasonable way to interpolate a fragment shader input that contains
+    * an integer. See Khronos bug #15671.
+    */
+   if (state->is_version(130, 300)
+       && var_type->contains_integer()
+       && interpolation != INTERP_QUALIFIER_FLAT
+       && ((state->stage == MESA_SHADER_FRAGMENT && mode == ir_var_shader_in)
+           || (state->stage == MESA_SHADER_VERTEX && mode == ir_var_shader_out
+               && state->es_shader))) {
+      const char *shader_var_type = (state->stage == MESA_SHADER_VERTEX) ?
+         "vertex output" : "fragment input";
+      _mesa_glsl_error(loc, state, "if a %s is (or contains) "
+                       "an integer, then it must be qualified with 'flat'",
+                       shader_var_type);
+   }
+
+   /* Double fragment inputs must be qualified with 'flat'.
+    *
+    * From the "Overview" of the ARB_gpu_shader_fp64 extension spec:
+    *    "This extension does not support interpolation of double-precision
+    *    values; doubles used as fragment shader inputs must be qualified as
+    *    "flat"."
+    *
+    * From section 4.3.4 ("Inputs") of the GLSL 4.00 spec:
+    *    "Fragment shader inputs that are signed or unsigned integers, integer
+    *    vectors, or any double-precision floating-point type must be
+    *    qualified with the interpolation qualifier flat."
+    *
+    * Note that the GLSL specs are missing the text "or contain"; this is
+    * presumably an oversight. See Khronos bug #15671.
+    *
+    * The 'double' type does not exist in GLSL ES so far.
+    */
+   if ((state->ARB_gpu_shader_fp64_enable
+        || state->is_version(400, 0))
+       && var_type->contains_double()
+       && interpolation != INTERP_QUALIFIER_FLAT
+       && state->stage == MESA_SHADER_FRAGMENT
+       && mode == ir_var_shader_in) {
+      _mesa_glsl_error(loc, state, "if a fragment input is (or contains) "
+                       "a double, then it must be qualified with 'flat'");
+   }
+}
+
 static glsl_interp_qualifier
 interpret_interpolation_qualifier(const struct ast_type_qualifier *qual,
+                                  const struct glsl_type *var_type,
                                   ir_variable_mode mode,
                                   struct _mesa_glsl_parse_state *state,
                                   YYLTYPE *loc)
@@ -2805,37 +2961,23 @@ interpret_interpolation_qualifier(const struct ast_type_qualifier *qual,
       interpolation = INTERP_QUALIFIER_NOPERSPECTIVE;
    else if (qual->flags.q.smooth)
       interpolation = INTERP_QUALIFIER_SMOOTH;
-   else
-      interpolation = INTERP_QUALIFIER_NONE;
-
-   if (interpolation != INTERP_QUALIFIER_NONE) {
-      if (mode != ir_var_shader_in && mode != ir_var_shader_out) {
-         _mesa_glsl_error(loc, state,
-                          "interpolation qualifier `%s' can only be applied to "
-                          "shader inputs or outputs.",
-                          interpolation_string(interpolation));
-
-      }
-
-      if ((state->stage == MESA_SHADER_VERTEX && mode == ir_var_shader_in) ||
-          (state->stage == MESA_SHADER_FRAGMENT && mode == ir_var_shader_out)) {
-         _mesa_glsl_error(loc, state,
-                          "interpolation qualifier `%s' cannot be applied to "
-                          "vertex shader inputs or fragment shader outputs",
-                          interpolation_string(interpolation));
-      }
-   } else if (state->es_shader &&
-              ((mode == ir_var_shader_in &&
-                state->stage != MESA_SHADER_VERTEX) ||
-               (mode == ir_var_shader_out &&
-                state->stage != MESA_SHADER_FRAGMENT))) {
+   else if (state->es_shader &&
+            ((mode == ir_var_shader_in &&
+              state->stage != MESA_SHADER_VERTEX) ||
+             (mode == ir_var_shader_out &&
+              state->stage != MESA_SHADER_FRAGMENT)))
       /* Section 4.3.9 (Interpolation) of the GLSL ES 3.00 spec says:
        *
        *    "When no interpolation qualifier is present, smooth interpolation
        *    is used."
        */
       interpolation = INTERP_QUALIFIER_SMOOTH;
-   }
+   else
+      interpolation = INTERP_QUALIFIER_NONE;
+
+   validate_interpolation_qualifier(state, loc,
+                                    interpolation,
+                                    qual, var_type, mode);
 
    return interpolation;
 }
@@ -3575,7 +3717,8 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
    }
 
    var->data.interpolation =
-      interpret_interpolation_qualifier(qual, (ir_variable_mode) var->data.mode,
+      interpret_interpolation_qualifier(qual, var->type,
+                                        (ir_variable_mode) var->data.mode,
                                         state, loc);
 
    /* Does the declaration use the deprecated 'attribute' or 'varying'
@@ -4756,124 +4899,6 @@ ast_declarator_list::hir(exec_list *instructions,
          var->data.how_declared = ir_var_hidden;
       }
 
-      /* Integer fragment inputs must be qualified with 'flat'.  In GLSL ES,
-       * so must integer vertex outputs.
-       *
-       * From section 4.3.4 ("Inputs") of the GLSL 1.50 spec:
-       *    "Fragment shader inputs that are signed or unsigned integers or
-       *    integer vectors must be qualified with the interpolation qualifier
-       *    flat."
-       *
-       * From section 4.3.4 ("Input Variables") of the GLSL 3.00 ES spec:
-       *    "Fragment shader inputs that are, or contain, signed or unsigned
-       *    integers or integer vectors must be qualified with the
-       *    interpolation qualifier flat."
-       *
-       * From section 4.3.6 ("Output Variables") of the GLSL 3.00 ES spec:
-       *    "Vertex shader outputs that are, or contain, signed or unsigned
-       *    integers or integer vectors must be qualified with the
-       *    interpolation qualifier flat."
-       *
-       * Note that prior to GLSL 1.50, this requirement applied to vertex
-       * outputs rather than fragment inputs.  That creates problems in the
-       * presence of geometry shaders, so we adopt the GLSL 1.50 rule for all
-       * desktop GL shaders.  For GLSL ES shaders, we follow the spec and
-       * apply the restriction to both vertex outputs and fragment inputs.
-       *
-       * Note also that the desktop GLSL specs are missing the text "or
-       * contain"; this is presumably an oversight, since there is no
-       * reasonable way to interpolate a fragment shader input that contains
-       * an integer.
-       */
-      if (state->is_version(130, 300) &&
-          var->type->contains_integer() &&
-          var->data.interpolation != INTERP_QUALIFIER_FLAT &&
-          ((state->stage == MESA_SHADER_FRAGMENT && var->data.mode == ir_var_shader_in)
-           || (state->stage == MESA_SHADER_VERTEX && var->data.mode == ir_var_shader_out
-               && state->es_shader))) {
-         const char *var_type = (state->stage == MESA_SHADER_VERTEX) ?
-            "vertex output" : "fragment input";
-         _mesa_glsl_error(&loc, state, "if a %s is (or contains) "
-                          "an integer, then it must be qualified with 'flat'",
-                          var_type);
-      }
-
-      /* Double fragment inputs must be qualified with 'flat'. */
-      if (var->type->contains_double() &&
-          var->data.interpolation != INTERP_QUALIFIER_FLAT &&
-          state->stage == MESA_SHADER_FRAGMENT &&
-          var->data.mode == ir_var_shader_in) {
-         _mesa_glsl_error(&loc, state, "if a fragment input is (or contains) "
-                          "a double, then it must be qualified with 'flat'",
-                          var_type);
-      }
-
-      /* Interpolation qualifiers cannot be applied to 'centroid' and
-       * 'centroid varying'.
-       *
-       * From page 29 (page 35 of the PDF) of the GLSL 1.30 spec:
-       *    "interpolation qualifiers may only precede the qualifiers in,
-       *    centroid in, out, or centroid out in a declaration. They do not apply
-       *    to the deprecated storage qualifiers varying or centroid varying."
-       *
-       * These deprecated storage qualifiers do not exist in GLSL ES 3.00.
-       */
-      if (state->is_version(130, 0)
-          && this->type->qualifier.has_interpolation()
-          && this->type->qualifier.flags.q.varying) {
-
-         const char *i = interpolation_string(var->data.interpolation);
-         const char *s;
-         if (this->type->qualifier.flags.q.centroid)
-            s = "centroid varying";
-         else
-            s = "varying";
-
-         _mesa_glsl_error(&loc, state,
-                          "qualifier '%s' cannot be applied to the "
-                          "deprecated storage qualifier '%s'", i, s);
-      }
-
-
-      /* Interpolation qualifiers can only apply to vertex shader outputs and
-       * fragment shader inputs.
-       *
-       * From page 29 (page 35 of the PDF) of the GLSL 1.30 spec:
-       *    "Outputs from a vertex shader (out) and inputs to a fragment
-       *    shader (in) can be further qualified with one or more of these
-       *    interpolation qualifiers"
-       *
-       * From page 31 (page 37 of the PDF) of the GLSL ES 3.00 spec:
-       *    "These interpolation qualifiers may only precede the qualifiers
-       *    in, centroid in, out, or centroid out in a declaration. They do
-       *    not apply to inputs into a vertex shader or outputs from a
-       *    fragment shader."
-       */
-      if (state->is_version(130, 300)
-          && this->type->qualifier.has_interpolation()) {
-
-         const char *i = interpolation_string(var->data.interpolation);
-         switch (state->stage) {
-         case MESA_SHADER_VERTEX:
-            if (this->type->qualifier.flags.q.in) {
-               _mesa_glsl_error(&loc, state,
-                                "qualifier '%s' cannot be applied to vertex "
-                                "shader inputs", i);
-            }
-            break;
-         case MESA_SHADER_FRAGMENT:
-            if (this->type->qualifier.flags.q.out) {
-               _mesa_glsl_error(&loc, state,
-                                "qualifier '%s' cannot be applied to fragment "
-                                "shader outputs", i);
-            }
-            break;
-         default:
-            break;
-         }
-      }
-
-
       /* From section 4.3.4 of the GLSL 4.00 spec:
        *    "Input variables may not be declared using the patch in qualifier
        *    in tessellation control or geometry shaders."
@@ -6608,7 +6633,8 @@ ast_process_struct_or_iface_block_members(exec_list *instructions,
          fields[i].type = field_type;
          fields[i].name = decl->identifier;
          fields[i].interpolation =
-            interpret_interpolation_qualifier(qual, var_mode, state, &loc);
+            interpret_interpolation_qualifier(qual, field_type,
+                                              var_mode, state, &loc);
          fields[i].centroid = qual->flags.q.centroid ? 1 : 0;
          fields[i].sample = qual->flags.q.sample ? 1 : 0;
          fields[i].patch = qual->flags.q.patch ? 1 : 0;