glsl: convert GS input primitive to use ast_type_qualifier
authorJordan Justen <jordan.l.justen@intel.com>
Mon, 3 Feb 2014 01:49:15 +0000 (17:49 -0800)
committerJordan Justen <jordan.l.justen@intel.com>
Thu, 20 Feb 2014 18:33:08 +0000 (10:33 -0800)
We introduce a new merge_in_qualifier ast_type_qualifier
which allows specialized handling of merging input layout
qualifiers.

By merging layout qualifiers into state->in_qualifier, we
allow multiple input qualifiers. For example, the primitive
type can be specified specified separately from the
invocations count (ARB_gpu_shader5).

state->gs_input_prim_type is moved into state->in_qualifier->prim_type

state->gs_input_prim_type_specified is still processed separately
so we can determine when the input primitive is specified. This
is important since certain scenerios are not supported until after
the primitive type has been specified in the shader code.

v4:
 * Merge with compute shader input layout qualifiers

Signed-off-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Anuj Phogat <anuj.phogat@gmail.com>
src/glsl/ast.h
src/glsl/ast_to_hir.cpp
src/glsl/ast_type.cpp
src/glsl/glsl_parser.yy
src/glsl/glsl_parser_extras.cpp
src/glsl/glsl_parser_extras.h

index 9140ca13cdae5e07e1b52200542c462620ed1a13..c4f28b0cc90f7223149c78f501961246a843978e 100644 (file)
@@ -587,6 +587,12 @@ struct ast_type_qualifier {
    bool merge_qualifier(YYLTYPE *loc,
                        _mesa_glsl_parse_state *state,
                        ast_type_qualifier q);
+
+   bool merge_in_qualifier(YYLTYPE *loc,
+                           _mesa_glsl_parse_state *state,
+                           ast_type_qualifier q,
+                           ast_node* &node);
+
 };
 
 class ast_declarator_list;
