[Mesa-dev] [PATCH V2 10/12] glsl: add support for complie-time constant expressions

Emil Velikov emil.l.velikov at gmail.com
Tue Nov 10 05:43:15 PST 2015


Hi Tim,

Mostly trivial suggestions, and one bug caught :-)

On 8 November 2015 at 22:34, Timothy Arceri <t_arceri at yahoo.com.au> wrote:
> From: Timothy Arceri <timothy.arceri at collabora.com>
>
> This patch replaces the old interger constant qualifiers with either
typo "integer"
> the new ast_layout_expression type if the qualifier requires merging
> or ast_expression if the qualifier can't have mulitple declorations
"multiple declarations"

> or if all but he newest qualifier is simply ignored.
>
> This also remove the location field that was temporarily added to
> ast_type_qualifier to keep track of the parser location.
> ---
>  src/glsl/ast.h                  |  33 +++---
>  src/glsl/ast_to_hir.cpp         | 253 +++++++++++++++++++++++++---------------
>  src/glsl/ast_type.cpp           |  81 +++++--------
>  src/glsl/glsl_parser.yy         |  25 ++--
>  src/glsl/glsl_parser_extras.cpp |  43 ++++---
>  5 files changed, 236 insertions(+), 199 deletions(-)
>
> diff --git a/src/glsl/ast.h b/src/glsl/ast.h
> index ef94cff..4fd049c 100644
> --- a/src/glsl/ast.h
> +++ b/src/glsl/ast.h

