[Mesa-dev] [PATCH 10/24] glsl: Implement parser support for atomic counters.

Ian Romanick idr at freedesktop.org
Wed Sep 18 08:23:47 PDT 2013


On 09/17/2013 03:51 PM, Paul Berry wrote:
> On 15 September 2013 00:10, Francisco Jerez <currojerez at riseup.net
> <mailto:currojerez at riseup.net>> wrote:
> 
>     ---
>      src/glsl/ast.h                | 15 ++++++++++
>      src/glsl/ast_to_hir.cpp       | 68
>     +++++++++++++++++++++++++++++++++++++++++--
>      src/glsl/ast_type.cpp         | 13 +++++++--
>      src/glsl/glsl_lexer.ll        |  2 +-
>      src/glsl/glsl_parser.yy       | 13 +++++++--
>      src/glsl/glsl_parser_extras.h | 10 +++++++
>      6 files changed, 114 insertions(+), 7 deletions(-)
> 
>     diff --git a/src/glsl/ast.h b/src/glsl/ast.h
>     index 26c4701..8a5d3fc 100644
>     --- a/src/glsl/ast.h
>     +++ b/src/glsl/ast.h
>     @@ -405,6 +405,12 @@ struct ast_type_qualifier {
>                */
>               unsigned explicit_binding:1;
> 
>     +         /**
>     +          * Flag set if GL_ARB_shader_atomic counter "offset" layout
>     +          * qualifier is used.
>     +          */
>     +         unsigned explicit_offset:1;
>     +
>               /** \name Layout qualifiers for GL_AMD_conservative_depth */
>               /** \{ */
>               unsigned depth_any:1;
>     @@ -468,6 +474,15 @@ struct ast_type_qualifier {
>         int binding;
> 
>         /**
>     +    * Offset specified via GL_ARB_shader_atomic_counter's "offset"
>     +    * keyword.
>     +    *
>     +    * \note
>     +    * This field is only valid if \c explicit_offset is set.
>     +    */
>     +   int offset;
>     +
>     +   /**
>          * Return true if and only if an interpolation qualifier is present.
>          */
>         bool has_interpolation() const;
>     diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
>     index fcca5df..7edbee4 100644
>     --- a/src/glsl/ast_to_hir.cpp
>     +++ b/src/glsl/ast_to_hir.cpp
>     @@ -1197,6 +1197,9 @@ ast_expression::hir(exec_list *instructions,
>                       !state->check_version(120, 300, &loc,
>                                             "array comparisons
>     forbidden")) {
>              error_emitted = true;
>     +      } else if ((op[0]->type->atomic_size() ||
>     op[1]->type->atomic_size())) {
>     +        _mesa_glsl_error(&loc, state, "atomic counter comparisons
>     forbidden");
>     +        error_emitted = true;
> 
> 
> Do we have spec text to back this up?  I looked around and couldn't find

Section 4.1.7 (Opaque Types) of the GLSL 4.40 spec says:

    "Except for array indexing, structure member selection, and
    parentheses, opaque variables are not allowed to be operands
    in expressions; such use results in a compile-time error."

We shouldn't allow comparisons of samplers either. :)

> anything.  It seems like doing equality comparisons on atomic counters
> is ill-defined, though (do two counters compare equal if they have equal
> values, or if they point to the same counter?  Both possibilities seem
> dodgy).  Maybe we should file a spec bug so we can get clarification
> from khronos about what's intended.
> 
> Note that we currently permit other comparisons that are similarly dodgy
> (e.g. comparing samplers).  It would be nice to get clarification from
> khronos about this too.

Given the above spec quote, I think the intention is clear.  We're just
doing the wrong thing.  I'm starting to feel better about my is_opaque /
contains_opaque predicate idea...

>            }
> 
>            if (error_emitted) {
>     @@ -1952,10 +1955,19 @@ validate_binding_qualifier(struct
>     _mesa_glsl_parse_state *state,
> 
>               return false;
>            }
>     +   } else if (var->type->atomic_size()) {
>     +      if (unsigned(qual->binding) >=
>     ctx->Const.MaxAtomicBufferBindings) {
>     +         _mesa_glsl_error(loc, state, "layout(binding = %d) exceeds
>     the "
>     +                          " maximum number of atomic counter buffer
>     bindings"
>     +                          "(%d)", qual->binding,
>     +                          ctx->Const.MaxAtomicBufferBindings);
>     +
>     +         return false;
>     +      }
>         } else {
>            _mesa_glsl_error(loc, state,
>                             "the \"binding\" qualifier only applies to
>     uniform "
>     -                       "blocks, samplers, or arrays of samplers");
>     +                       "blocks, samplers, atomic counters, or
>     arrays thereof");
>            return false;
>         }
> 
>     @@ -1983,7 +1995,7 @@ apply_type_qualifier_to_variable(const struct
>     ast_type_qualifier *qual,
>         }
> 
>         if (qual->flags.q.constant || qual->flags.q.attribute
>     -       || qual->flags.q.uniform
>     +       || (qual->flags.q.uniform && var->type !=
>     glsl_type::atomic_uint_type)
>             || (qual->flags.q.varying && (state->target ==
>     fragment_shader)))
>            var->read_only = 1;
> 
> 
> I'm not entirely convinced this is right.  An atomic counter, like a
> sampler, is a handle to an underlying object, not the underlying object
> itself.  The handle should be considered read-only even if the object it
> refers to is mutable.  That way we still prohibit

Yeah, I was going to say the same thing. :)

> uniform atomic_uint foo;
> uniform atomic_uint bar;
> void main() {
>    foo = bar;
> }
>  
> 
> 
>     @@ -2225,6 +2237,35 @@ apply_type_qualifier_to_variable(const struct
>     ast_type_qualifier *qual,
>            var->binding = qual->binding;
>         }
> 
>     +   if (var->type->atomic_size()) {
>     +      if (var->mode == ir_var_uniform) {
>     +         if (var->explicit_binding) {
>     +            _mesa_glsl_parse_state::atomic_counter_binding &binding =
>     +               state->atomic_counter_bindings[var->binding];
>     +
>     +            if (binding.next_offset % ATOMIC_COUNTER_SIZE)
>     +               _mesa_glsl_error(loc, state,
>     +                                "misaligned atomic counter offset");
>     +
>     +            if (binding.offsets.count(binding.next_offset))
>     +               _mesa_glsl_error(loc, state,
>     +                                "atomic counter offsets must be
>     unique");
> 
> 
> GLSL 4.20 clarifies that atomic counter offsets must be unique and
> non-overlapping (see GLSL 4.20 4.4.4.1 "Atomic Counter Layout
> Qualifiers").  So I tihnk we need a stronger check than this. 
> Specifically, declarations like the following should be disallowed:
> 
> layout(binding=0, offset=16) atomic_uint foo[4]; // Uses offsets 16, 20,
> 24, 28
> layout(binding=0, offset=20) atomic_uint bar; // Error: overlaps foo.

I also think this check belongs in the linker.  I don't see a lot of
value in doing it twice, and we have to verify atomics declared in other
compilation units.

>     +
>     +            var->atomic.offset = binding.next_offset;
>     +            binding.offsets.insert(binding.next_offset);
>     +            binding.next_offset += var->type->atomic_size();
>     +
>     +         } else {
>     +            _mesa_glsl_error(loc, state,
>     +                             "atomic counters require explicit
>     binding point");
>     +         }
>     +      } else if (var->mode != ir_var_function_in) {
>     +         _mesa_glsl_error(loc, state, "atomic counters may only be
>     declared as "
>     +                          "function parameters or uniform-qualified "
>     +                          "global variables");
>     +      }
>     +   }
>     +
>         /* Does the declaration use the deprecated 'attribute' or 'varying'
>          * keywords?
>          */
>     @@ -2725,6 +2766,18 @@ ast_declarator_list::hir(exec_list *instructions,
>         (void) this->type->specifier->hir(instructions, state);
> 
>         decl_type = this->type->glsl_type(& type_name, state);
>     +
>     +   /* An offset-qualified atomic counter declaration sets the default
>     +    * offset for the next declaration within the same atomic counter
>     +    * buffer.
>     +    */
>     +   if (decl_type && decl_type->atomic_size()) {
>     +      if (type->qualifier.flags.q.explicit_binding &&
>     +          type->qualifier.flags.q.explicit_offset)
>     +         state->atomic_counter_bindings[type->qualifier.binding]
>     +            .next_offset = type->qualifier.offset;
>     +   }
>     +
>         if (this->declarations.is_empty()) {
>            /* If there is no structure involved in the program text,
>     there are two
>             * possible scenarios:
>     @@ -2754,6 +2807,11 @@ ast_declarator_list::hir(exec_list *instructions,
>               _mesa_glsl_error(&loc, state,
>                                "invalid type `%s' in empty declaration",
>                                type_name);
>     +      } else if (decl_type->base_type == GLSL_TYPE_ATOMIC_UINT) {
>     +         /* Empty atomic counter declarations are allowed and useful
>     +          * to set the default offset qualifier.
>     +          */
>     +         return NULL;
>            } else if (this->type->qualifier.precision !=
>     ast_precision_none) {
>               if (this->type->specifier->structure != NULL) {
>                  _mesa_glsl_error(&loc, state,
>     @@ -4475,6 +4533,12 @@
>     ast_process_structure_or_interface_block(exec_list *instructions,
>                                   "uniform in non-default uniform block
>     contains sampler");
>               }
> 
>     +         if (field_type->atomic_size()) {
>     +            YYLTYPE loc = decl_list->get_location();
>     +            _mesa_glsl_error(&loc, state, "atomic counter in
>     structure or "
>     +                             "uniform block");
>     +         }
>     +
> 
> Are you sure this is not allowed?  I can't find any spec text to back
> this up.  All I found was this text from ARB_shader_atomic_counters:

Yeah, this is definitely wrong.  See the text I quoted in reply to patch
8.  However, opaque types are not allowed in uniform blocks.  Section
4.3.9 (Interface Blocks) of the GLSL 4.40 spec specifically calls that out:

    "Types and declarators are the same as for other input, output,
    uniform, and buffer variable declarations outside blocks, with
    these exceptions:

        • initializers are not allowed
        • opaque types are not allowed
        • structure definitions cannot be nested inside a block"

> "Except for array indexing, structure field selection, and parenthesis,
> counters are not allowed to be operands in expressions."
> 
> Which would seem to imply that atomic counters *are* allowed as
> structure fields.
>  
> 
>               const struct ast_type_qualifier *const qual =
>                  & decl_list->type->qualifier;
>               if (qual->flags.q.std140 ||
>     diff --git a/src/glsl/ast_type.cpp b/src/glsl/ast_type.cpp
>     index 8aabd95..2b088bf 100644
>     --- a/src/glsl/ast_type.cpp
>     +++ b/src/glsl/ast_type.cpp
>     @@ -72,7 +72,8 @@ ast_type_qualifier::has_layout() const
>                || this->flags.q.packed
>                || this->flags.q.explicit_location
>                || this->flags.q.explicit_index
>     -          || this->flags.q.explicit_binding;
>     +          || this->flags.q.explicit_binding
>     +          || this->flags.q.explicit_offset;
>      }
> 
>      bool
>     @@ -121,13 +122,18 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
>         ubo_layout_mask.flags.q.packed = 1;
>         ubo_layout_mask.flags.q.shared = 1;
> 
>     +   ast_type_qualifier ubo_binding_mask;
>     +   ubo_binding_mask.flags.q.explicit_binding = 1;
>     +   ubo_binding_mask.flags.q.explicit_offset = 1;
>     +
>         /* Uniform block layout qualifiers get to overwrite each
>          * other (rightmost having priority), while all other
>          * qualifiers currently don't allow duplicates.
>          */
> 
>         if ((this->flags.i & q.flags.i & ~(ubo_mat_mask.flags.i |
>     -                                     ubo_layout_mask.flags.i)) != 0) {
>     +                                     ubo_layout_mask.flags.i |
>     +                                      ubo_binding_mask.flags.i)) !=
>     0) {
>            _mesa_glsl_error(loc, state,
>                            "duplicate layout qualifiers used");
>            return false;
>     @@ -168,6 +174,9 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
>         if (q.flags.q.explicit_binding)
>            this->binding = q.binding;
> 
>     +   if (q.flags.q.explicit_offset)
>     +      this->offset = q.offset;
>     +
>         if (q.precision != ast_precision_none)
>            this->precision = q.precision;
> 
>     diff --git a/src/glsl/glsl_lexer.ll b/src/glsl/glsl_lexer.ll
>     index e24df80..822d70d 100644
>     --- a/src/glsl/glsl_lexer.ll
>     +++ b/src/glsl/glsl_lexer.ll
>     @@ -337,6 +337,7 @@ samplerExternalOES          {
>                                  return IDENTIFIER;
>                     }
> 
>     +atomic_uint     KEYWORD_WITH_ALT(420, 300, 420, 0,
>     yyextra->ARB_shader_atomic_counters_enable, ATOMIC_UINT);
> 
>      struct         return STRUCT;
>      void           return VOID_TOK;
>     @@ -518,7 +519,6 @@ restrict    KEYWORD(0, 300, 0, 0, RESTRICT);
>      readonly       KEYWORD(0, 300, 0, 0, READONLY);
>      writeonly      KEYWORD(0, 300, 0, 0, WRITEONLY);
>      resource       KEYWORD(0, 300, 0, 0, RESOURCE);
>     -atomic_uint    KEYWORD(0, 300, 0, 0, ATOMIC_UINT);
>      patch          KEYWORD(0, 300, 0, 0, PATCH);
>      sample         KEYWORD(0, 300, 0, 0, SAMPLE);
>      subroutine     KEYWORD(0, 300, 0, 0, SUBROUTINE);
>     diff --git a/src/glsl/glsl_parser.yy b/src/glsl/glsl_parser.yy
>     index fa6e205..b9498b4 100644
>     --- a/src/glsl/glsl_parser.yy
>     +++ b/src/glsl/glsl_parser.yy
>     @@ -118,6 +118,7 @@ _mesa_glsl_lex(YYSTYPE *val, YYLTYPE *loc,
>     _mesa_glsl_parse_state *state)
>      %token SAMPLER2DMS ISAMPLER2DMS USAMPLER2DMS
>      %token SAMPLER2DMSARRAY ISAMPLER2DMSARRAY USAMPLER2DMSARRAY
>      %token SAMPLEREXTERNALOES
>     +%token ATOMIC_UINT
>      %token STRUCT VOID_TOK WHILE
>      %token <identifier> IDENTIFIER TYPE_IDENTIFIER NEW_IDENTIFIER
>      %type <identifier> any_identifier
>     @@ -147,7 +148,7 @@ _mesa_glsl_lex(YYSTYPE *val, YYLTYPE *loc,
>     _mesa_glsl_parse_state *state)
>      %token HVEC2 HVEC3 HVEC4 DVEC2 DVEC3 DVEC4 FVEC2 FVEC3 FVEC4
>      %token SAMPLER3DRECT
>      %token SIZEOF CAST NAMESPACE USING
>     -%token COHERENT RESTRICT READONLY WRITEONLY RESOURCE ATOMIC_UINT
>     PATCH SAMPLE
>     +%token COHERENT RESTRICT READONLY WRITEONLY RESOURCE PATCH SAMPLE
>      %token SUBROUTINE
> 
>      %token ERROR_TOK
>     @@ -1288,12 +1289,19 @@ layout_qualifier_id:
>               }
>            }
> 
>     -      if (state->ARB_shading_language_420pack_enable &&
>     +      if ((state->ARB_shading_language_420pack_enable ||
>     +           state->ARB_shader_atomic_counters_enable) &&
>                strcmp("binding", $1) == 0) {
>               $$.flags.q.explicit_binding = 1;
>               $$.binding = $3;
>            }
> 
>     +      if (state->ARB_shader_atomic_counters_enable &&
>     +          strcmp("offset", $1) == 0) {
>     +         $$.flags.q.explicit_offset = 1;
>     +         $$.offset = $3;
>     +      }
>     +
>            if (strcmp("max_vertices", $1) == 0) {
>               $$.flags.q.max_vertices = 1;
> 
>     @@ -1663,6 +1671,7 @@ basic_type_specifier_nonarray:
>         | SAMPLER2DMSARRAY       { $$ = "sampler2DMSArray"; }
>         | ISAMPLER2DMSARRAY      { $$ = "isampler2DMSArray"; }
>         | USAMPLER2DMSARRAY      { $$ = "usampler2DMSArray"; }
>     +   | ATOMIC_UINT            { $$ = "atomic_uint"; }
>         ;
> 
>      precision_qualifier:
>     diff --git a/src/glsl/glsl_parser_extras.h
>     b/src/glsl/glsl_parser_extras.h
>     index 4ffbf8f..d0e131a 100644
>     --- a/src/glsl/glsl_parser_extras.h
>     +++ b/src/glsl/glsl_parser_extras.h
>     @@ -31,6 +31,8 @@
>      #ifdef __cplusplus
> 
> 
>     +#include <map>
>     +#include <set>
>      #include <stdlib.h>
>      #include "glsl_symbol_table.h"
> 
>     @@ -331,6 +333,14 @@ struct _mesa_glsl_parse_state {
>          * Unused for other shader types.
>          */
>         unsigned gs_input_size;
>     +
>     +   struct atomic_counter_binding {
>     +      atomic_counter_binding() : offsets(), next_offset(0) {}
>     +      std::set<unsigned> offsets;
>     +      unsigned next_offset;
>     +   };
>     +
>     +   std::map<unsigned, atomic_counter_binding> atomic_counter_bindings;
>      };
> 
>      # define YYLLOC_DEFAULT(Current, Rhs, N)                       \
>     --
>     1.8.3.4
> 
>     _______________________________________________
>     mesa-dev mailing list
>     mesa-dev at lists.freedesktop.org <mailto:mesa-dev at lists.freedesktop.org>
>     http://lists.freedesktop.org/mailman/listinfo/mesa-dev
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev



More information about the mesa-dev mailing list