index e731d839d2a7a8dae26cc06ea5550ece5f223574..f754652dc9c17597c775ef29d077aee89c89c15d 100644 (file)
@@ -2842,7 +2842,7 @@ handle_geometry_shader_input_decl(struct _mesa_glsl_parse_state *state,
 {
    unsigned num_vertices = 0;
    if (state->gs_input_prim_type_specified) {
-      num_vertices = vertices_per_prim(state->gs_input_prim_type);
+      num_vertices = vertices_per_prim(state->in_qualifier->prim_type);
    }
 
    /* Geometry shader input variables must be arrays.  Caller should have
@@ -5332,7 +5332,7 @@ ast_gs_input_layout::hir(exec_list *instructions,
     * was consistent with this one.
     */
    if (state->gs_input_prim_type_specified &&
-       state->gs_input_prim_type != this->prim_type) {
+       state->in_qualifier->prim_type != this->prim_type) {
       _mesa_glsl_error(&loc, state,
                        "geometry shader input layout does not match"
                        " previous declaration");
@@ -5353,7 +5353,6 @@ ast_gs_input_layout::hir(exec_list *instructions,
    }
 
    state->gs_input_prim_type_specified = true;
-   state->gs_input_prim_type = this->prim_type;
 
    /* If any shader inputs occurred before this declaration and did not
     * specify an array size, their size is determined now.
index 200566c6d3fb87b5f4e793123982a70510b4a025..2f36cf43c11f0669b6ab791e3fc2399421588973 100644 (file)
@@ -198,3 +198,84 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
    return true;
 }
 
+bool
+ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
+                                       _mesa_glsl_parse_state *state,
+                                       ast_type_qualifier q,
+                                       ast_node* &node)
+{
+   void *mem_ctx = state;
+   bool create_gs_ast = false;
+   bool create_cs_ast = false;
+
+   switch (state->stage) {
+   case MESA_SHADER_GEOMETRY:
+      if (q.flags.q.prim_type) {
+         /* Make sure this is a valid input primitive type. */
+         switch (q.prim_type) {
+         case GL_POINTS:
+         case GL_LINES:
+         case GL_LINES_ADJACENCY:
+         case GL_TRIANGLES:
+         case GL_TRIANGLES_ADJACENCY:
+            break;
+         default:
+            _mesa_glsl_error(loc, state,
+                             "invalid geometry shader input primitive type");
+            break;
+         }
+      }
+
+      create_gs_ast |=
+         q.flags.q.prim_type &&
+         !state->in_qualifier->flags.q.prim_type;
+      break;
+   case MESA_SHADER_FRAGMENT:
+      if (q.flags.q.early_fragment_tests) {
+         state->early_fragment_tests = true;
+      } else {
+         _mesa_glsl_error(loc, state, "invalid input layout qualifier");
+      }
+      break;
+   case MESA_SHADER_COMPUTE:
+      create_cs_ast |=
+         q.flags.q.local_size != 0 &&
+         state->in_qualifier->flags.q.local_size == 0;
+      break;
+   default:
+      _mesa_glsl_error(loc, state,
+                       "input layout qualifiers only valid in "
+                       "geometry, fragment and compute shaders");
+      break;
+   }
+
+   /* Input layout qualifiers can be specified multiple
+    * times in separate declarations, as long as they match.
+    */
+   if (this->flags.q.prim_type) {
+      if (q.flags.q.prim_type &&
+          this->prim_type != q.prim_type) {
+         _mesa_glsl_error(loc, state,
+                          "conflicting input primitive types specified");
+      }
+   } else if (q.flags.q.prim_type) {
+      state->in_qualifier->flags.q.prim_type = 1;
+      state->in_qualifier->prim_type = q.prim_type;
+   }
+
+   if (create_gs_ast) {
+      node = new(mem_ctx) ast_gs_input_layout(*loc, q.prim_type);
+   } else if (create_cs_ast) {
+      /* Infer a local_size of 1 for every unspecified dimension */
+      unsigned local_size[3];
+      for (int i = 0; i < 3; i++) {
+         if (q.flags.q.local_size & (1 << i))
+            local_size[i] = q.local_size[i];
+         else
+            local_size[i] = 1;
+      }
+      node = new(mem_ctx) ast_cs_input_layout(*loc, local_size);
+   }
+
+   return true;
+}
index 369da5034d6bc23077b57cbee67787089fbac003..c3fa4555e14c92de5b5abc5d15b91f335e86a754 100644 (file)
@@ -2487,62 +2487,9 @@ layout_defaults:
 
    | layout_qualifier IN_TOK ';'
    {
-      void *ctx = state;
       $$ = NULL;
-      switch (state->stage) {
-      case MESA_SHADER_GEOMETRY: {
-         if (!$1.flags.q.prim_type) {
-            _mesa_glsl_error(& @1, state,
-                             "input layout qualifiers must specify a primitive"
-                             " type");
-         } else {
-            /* Make sure this is a valid input primitive type. */
-            switch ($1.prim_type) {
-            case GL_POINTS:
-            case GL_LINES:
-            case GL_LINES_ADJACENCY:
-            case GL_TRIANGLES:
-            case GL_TRIANGLES_ADJACENCY:
-               $$ = new(ctx) ast_gs_input_layout(@1, $1.prim_type);
-               break;
-            default:
-               _mesa_glsl_error(&@1, state,
-                                "invalid geometry shader input primitive type");
-               break;
-            }
-         }
-      }
-         break;
-      case MESA_SHADER_FRAGMENT:
-         if ($1.flags.q.early_fragment_tests) {
-            state->early_fragment_tests = true;
-         } else {
-            _mesa_glsl_error(& @1, state, "invalid input layout qualifier");
-         }
-         break;
-      case MESA_SHADER_COMPUTE: {
-         if ($1.flags.q.local_size == 0) {
-            _mesa_glsl_error(& @1, state,
-                             "input layout qualifiers must specify a local "
-                             "size");
-         } else {
-            /* Infer a local_size of 1 for every unspecified dimension */
-            unsigned local_size[3];
-            for (int i = 0; i < 3; i++) {
-               if ($1.flags.q.local_size & (1 << i))
-                  local_size[i] = $1.local_size[i];
-               else
-                  local_size[i] = 1;
-            }
-            $$ = new(ctx) ast_cs_input_layout(@1, local_size);
-         }
-      }
-         break;
-      default:
-         _mesa_glsl_error(& @1, state,
-                          "input layout qualifiers only valid in "
-                          "geometry, fragment and compute shaders");
-         break;
+      if (!state->in_qualifier->merge_in_qualifier(& @1, state, $1, $$)) {
+         YYERROR;
       }
    }
 
index 901124d2c396033b4941fc5cd46644668ade49d8..f102b11bc6d70d5f440fdb1f55b7ff86a6b2f6bb 100644 (file)
@@ -202,8 +202,8 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
    this->default_uniform_qualifier->flags.q.column_major = 1;
 
    this->gs_input_prim_type_specified = false;
-   this->gs_input_prim_type = GL_POINTS;
    this->gs_input_size = 0;
+   this->in_qualifier = new(this) ast_type_qualifier();
    this->out_qualifier = new(this) ast_type_qualifier();
    this->early_fragment_tests = false;
    memset(this->atomic_counter_offsets, 0,
@@ -1348,7 +1348,7 @@ set_shader_inout_layout(struct gl_shader *shader,
 {
    if (shader->Stage != MESA_SHADER_GEOMETRY) {
       /* Should have been prevented by the parser. */
-      assert(!state->gs_input_prim_type_specified);
+      assert(!state->in_qualifier->flags.i);
       assert(!state->out_qualifier->flags.i);
    }
 
@@ -1364,7 +1364,7 @@ set_shader_inout_layout(struct gl_shader *shader,
          shader->Geom.VerticesOut = state->out_qualifier->max_vertices;
 
       if (state->gs_input_prim_type_specified) {
-         shader->Geom.InputType = state->gs_input_prim_type;
+         shader->Geom.InputType = state->in_qualifier->prim_type;
       } else {
          shader->Geom.InputType = PRIM_UNKNOWN;
       }
index ad4ef0146874e124fccd565fd171f1bb269bac28..d98474e65723fb62ad8ed54940fb156391fb9478 100644 (file)
@@ -190,11 +190,8 @@ struct _mesa_glsl_parse_state {
     */
    bool gs_input_prim_type_specified;
 
-   /**
-    * If gs_input_prim_type_specified is true, the primitive type that was
-    * specified.  Otherwise ignored.
-    */
-   GLenum gs_input_prim_type;
+   /** Input layout qualifiers from GLSL 1.50. (geometry shader controls)*/
+   struct ast_type_qualifier *in_qualifier;
 
    /**
     * True if a compute shader input local size was specified using a layout