glsl: ignore all but the rightmost layout qualifier name from the rightmost layout...
authorAndres Gomez <agomez@igalia.com>
Sat, 22 Oct 2016 14:01:11 +0000 (17:01 +0300)
committerAndres Gomez <agomez@igalia.com>
Fri, 25 Nov 2016 11:18:30 +0000 (13:18 +0200)
From page 46 (page 52 of the PDF) of the GLSL 4.20 spec:

  " More than one layout qualifier may appear in a single
    declaration. If the same layout-qualifier-name occurs in multiple
    layout qualifiers for the same declaration, the last one overrides
    the former ones."

Consider this example:

  " #version 150
    #extension GL_ARB_shading_language_420pack: enable

    layout(max_vertices=2) layout(max_vertices=3) out;
    layout(max_vertices=3) out;"

Although different values for "max_vertices" results in a compilation
error. The above code is valid because max_vertices=2 is ignored.

Hence, when merging qualifiers in an ast_type_qualifier, we now ignore
new appearances of a same layout-qualifier-name if the new
"is_multiple_layouts_merge" parameter is on, since the GLSL parser
works in this case from right to left.

In addition, any special treatment for the buffer, uniform, in or out
layout defaults has been moved in the GLSL parser to the rule
triggered just after any previous processing/merging on the
layout-qualifiers has happened in a single declaration since it was
run too soon previously.

Fixes GL44-CTS.shading_language_420pack.qualifier_override_layout

Reviewed-by: Timothy Arceri <timothy.arceri@collabora.com>
Signed-off-by: Andres Gomez <agomez@igalia.com>
src/compiler/glsl/ast.h
src/compiler/glsl/ast_type.cpp
src/compiler/glsl/glsl_parser.yy

index 62ccb9d4d3424162994fdb7cfd0b91dbaf764ede..7bbb58800a74ffc8466e93aebe9dcae36f7d6178 100644 (file)
@@ -753,7 +753,8 @@ struct ast_type_qualifier {
    bool merge_qualifier(YYLTYPE *loc,
                        _mesa_glsl_parse_state *state,
                         const ast_type_qualifier &q,
-                        bool is_single_layout_merge);
+                        bool is_single_layout_merge,
+                        bool is_multiple_layouts_merge = false);
 
    /**
     * Validate current qualifier against the global out one.
index 20c0fcfae21cdfe4aba853c0a5649188b60fe811..91050a5877acfc1263c4106e05a24a3dd18883fc 100644 (file)
@@ -183,15 +183,21 @@ validate_point_mode(YYLTYPE *loc,
 }
 
 /**
- * This function merges both duplicate identifies within a single layout and
- * multiple layout qualifiers on a single variable declaration. The
- * is_single_layout_merge param is used differentiate between the two.
+ * This function merges duplicate layout identifiers.
+ *
+ * It deals with duplicates within a single layout qualifier, among multiple
+ * layout qualifiers on a single declaration and on several declarations for
+ * the same variable.
+ *
+ * The is_single_layout_merge and is_multiple_layouts_merge parameters are
+ * used to differentiate among them.
  */
 bool
 ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
                                     _mesa_glsl_parse_state *state,
                                     const ast_type_qualifier &q,
