glsl: Implement parser support for atomic counters.
authorFrancisco Jerez <currojerez@riseup.net>
Sun, 20 Oct 2013 19:38:07 +0000 (12:38 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Thu, 7 Nov 2013 23:56:57 +0000 (15:56 -0800)
v2: Mark atomic counters as read-only variables.  Move offset overlap
    code to the linker.  Use the contains_atomic() convenience method.
v3: Use pointer to integer instead of non-const reference.  Add
    comment so we remember to add a spec quotation from the next GLSL
    release once the issue of atomic counter aggregation within
    structures is clarified.
v4 (idr): Don't use std::map because it's overkill.  Add an assertion
    that ctx->Const.MaxAtomicBufferBindings <= MAX_COMBINED_ATOMIC_BUFFERS.

Signed-off-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Paul Berry <stereotype441@gmail.com>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
src/glsl/ast.h
src/glsl/ast_to_hir.cpp
src/glsl/ast_type.cpp
src/glsl/glsl_lexer.ll
src/glsl/glsl_parser.yy
src/glsl/glsl_parser_extras.h

index 97905c6a6d1dde2a463d898283e858b4efb29603..5c214b6043b7b9043ea6e9d8c5eb6ead8533f50d 100644 (file)
@@ -385,6 +385,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;
@@ -447,6 +453,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.
     */
index f75e68ce1929cdf95dcce5b294572d4a9daf2481..76b256c731ad9b9ac4aab70563ce6c208e89e72d 100644 (file)
@@ -1995,12 +1995,22 @@ validate_binding_qualifier(struct _mesa_glsl_parse_state *state,
                           "exceeds the maximum number of texture image units "
                           "(%d)", qual->binding, elements, limit);
 
+         return false;
+      }
+   } else if (var->type->contains_atomic()) {
+      assert(ctx->Const.MaxAtomicBufferBindings <= MAX_COMBINED_ATOMIC_BUFFERS);
+      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;
    }
 
@@ -2300,6 +2310,29 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
       var->binding = qual->binding;
    }
 
+   if (var->type->contains_atomic()) {
+      if (var->mode == ir_var_uniform) {
+         if (var->explicit_binding) {
+            unsigned *offset = &state->atomic_counter_offsets[var->binding];
+
+            if (*offset % ATOMIC_COUNTER_SIZE)
+               _mesa_glsl_error(loc, state,
+                                "misaligned atomic counter offset");
+
+            var->atomic.offset = *offset;
+            *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?
     */
@@ -2835,6 +2868,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->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;
+   }
+
    if (this->declarations.is_empty()) {
       /* If there is no structure involved in the program text, there are two
        * possible scenarios:
@@ -2864,6 +2909,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,
@@ -4565,6 +4615,17 @@ ast_process_structure_or_interface_block(exec_list *instructions,
                              "uniform in non-default uniform block contains sampler");
          }
 
+         if (field_type->contains_atomic()) {
+            /* FINISHME: Add a spec quotation here once updated spec
+             * FINISHME: language is available.  See Khronos bug #10903
+             * FINISHME: on whether atomic counters are allowed in
+             * FINISHME: structures.
+             */
+            YYLTYPE loc = decl_list->get_location();
+            _mesa_glsl_error(&loc, state, "atomic counter in structure or "
+                             "uniform block");
+         }
+
          const struct ast_type_qualifier *const qual =
             & decl_list->type->qualifier;
          if (qual->flags.q.std140 ||
index 8aabd95f999c59d1039435c93c7423b48f7df53a..2b088bf8b855b23fa2efe058febbbb50240060c4 100644 (file)
@@ -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;
 
index e24df8096c38b67a24256f5916f68c274c2af684..822d70d6b66e71bb92bb7c2c6ae3913a6a32fcba 100644 (file)
@@ -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);
index 14420f8a36c4c195236e5a3abac54b835e94cb36..ada3690f609093a8d8097da4c2547cfe29a2f47c 100644 (file)
@@ -144,6 +144,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2,
 %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
@@ -173,7 +174,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2,
 %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
@@ -1324,12 +1325,19 @@ layout_qualifier_id:
          }
       }
 
-      if (state->ARB_shading_language_420pack_enable &&
+      if ((state->ARB_shading_language_420pack_enable ||
+           state->ARB_shader_atomic_counters_enable) &&
           match_layout_qualifier("binding", $1, state) == 0) {
          $$.flags.q.explicit_binding = 1;
          $$.binding = $3;
       }
 
+      if (state->ARB_shader_atomic_counters_enable &&
+          match_layout_qualifier("offset", $1, state) == 0) {
+         $$.flags.q.explicit_offset = 1;
+         $$.offset = $3;
+      }
+
       if (match_layout_qualifier("max_vertices", $1, state) == 0) {
          $$.flags.q.max_vertices = 1;
 
@@ -1703,6 +1711,7 @@ basic_type_specifier_nonarray:
    | SAMPLER2DMSARRAY       { $$ = "sampler2DMSArray"; }
    | ISAMPLER2DMSARRAY      { $$ = "isampler2DMSArray"; }
    | USAMPLER2DMSARRAY      { $$ = "usampler2DMSArray"; }
+   | ATOMIC_UINT            { $$ = "atomic_uint"; }
    ;
 
 precision_qualifier:
index 345d7a0187ed33cad3794d29b94096d22c9b7fce..d232bb3f66dee6e391f098ab6b9aee918f5953d6 100644 (file)
@@ -373,6 +373,9 @@ struct _mesa_glsl_parse_state {
     * Unused for other shader types.
     */
    unsigned gs_input_size;
+
+   /** Atomic counter offsets by binding */
+   unsigned atomic_counter_offsets[MAX_COMBINED_ATOMIC_BUFFERS];
 };
 
 # define YYLLOC_DEFAULT(Current, Rhs, N)                       \