> @@ -1156,9 +1150,10 @@ private:
>  class ast_cs_input_layout : public ast_node
>  {
>  public:
> -   ast_cs_input_layout(const struct YYLTYPE &locp, const unsigned *local_size)
> +   ast_cs_input_layout(const struct YYLTYPE &locp,
> +                       ast_layout_expression **local_size)
>     {
> -      memcpy(this->local_size, local_size, sizeof(this->local_size));
> +      memcpy(this->local_size, *local_size, sizeof(this->local_size));
While we do use this in other places in mesa it's quite a bit of abuse
of C++. This will involve setting new[] (template) overrides which use
ralloc and using them. Obviously not part of this patch, but more of a
FYI.


> --- a/src/glsl/ast_to_hir.cpp
> +++ b/src/glsl/ast_to_hir.cpp

> @@ -2467,11 +2463,11 @@ validate_explicit_location(const struct ast_type_qualifier *qual,
>                             YYLTYPE *loc)
>  {
>     bool fail = false;
> +   unsigned qual_location;
>
> -   if (qual->location < 0) {
> -       _mesa_glsl_error(loc, state, "invalid location %d specified",
> -                        qual->location);
> -       return;
> +   if (!process_qualifier_constant(state, loc, "location",
> +                                   qual->location, &qual_location, 0)) {
> +      return;
Most/all(?) other places have their process() in the caller, rather
than in validate().


> @@ -2620,22 +2616,30 @@ validate_layout_qualifiers(const struct ast_type_qualifier *qual,
>            * Older specifications don't mandate a behavior; we take
>            * this as a clarification and always generate the error.
>            */
> -         if (qual->index < 0 || qual->index > 1) {
> +         unsigned qual_index;
> +         if (process_qualifier_constant(state, loc, "index",
> +                                        qual->index, &qual_index, 0) &&
> +             qual_index > 1) {
>              _mesa_glsl_error(loc, state,
>                               "explicit index may only be 0 or 1");
>           } else {
>              var->data.explicit_index = true;
> -            var->data.index = qual->index;
> +            var->data.index = qual_index;
This looks wrong. I recommend splitting out the process and validate
steps. Yes the latter is trivial yet enough to catch you here.

Namely:
Currently we assign garbage into data.index even if process() fails.


> @@ -2839,7 +2843,12 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
>
>     if (state->stage == MESA_SHADER_GEOMETRY &&
>         qual->flags.q.out && qual->flags.q.stream) {
Not 100% sure but I'm leaning that we checking
has_explicit_attrib_stream(), or flags.q.explicit_stream. Based
(biased:P) on what other places do. Obviously not meant to be part of
this patch.

> -      var->data.stream = qual->stream;
> +      unsigned qual_stream;
> +      if (process_qualifier_constant(state, loc, "stream", qual->stream,
> +                                     &qual_stream, 0)) {
> +         validate_stream_qualifier(loc, state, qual_stream);
There are various approaches of using the process/validate combo in this patch.

Imho it's worth adding a comment when we can ignore skip validate,
and/or ignore its return value.


> @@ -3598,15 +3607,16 @@ static void
>  handle_tess_ctrl_shader_output_decl(struct _mesa_glsl_parse_state *state,
>                                      YYLTYPE loc, ir_variable *var)
>  {
> -   int num_vertices = 0;
> +   unsigned num_vertices = 0;
>
>     if (state->tcs_output_vertices_specified) {
> -      num_vertices = state->out_qualifier->vertices;
> -      if (num_vertices <= 0) {
> -         _mesa_glsl_error(&loc, state, "invalid vertices (%d) specified",
> -                          num_vertices);
> +      if (!state->out_qualifier->vertices->
> +             process_qualifier_constant(state, "vertices",
> +                                        &num_vertices, 0)) {
Off by one ? Original code checks for <= 0 while process() will does <
0. Although on second thought the num_vertices == 0 || num_vertices >
MaxFoo is a validation stage, so we might want to keep it below.

>           return;
> -      } else if ((unsigned) num_vertices > state->Const.MaxPatchVertices) {
> +      }
> +
> +      if (num_vertices > state->Const.MaxPatchVertices) {
>           _mesa_glsl_error(&loc, state, "vertices (%d) exceeds "
>                            "GL_MAX_PATCH_VERTICES", num_vertices);
>           return;

> @@ -3881,9 +3890,19 @@ ast_declarator_list::hir(exec_list *instructions,
>      */
>     if (decl_type && decl_type->contains_atomic()) {
>        if (type->qualifier.flags.q.explicit_binding &&
> -          type->qualifier.flags.q.explicit_offset)
> -         state->atomic_counter_offsets[type->qualifier.binding] =
> -            type->qualifier.offset;
> +          type->qualifier.flags.q.explicit_offset) {
> +         unsigned qual_binding;
> +         if (process_qualifier_constant(state, &loc, "binding",
> +                                        type->qualifier.binding,
> +                                        &qual_binding, 0)) {
> +            unsigned qual_offset;
> +            if (process_qualifier_constant(state, &loc, "offset",
> +                                           type->qualifier.offset,
> +                                           &qual_offset, 0)) {
Bikeshed: declare both variables and combine the process(binding) &&
process(offset) into a single if ?


> @@ -6011,8 +6040,12 @@ ast_process_structure_or_interface_block(exec_list *instructions,
>           const struct ast_type_qualifier *const qual =
>              & decl_list->type->qualifier;
>
> -         if (qual->flags.q.explicit_binding)
> -            validate_binding_qualifier(state, &loc, decl_type, qual);
> +         unsigned qual_binding;
> +         if (qual->flags.q.explicit_binding &&
> +             process_qualifier_constant(state, &loc, "binding",
> +                                        qual->binding, &qual_binding, 0))
Bikeshed: might want to keep the following pattern, or not as long as
it's consistent throughout :)

if (flag)
  unsigned qual_foo
  if (process(foo))
     validate(foo)


> +            validate_binding_qualifier(state, &loc, decl_type,
> +                                       qual, qual_binding);
>
>           if (qual->flags.q.std140 ||
>               qual->flags.q.std430 ||
> @@ -6050,12 +6083,17 @@ ast_process_structure_or_interface_block(exec_list *instructions,
>            *   the specified stream must match the stream associated with the
>            *   containing block."
>            */
> -         if (qual->flags.q.explicit_stream &&
> -             qual->stream != layout->stream) {
> -            _mesa_glsl_error(&loc, state, "stream layout qualifier on "
> -                             "interface block member `%s' does not match "
> -                             "the interface block (%d vs %d)",
> -                             fields[i].name, qual->stream, layout->stream);
> +         if (qual->flags.q.explicit_stream && block_stream_processed) {
> +            unsigned qual_stream;
> +            if (process_qualifier_constant(state, &loc, "stream",
> +                                           qual->stream, &qual_stream, 0)) {
> +               if (qual_stream != *block_stream) {
> +                  _mesa_glsl_error(&loc, state, "stream layout qualifier on "
> +                                   "interface block member `%s' does not "
> +                                   "match the interface block (%d vs %d)",
> +                                   fields[i].name, qual_stream, *block_stream);
> +               }
> +            }
Was going to say "hey
ast_layout_expression::process_qualifier_constant() already does that
for you" only to realise that it deals with a linked list, while we
have an array. Shame we cannot reuse it :(


More information about the mesa-dev mailing list