-                                    bool is_single_layout_merge)
+                                    bool is_single_layout_merge,
+                                    bool is_multiple_layouts_merge)
 {
    bool r = true;
    ast_type_qualifier ubo_mat_mask;
@@ -269,7 +275,8 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
    }
 
    if (q.flags.q.max_vertices) {
-      if (this->flags.q.max_vertices && !is_single_layout_merge) {
+      if (this->flags.q.max_vertices
+          && !is_single_layout_merge && !is_multiple_layouts_merge) {
          this->max_vertices->merge_qualifier(q.max_vertices);
       } else {
          this->flags.q.max_vertices = 1;
@@ -287,7 +294,8 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
    }
 
    if (q.flags.q.invocations) {
-      if (this->flags.q.invocations && !is_single_layout_merge) {
+      if (this->flags.q.invocations
+          && !is_single_layout_merge && !is_multiple_layouts_merge) {
          this->invocations->merge_qualifier(q.invocations);
       } else {
          this->flags.q.invocations = 1;
@@ -338,7 +346,7 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
          if (process_qualifier_constant(state, loc, "xfb_buffer",
                                         this->xfb_buffer, &buff_idx)) {
             if (state->out_qualifier->out_xfb_stride[buff_idx]
-                && !is_single_layout_merge) {
+                && !is_single_layout_merge && !is_multiple_layouts_merge) {
                state->out_qualifier->out_xfb_stride[buff_idx]->merge_qualifier(
                   new(state->linalloc) ast_layout_expression(*loc, this->xfb_stride));
             } else {
@@ -350,7 +358,8 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
    }
 
    if (q.flags.q.vertices) {
-      if (this->flags.q.vertices && !is_single_layout_merge) {
+      if (this->flags.q.vertices
+          && !is_single_layout_merge && !is_multiple_layouts_merge) {
          this->vertices->merge_qualifier(q.vertices);
       } else {
          this->flags.q.vertices = 1;
@@ -386,7 +395,8 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
 
    for (int i = 0; i < 3; i++) {
       if (q.flags.q.local_size & (1 << i)) {
-         if (this->local_size[i] && !is_single_layout_merge) {
+         if (this->local_size[i]
+             && !is_single_layout_merge && !is_multiple_layouts_merge) {
             this->local_size[i]->merge_qualifier(q.local_size[i]);
          } else {
             this->local_size[i] = q.local_size[i];
index 82501af6456973593501056ccc18b2153d90aaf9..5a8f854ece8912607dcae85b8f031972f66dde9f 100644 (file)
@@ -297,10 +297,10 @@ static bool match_layout_qualifier(const char *s1, const char *s2,
 %type <node> for_init_statement
 %type <for_rest_statement> for_rest_statement
 %type <node> layout_defaults
-%type <node> layout_uniform_defaults
-%type <node> layout_buffer_defaults
-%type <node> layout_in_defaults
-%type <node> layout_out_defaults
+%type <type_qualifier> layout_uniform_defaults
+%type <type_qualifier> layout_buffer_defaults
+%type <type_qualifier> layout_in_defaults
+%type <type_qualifier> layout_out_defaults
 
 %right THEN ELSE
 %%
@@ -1891,7 +1891,7 @@ type_qualifier:
          _mesa_glsl_error(&@1, state, "duplicate layout(...) qualifiers");
 
       $$ = $1;
-      $$.merge_qualifier(&@1, state, $2, false);
+      $$.merge_qualifier(& @1, state, $2, false, $2.has_layout());
    }
    | subroutine_qualifier type_qualifier
    {
@@ -2718,7 +2718,8 @@ interface_block:
          YYERROR;
       }
 
-      if (!$1.merge_qualifier(& @1, state, block->layout, false)) {
+      if (!$1.merge_qualifier(& @1, state, block->layout, false,
+                              block->layout.has_layout())) {
          YYERROR;
       }
 
@@ -2853,123 +2854,118 @@ member_declaration:
 layout_uniform_defaults:
    layout_qualifier layout_uniform_defaults
    {
-      $$ = NULL;
+      $$ = $1;
       if (!state->has_420pack_or_es31()) {
          _mesa_glsl_error(&@1, state, "duplicate layout(...) qualifiers");
          YYERROR;
-      } else {
-         if (!state->default_uniform_qualifier->
-                merge_qualifier(& @1, state, $1, false)) {
-            YYERROR;
-         }
       }
-   }
-   | layout_qualifier UNIFORM ';'
-   {
-      if (!state->default_uniform_qualifier->
-             merge_qualifier(& @1, state, $1, false)) {
+      if (!$$.merge_qualifier(& @1, state, $2, false, true)) {
          YYERROR;
       }
-      $$ = NULL;
    }
+   | layout_qualifier UNIFORM ';'
    ;
 
 layout_buffer_defaults:
    layout_qualifier layout_buffer_defaults
    {
-      $$ = NULL;
+      $$ = $1;
       if (!state->has_420pack_or_es31()) {
          _mesa_glsl_error(&@1, state, "duplicate layout(...) qualifiers");
          YYERROR;
-      } else {
-         if (!state->default_shader_storage_qualifier->
-                merge_qualifier(& @1, state, $1, false)) {
-            YYERROR;
-         }
       }
-   }
-   | layout_qualifier BUFFER ';'
-   {
-      if (!state->default_shader_storage_qualifier->
-             merge_qualifier(& @1, state, $1, false)) {
+      if (!$$.merge_qualifier(& @1, state, $2, false, true)) {
          YYERROR;
       }
-
-      /* From the GLSL 4.50 spec, section 4.4.5:
-       *
-       *     "It is a compile-time error to specify the binding identifier for
-       *     the global scope or for block member declarations."
-       */
-      if (state->default_shader_storage_qualifier->flags.q.explicit_binding) {
-         _mesa_glsl_error(& @1, state,
-                          "binding qualifier cannot be set for default layout");
-      }
-
-      $$ = NULL;
    }
+   | layout_qualifier BUFFER ';'
    ;
 
 layout_in_defaults:
    layout_qualifier layout_in_defaults
    {
-      $$ = NULL;
+      $$ = $1;
       if (!state->has_420pack_or_es31()) {
          _mesa_glsl_error(&@1, state, "duplicate layout(...) qualifiers");
          YYERROR;
-      } else {
-         if (!$1.validate_in_qualifier(& @1, state)) {
-            YYERROR;
-         }
-         if (!$1.merge_into_in_qualifier(& @1, state, $$, false)) {
-            YYERROR;
-         }
-         $$ = $2;
+      }
+      if (!$$.merge_qualifier(& @1, state, $2, false, true)) {
+         YYERROR;
+      }
+      if (!$$.validate_in_qualifier(& @1, state)) {
+         YYERROR;
       }
    }
    | layout_qualifier IN_TOK ';'
    {
-      $$ = NULL;
       if (!$1.validate_in_qualifier(& @1, state)) {
          YYERROR;
       }
-      if (!$1.merge_into_in_qualifier(& @1, state, $$, true)) {
-         YYERROR;
-      }
    }
    ;
 
 layout_out_defaults:
    layout_qualifier layout_out_defaults
    {
-      $$ = NULL;
+      $$ = $1;
       if (!state->has_420pack_or_es31()) {
          _mesa_glsl_error(&@1, state, "duplicate layout(...) qualifiers");
          YYERROR;
-      } else {
-         if (!$1.validate_out_qualifier(& @1, state)) {
-            YYERROR;
-         }
-         if (!$1.merge_into_out_qualifier(& @1, state, $$, false)) {
-            YYERROR;
-         }
-         $$ = $2;
+      }
+      if (!$$.merge_qualifier(& @1, state, $2, false, true)) {
+         YYERROR;
+      }
+      if (!$$.validate_out_qualifier(& @1, state)) {
+         YYERROR;
       }
    }
    | layout_qualifier OUT_TOK ';'
    {
-      $$ = NULL;
       if (!$1.validate_out_qualifier(& @1, state)) {
          YYERROR;
       }
-      if (!$1.merge_into_out_qualifier(& @1, state, $$, true)) {
-         YYERROR;
-      }
    }
    ;
 
 layout_defaults:
    layout_uniform_defaults
+   {
+      $$ = NULL;
+      if (!state->default_uniform_qualifier->
+             merge_qualifier(& @1, state, $1, false)) {
+         YYERROR;
+      }
+   }
    | layout_buffer_defaults
+   {
+      $$ = NULL;
+      if (!state->default_shader_storage_qualifier->
+             merge_qualifier(& @1, state, $1, false)) {
+         YYERROR;
+      }
+
+      /* From the GLSL 4.50 spec, section 4.4.5:
+       *
+       *     "It is a compile-time error to specify the binding identifier for
+       *     the global scope or for block member declarations."
+       */
+      if (state->default_shader_storage_qualifier->flags.q.explicit_binding) {
+         _mesa_glsl_error(& @1, state,
+                          "binding qualifier cannot be set for default layout");
+      }
+   }
    | layout_in_defaults
+   {
+      $$ = NULL;
+      if (!$1.merge_into_in_qualifier(& @1, state, $$, true)) {
+         YYERROR;
+      }
+   }
    | layout_out_defaults
+   {
+      $$ = NULL;
+      if (!$1.merge_into_out_qualifier(& @1, state, $$, true)) {
+         YYERROR;
+      }
+   }
    ;