[Mesa-dev] [PATCH 33/34] glsl: Implement rules for geometry shader input sizes.

Paul Berry stereotype441 at gmail.com
Sun Jul 28 23:03:59 PDT 2013


Section 4.3.8.1 (Input Layout Qualifiers) of the GLSL 1.50 spec
contains some tricky rules for how the sizes of geometry shader input
arrays are related to the input layout specification.  In essence,
those rules boil down to the following:

- If an input array declaration does not specify a size, and it
  follows an input layout declaration, it is sized according to the
  input layout.

- If an input layout declaration follows an input array declaration
  that didn't specify a size, the input array declaration is given a
  size at the time the input layout declaration appears.

- All input layout declarations and input array sizes must ultimately
  match.  Inconsistencies are reported as soon as they are detected,
  at compile time if the inconsistency is within one compilation unit,
  otherwise at link time.

- At least one compilation unit must contain an input layout
  declaration.
---
 src/glsl/ast_to_hir.cpp       | 112 ++++++++++++++++++++++++++++++++++++++++++
 src/glsl/glsl_parser_extras.h |   9 ++++
 2 files changed, 121 insertions(+)

diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index 44399c6..a067f4e 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -2523,6 +2523,73 @@ process_initializer(ir_variable *var, ast_declaration *decl,
    return result;
 }
 
+
+/**
+ * Do additional processing necessary for geometry shader input array
+ * declarations (this covers both interface blocks arrays and input variable
+ * arrays).
+ */
+static void
+handle_geometry_shader_input_decl(struct _mesa_glsl_parse_state *state,
+                                  YYLTYPE loc, ir_variable *var)
+{
+   unsigned num_vertices = 0;
+   if (state->gs_input_prim_type_specified) {
+      num_vertices = vertices_per_prim(state->gs_input_prim_type);
+   }
+
+   assert(var->type->is_array());
+   if (var->type->length == 0) {
+      /* Section 4.3.8.1 (Input Layout Qualifiers) of the GLSL 1.50 spec says:
+       *
+       *   All geometry shader input unsized array declarations will be
+       *   sized by an earlier input layout qualifier, when present, as per
+       *   the following table.
+       *
+       * Followed by a table mapping each allowed input layout qualifier to
+       * the corresponding input length.
+       */
+      if (num_vertices != 0)
+         var->type = glsl_type::get_array_instance(var->type->fields.array,
+                                                   num_vertices);
+   } else {
+      /* Section 4.3.8.1 (Input Layout Qualifiers) of the GLSL 1.50 spec
+       * includes the following examples of compile-time errors:
+       *
+       *   // code sequence within one shader...
+       *   in vec4 Color1[];    // size unknown
+       *   ...Color1.length()...// illegal, length() unknown
+       *   in vec4 Color2[2];   // size is 2
+       *   ...Color1.length()...// illegal, Color1 still has no size
+       *   in vec4 Color3[3];   // illegal, input sizes are inconsistent
+       *   layout(lines) in;    // legal, input size is 2, matching
+       *   in vec4 Color4[3];   // illegal, contradicts layout
+       *   ...
+       *
+       * To detect the case illustrated by Color3, we verify that the size of
+       * an explicitly-sized array matches the size of any previously declared
+       * explicitly-sized array.  To detect the case illustrated by Color4, we
+       * verify that the size of an explicitly-sized array is consistent with
+       * any previously declared input layout.
+       */
+      if (num_vertices != 0 && var->type->length != num_vertices) {
+         _mesa_glsl_error(&loc, state,
+                          "geometry shader input size contradicts previously"
+                          " declared layout (size is %u, but layout requires a"
+                          " size of %u)", var->type->length, num_vertices);
+      } else if (state->gs_input_size != 0 &&
+                 var->type->length != state->gs_input_size) {
+         _mesa_glsl_error(&loc, state,
+                          "geometry shader input sizes are "
+                          "inconsistent (size is %u, but a previous "
+                          "declaration has size %u)",
+                          var->type->length, state->gs_input_size);
+      } else {
+         state->gs_input_size = var->type->length;
+      }
+   }
+}
+
 ir_rvalue *
 ast_declarator_list::hir(exec_list *instructions,
 			 struct _mesa_glsl_parse_state *state)
@@ -2834,6 +2901,8 @@ ast_declarator_list::hir(exec_list *instructions,
                _mesa_glsl_error(&loc, state,
                                 "geometry shader inputs must be arrays");
             }
+
+            handle_geometry_shader_input_decl(state, loc, var);
          }
       }
 
@@ -4437,6 +4506,8 @@ ast_interface_block::hir(exec_list *instructions,
       }
 
       var->interface_type = block_type;
+      if (state->target == geometry_shader)
+         handle_geometry_shader_input_decl(state, loc, var);
       state->symbols->add_variable(var);
       instructions->push_tail(var);
    } else {
@@ -4485,9 +4556,50 @@ ast_gs_input_layout::hir(exec_list *instructions,
       return NULL;
    }
 
+   /* If any shader inputs occurred before this declaration and specified an
+    * array size, make sure the size they specified is consistent with the
+    * primitive type.
+    */
+   unsigned num_vertices = vertices_per_prim(this->prim_type);
+   if (state->gs_input_size != 0 && state->gs_input_size != num_vertices) {
+      _mesa_glsl_error(&loc, state,
+                       "this geometry shader input layout implies %u vertices"
+                       " per primitive, but a previous input is declared"
+                       " with size %u", num_vertices, state->gs_input_size);
+      return NULL;
+   }
+
    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.
+    */
+   foreach_list (node, instructions) {
+      ir_variable *var = ((ir_instruction *) node)->as_variable();
+      if (var == NULL || var->mode != ir_var_shader_in)
+         continue;
+
+      /* Note: gl_PrimitiveIDIn has mode ir_var_shader_in, but it's not an
+       * array; skip it.
+       */
+      if (!var->type->is_array())
+         continue;
+
+      if (var->type->length == 0) {
+         if (var->max_array_access >= num_vertices) {
+            _mesa_glsl_error(&loc, state,
+                             "this geometry shader input layout implies %u"
+                             " vertices, but an access to element %u of input"
+                             " `%s' already exists", num_vertices,
+                             var->max_array_access, var->name);
+         } else {
+            var->type = glsl_type::get_array_instance(var->type->fields.array,
+                                                      num_vertices);
+         }
+      }
+   }
+
    return NULL;
 }
 
diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h
index fe662e8..9da292b 100644
--- a/src/glsl/glsl_parser_extras.h
+++ b/src/glsl/glsl_parser_extras.h
@@ -316,6 +316,15 @@ struct _mesa_glsl_parse_state {
    /** Shaders containing built-in functions that are used for linking. */
    struct gl_shader *builtins_to_link[16];
    unsigned num_builtins_to_link;
+
+   /**
+    * For geometry shaders, size of the most recently seen input declaration
+    * that was a sized array, or 0 if no sized input array declarations have
+    * been seen.
+    *
+    * Unused for other shader types.
+    */
+   unsigned gs_input_size;
 };
 
 # define YYLLOC_DEFAULT(Current, Rhs, N)			\
-- 
1.8.3.4



More information about the mesa-dev mailing list