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

Ian Romanick idr at freedesktop.org
Wed Jul 31 18:05:29 PDT 2013


On 07/28/2013 11:03 PM, Paul Berry wrote:
> 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.

Some later GLSL specs "clarify" that some errors are generated at 
different times.  I use scare quotes because, in reality, the spec was 
just changed to match shipping implementations.  It would be worth 
checking this last statement against the 4.30 or 4.40 spec.

> - 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
                                                block
> + * 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)			\
>



More information about the mesa-dev mailing list