glsl: update parser to allow duplicate default layout qualifiers
authorTimothy Arceri <timothy.arceri@collabora.com>
Mon, 18 Jan 2016 06:06:57 +0000 (17:06 +1100)
committerTimothy Arceri <timothy.arceri@collabora.com>
Tue, 19 Jan 2016 21:06:45 +0000 (08:06 +1100)
In order to only create a single node for each default declaration
we add a new boolean parameter to the in/out merge function to
only create one once we reach the rightmost layout qualifier.

From the ARB_shading_language_420pack 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."

Acked-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Chris Forbes <chrisf@ijw.co.nz>
src/glsl/ast.h
src/glsl/ast_type.cpp
src/glsl/glsl_parser.yy

index f8ab0b71b7bb2b34b367c1b791f853f4c91bfde5..465166994eabcf06f285e67a8b47e62d9dd692a6 100644 (file)
@@ -704,12 +704,12 @@ struct ast_type_qualifier {
    bool merge_out_qualifier(YYLTYPE *loc,
                            _mesa_glsl_parse_state *state,
                            const ast_type_qualifier &q,
-                           ast_node* &node);
+                           ast_node* &node, bool create_node);
 
    bool merge_in_qualifier(YYLTYPE *loc,
                            _mesa_glsl_parse_state *state,
                            const ast_type_qualifier &q,
-                           ast_node* &node);
+                           ast_node* &node, bool create_node);
 
    ast_subroutine_list *subroutine_list;
 };
index e59d1b2754b6d8e504463dd7b9e9f9f1ad1bd9aa..32cb0a0319cd8822df80acb92fbd9e1a12030665 100644 (file)
@@ -291,7 +291,7 @@ bool
 ast_type_qualifier::merge_out_qualifier(YYLTYPE *loc,
                                         _mesa_glsl_parse_state *state,
                                         const ast_type_qualifier &q,
-                                        ast_node* &node)
+                                        ast_node* &node, bool create_node)
 {
    void *mem_ctx = state;
    const bool r = this->merge_qualifier(loc, state, q);
@@ -314,7 +314,9 @@ ast_type_qualifier::merge_out_qualifier(YYLTYPE *loc,
       /* Allow future assigments of global out's stream id value */
       this->flags.q.explicit_stream = 0;
    } else if (state->stage == MESA_SHADER_TESS_CTRL) {
-      node = new(mem_ctx) ast_tcs_output_layout(*loc);
+      if (create_node) {
+         node = new(mem_ctx) ast_tcs_output_layout(*loc);
+      }
    } else {
       _mesa_glsl_error(loc, state, "out layout qualifiers only valid in "
                        "tessellation control or geometry shaders");
@@ -327,7 +329,7 @@ bool
 ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
                                        _mesa_glsl_parse_state *state,
                                        const ast_type_qualifier &q,
-                                       ast_node* &node)
+                                       ast_node* &node, bool create_node)
 {
    void *mem_ctx = state;
    bool create_gs_ast = false;
@@ -467,10 +469,12 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
       this->point_mode = q.point_mode;
    }
 
-   if (create_gs_ast) {
-      node = new(mem_ctx) ast_gs_input_layout(*loc, q.prim_type);
-   } else if (create_cs_ast) {
-      node = new(mem_ctx) ast_cs_input_layout(*loc, q.local_size);
+   if (create_node) {
+      if (create_gs_ast) {
+         node = new(mem_ctx) ast_gs_input_layout(*loc, q.prim_type);
+      } else if (create_cs_ast) {
+         node = new(mem_ctx) ast_cs_input_layout(*loc, q.local_size);
+      }
    }
 
    return true;
index 925cb820ba9661cdfff94f357cc311ef6cea3d06..6099aeb12cac11f599cb1ef068d8c6cba9649f6e 100644 (file)
@@ -2742,7 +2742,20 @@ member_declaration:
    ;
 
 layout_uniform_defaults:
-   layout_qualifier UNIFORM ';'
+   layout_qualifier layout_uniform_defaults
+   {
+      $$ = NULL;
+      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)) {
+            YYERROR;
+         }
+      }
+   }
+   | layout_qualifier UNIFORM ';'
    {
       if (!state->default_uniform_qualifier->merge_qualifier(& @1, state, $1)) {
          YYERROR;
@@ -2752,7 +2765,20 @@ layout_uniform_defaults:
    ;
 
 layout_buffer_defaults:
-   layout_qualifier BUFFER ';'
+   layout_qualifier layout_buffer_defaults
+   {
+      $$ = NULL;
+      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)) {
+            YYERROR;
+         }
+      }
+   }
+   | layout_qualifier BUFFER ';'
    {
       if (!state->default_shader_storage_qualifier->merge_qualifier(& @1, state, $1)) {
          YYERROR;
@@ -2773,20 +2799,48 @@ layout_buffer_defaults:
    ;
 
 layout_in_defaults:
-   layout_qualifier IN_TOK ';'
+   layout_qualifier layout_in_defaults
    {
       $$ = NULL;
-      if (!state->in_qualifier->merge_in_qualifier(& @1, state, $1, $$)) {
+      if (!state->has_420pack_or_es31()) {
+         _mesa_glsl_error(&@1, state, "duplicate layout(...) qualifiers");
+         YYERROR;
+      } else {
+         if (!state->in_qualifier->
+                merge_in_qualifier(& @1, state, $1, $$, false)) {
+            YYERROR;
+         }
+      }
+   }
+   | layout_qualifier IN_TOK ';'
+   {
+      $$ = NULL;
+      if (!state->in_qualifier->
+             merge_in_qualifier(& @1, state, $1, $$, true)) {
          YYERROR;
       }
    }
    ;
 
 layout_out_defaults:
-   layout_qualifier OUT_TOK ';'
+   layout_qualifier layout_out_defaults
+   {
+      $$ = NULL;
+      if (!state->has_420pack_or_es31()) {
+         _mesa_glsl_error(&@1, state, "duplicate layout(...) qualifiers");
+         YYERROR;
+      } else {
+         if (!state->out_qualifier->
+                merge_out_qualifier(& @1, state, $1, $$, false)) {
+            YYERROR;
+         }
+      }
+   }
+   | layout_qualifier OUT_TOK ';'
    {
       $$ = NULL;
-      if (!state->out_qualifier->merge_out_qualifier(& @1, state, $1, $$))
+      if (!state->out_qualifier->
+             merge_out_qualifier(& @1, state, $1, $$, true))
          YYERROR;
    }
    ;