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

Timothy Arceri t_arceri at yahoo.com.au
Sun Nov 8 14:34:39 PST 2015


From: Timothy Arceri <timothy.arceri at collabora.com>

This patch replaces the old interger constant qualifiers with either
the new ast_layout_expression type if the qualifier requires merging
or ast_expression if the qualifier can't have mulitple declorations
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
@@ -573,13 +573,11 @@ struct ast_type_qualifier {
       uint64_t i;
    } flags;
 
-   struct YYLTYPE *loc;
-
    /** Precision of the type (highp/medium/lowp). */
    unsigned precision:2;
 
    /** Geometry shader invocations for GL_ARB_gpu_shader5. */
-   int invocations;
+   ast_layout_expression *invocations;
 
    /**
     * Location specified via GL_ARB_explicit_attrib_location layout
@@ -587,20 +585,20 @@ struct ast_type_qualifier {
     * \note
     * This field is only valid if \c explicit_location is set.
     */
-   int location;
+   ast_expression *location;
    /**
     * Index specified via GL_ARB_explicit_attrib_location layout
     *
     * \note
     * This field is only valid if \c explicit_index is set.
     */
-   int index;
+   ast_expression *index;
 
    /** Maximum output vertices in GLSL 1.50 geometry shaders. */
-   int max_vertices;
+   ast_layout_expression *max_vertices;
 
    /** Stream in GLSL 1.50 geometry shaders. */
-   unsigned stream;
+   ast_expression *stream;
 
    /**
     * Input or output primitive type in GLSL 1.50 geometry shaders
@@ -614,7 +612,7 @@ struct ast_type_qualifier {
     * \note
     * This field is only valid if \c explicit_binding is set.
     */
-   int binding;
+   ast_expression *binding;
 
    /**
     * Offset specified via GL_ARB_shader_atomic_counter's "offset"
@@ -623,14 +621,14 @@ struct ast_type_qualifier {
     * \note
     * This field is only valid if \c explicit_offset is set.
     */
-   int offset;
+   ast_expression *offset;
 
    /**
     * Local size specified via GL_ARB_compute_shader's "local_size_{x,y,z}"
     * layout qualifier.  Element i of this array is only valid if
     * flags.q.local_size & (1 << i) is set.
     */
-   int local_size[3];
+   ast_layout_expression *local_size[3];
 
    /** Tessellation evaluation shader: vertex spacing (equal, fractional even/odd) */
    GLenum vertex_spacing;
@@ -642,7 +640,7 @@ struct ast_type_qualifier {
    bool point_mode;
 
    /** Tessellation control shader: number of output vertices */
-   int vertices;
+   ast_layout_expression *vertices;
 
    /**
     * Image format specified with an ARB_shader_image_load_store
@@ -1114,17 +1112,13 @@ public:
 class ast_tcs_output_layout : public ast_node
 {
 public:
-   ast_tcs_output_layout(const struct YYLTYPE &locp, int vertices)
-      : vertices(vertices)
+   ast_tcs_output_layout(const struct YYLTYPE &locp)
    {
       set_location(locp);
    }
 
    virtual ir_rvalue *hir(exec_list *instructions,
                           struct _mesa_glsl_parse_state *state);
-
-private:
-   const int vertices;
 };
 
 
@@ -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));
       set_location(locp);
    }
 
@@ -1166,7 +1161,7 @@ public:
                           struct _mesa_glsl_parse_state *state);
 
 private:
-   unsigned local_size[3];
+   ast_layout_expression *local_size[3];
 };
 
 /*@}*/
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index fcf7566..d55a99e 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -2319,7 +2319,8 @@ static bool
 validate_binding_qualifier(struct _mesa_glsl_parse_state *state,
                            YYLTYPE *loc,
                            const glsl_type *type,
-                           const ast_type_qualifier *qual)
+                           const ast_type_qualifier *qual,
+                           unsigned qual_binding)
 {
    if (!qual->flags.q.uniform && !qual->flags.q.buffer) {
       _mesa_glsl_error(loc, state,
@@ -2328,14 +2329,9 @@ validate_binding_qualifier(struct _mesa_glsl_parse_state *state,
       return false;
    }
 
-   if (qual->binding < 0) {
-      _mesa_glsl_error(loc, state, "binding values must be >= 0");
-      return false;
-   }
-
    const struct gl_context *const ctx = state->ctx;
    unsigned elements = type->is_array() ? type->arrays_of_arrays_size() : 1;
-   unsigned max_index = qual->binding + elements - 1;
+   unsigned max_index = qual_binding + elements - 1;
    const glsl_type *base_type = type->without_array();
 
    if (base_type->is_interface()) {
@@ -2351,9 +2347,9 @@ validate_binding_qualifier(struct _mesa_glsl_parse_state *state,
        */
       if (qual->flags.q.uniform &&
          max_index >= ctx->Const.MaxUniformBufferBindings) {
-         _mesa_glsl_error(loc, state, "layout(binding = %d) for %d UBOs exceeds "
+         _mesa_glsl_error(loc, state, "layout(binding = %u) for %d UBOs exceeds "
                           "the maximum number of UBO binding points (%d)",
-                          qual->binding, elements,
+                          qual_binding, elements,
                           ctx->Const.MaxUniformBufferBindings);
          return false;
       }
@@ -2369,9 +2365,9 @@ validate_binding_qualifier(struct _mesa_glsl_parse_state *state,
        */
       if (qual->flags.q.buffer &&
          max_index >= ctx->Const.MaxShaderStorageBufferBindings) {
-         _mesa_glsl_error(loc, state, "layout(binding = %d) for %d SSBOs exceeds "
+         _mesa_glsl_error(loc, state, "layout(binding = %u) for %d SSBOs exceeds "
                           "the maximum number of SSBO binding points (%d)",
-                          qual->binding, elements,
+                          qual_binding, elements,
                           ctx->Const.MaxShaderStorageBufferBindings);
          return false;
       }
@@ -2386,18 +2382,18 @@ validate_binding_qualifier(struct _mesa_glsl_parse_state *state,
       unsigned limit = ctx->Const.MaxCombinedTextureImageUnits;
 
       if (max_index >= limit) {
-         _mesa_glsl_error(loc, state, "layout(binding = %d) for %d samplers "
+         _mesa_glsl_error(loc, state, "layout(binding = %u) for %d samplers "
                           "exceeds the maximum number of texture image units "
-                          "(%d)", qual->binding, elements, limit);
+                          "(%d)", qual_binding, elements, limit);
 
          return false;
       }
    } else if (base_type->contains_atomic()) {
       assert(ctx->Const.MaxAtomicBufferBindings <= MAX_COMBINED_ATOMIC_BUFFERS);
-      if (unsigned(qual->binding) >= ctx->Const.MaxAtomicBufferBindings) {
+      if (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,
+                          "(%u)", qual_binding,
                           ctx->Const.MaxAtomicBufferBindings);
 
          return false;
@@ -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;
    }
 
    /* Checks for GL_ARB_explicit_uniform_location. */
@@ -2480,7 +2476,7 @@ validate_explicit_location(const struct ast_type_qualifier *qual,
          return;
 
       const struct gl_context *const ctx = state->ctx;
-      unsigned max_loc = qual->location + var->type->uniform_locations() - 1;
+      unsigned max_loc = qual_location + var->type->uniform_locations() - 1;
 
       if (max_loc >= ctx->Const.MaxUserAssignableUniformLocations) {
          _mesa_glsl_error(loc, state, "location(s) consumed by uniform %s "
@@ -2490,7 +2486,7 @@ validate_explicit_location(const struct ast_type_qualifier *qual,
       }
 
       var->data.explicit_location = true;
-      var->data.location = qual->location;
+      var->data.location = qual_location;
       return;
    }
 
@@ -2575,23 +2571,23 @@ validate_explicit_location(const struct ast_type_qualifier *qual,
       switch (state->stage) {
       case MESA_SHADER_VERTEX:
          var->data.location = (var->data.mode == ir_var_shader_in)
-            ? (qual->location + VERT_ATTRIB_GENERIC0)
-            : (qual->location + VARYING_SLOT_VAR0);
+            ? (qual_location + VERT_ATTRIB_GENERIC0)
+            : (qual_location + VARYING_SLOT_VAR0);
          break;
 
       case MESA_SHADER_TESS_CTRL:
       case MESA_SHADER_TESS_EVAL:
       case MESA_SHADER_GEOMETRY:
          if (var->data.patch)
-            var->data.location = qual->location + VARYING_SLOT_PATCH0;
+            var->data.location = qual_location + VARYING_SLOT_PATCH0;
          else
-            var->data.location = qual->location + VARYING_SLOT_VAR0;
+            var->data.location = qual_location + VARYING_SLOT_VAR0;
          break;
 
       case MESA_SHADER_FRAGMENT:
          var->data.location = (var->data.mode == ir_var_shader_out)
-            ? (qual->location + FRAG_RESULT_DATA0)
-            : (qual->location + VARYING_SLOT_VAR0);
+            ? (qual_location + FRAG_RESULT_DATA0)
+            : (qual_location + VARYING_SLOT_VAR0);
          break;
       case MESA_SHADER_COMPUTE:
          assert(!"Unexpected shader type");
@@ -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;
          }
       }
    } else if (qual->flags.q.explicit_index) {
       _mesa_glsl_error(loc, state, "explicit index requires explicit location");
    }
 
-   if (qual->flags.q.explicit_binding &&
-       validate_binding_qualifier(state, loc, var->type, qual)) {
-      var->data.explicit_binding = true;
-      var->data.binding = qual->binding;
+   if (qual->flags.q.explicit_binding) {
+      unsigned qual_binding;
+      if (process_qualifier_constant(state, loc, "binding",
+                                     qual->binding, &qual_binding, 0) &&
+          validate_binding_qualifier(state, loc, var->type, qual,
+                                     qual_binding)) {
+         var->data.explicit_binding = true;
+         var->data.binding = qual_binding;
+      }
    }
 
    if (var->type->contains_atomic()) {
@@ -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) {
-      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);
+         var->data.stream = qual_stream;
+      }
    }
 
    if (qual->flags.q.patch)
@@ -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)) {
          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;
@@ -3624,8 +3634,7 @@ handle_tess_ctrl_shader_output_decl(struct _mesa_glsl_parse_state *state,
    if (var->data.patch)
       return;
 
-   validate_layout_qualifier_vertex_count(state, loc, var,
-                                          (unsigned) num_vertices,
+   validate_layout_qualifier_vertex_count(state, loc, var, num_vertices,
                                           &state->tcs_output_size,
                                           "tessellation control shader output");
 }
@@ -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)) {
+               state->atomic_counter_offsets[qual_binding] = qual_offset;
+            }
+         }
+      }
    }
 
    if (this->declarations.is_empty()) {
@@ -5917,7 +5936,8 @@ ast_process_structure_or_interface_block(exec_list *instructions,
                                          enum glsl_matrix_layout matrix_layout,
                                          bool allow_reserved_names,
                                          ir_variable_mode var_mode,
-                                         ast_type_qualifier *layout)
+                                         ast_type_qualifier *layout,
+                                         unsigned *block_stream)
 {
    unsigned decl_count = 0;
 
@@ -5929,6 +5949,15 @@ ast_process_structure_or_interface_block(exec_list *instructions,
                        "Interface block sets both readonly and writeonly");
    }
 
+   bool block_stream_processed = false;
+   if (layout) {
+      if (process_qualifier_constant(state, &loc, "stream", layout->stream,
+                                     block_stream, 0)) {
+         block_stream_processed = true;
+         validate_stream_qualifier(&loc, state, *block_stream);
+      }
+   }
+
    /* Make an initial pass over the list of fields to determine how
     * many there are.  Each element in this list is an ast_declarator_list.
     * This means that we actually need to count the number of elements in the
@@ -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))
+            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);
+               }
+            }
          }
 
          if (qual->flags.q.row_major || qual->flags.q.column_major) {
@@ -6198,6 +6236,7 @@ ast_struct_specifier::hir(exec_list *instructions,
                                                GLSL_MATRIX_LAYOUT_INHERITED,
                                                false /* allow_reserved_names */,
                                                ir_var_auto,
+                                               NULL,
                                                NULL);
 
    validate_identifier(this->name, loc, state);
@@ -6344,6 +6383,7 @@ ast_interface_block::hir(exec_list *instructions,
     */
    state->struct_specifier_depth++;
 
+   unsigned qual_stream;
    unsigned int num_variables =
       ast_process_structure_or_interface_block(&declared_variables,
                                                state,
@@ -6354,7 +6394,8 @@ ast_interface_block::hir(exec_list *instructions,
                                                matrix_layout,
                                                redeclaring_per_vertex,
                                                var_mode,
-                                               &this->layout);
+                                               &this->layout,
+                                               &qual_stream);
 
    state->struct_specifier_depth--;
 
@@ -6494,8 +6535,12 @@ ast_interface_block::hir(exec_list *instructions,
                                         num_variables,
                                         packing,
                                         this->block_name);
-   if (this->layout.flags.q.explicit_binding)
-      validate_binding_qualifier(state, &loc, block_type, &this->layout);
+   unsigned qual_binding;
+   if (this->layout.flags.q.explicit_binding &&
+       process_qualifier_constant(state, &loc, "binding", this->layout.binding,
+                                  &qual_binding, 0))
+      validate_binding_qualifier(state, &loc, block_type,
+                                 &this->layout, qual_binding);
 
    if (!state->symbols->add_interface(block_type->name, block_type, var_mode)) {
       YYLTYPE loc = this->get_location();
@@ -6626,9 +6671,13 @@ ast_interface_block::hir(exec_list *instructions,
                              "not allowed");
          }
 
-         if (this->layout.flags.q.explicit_binding)
+         unsigned qual_binding;
+         if (this->layout.flags.q.explicit_binding &&
+             process_qualifier_constant(state, &loc, "binding",
+                                        this->layout.binding, &qual_binding,
+                                        0))
             validate_binding_qualifier(state, &loc, block_array_type,
-                                       &this->layout);
+                                       &this->layout, qual_binding);
 
          var = new(state) ir_variable(block_array_type,
                                       this->instance_name,
@@ -6696,9 +6745,15 @@ ast_interface_block::hir(exec_list *instructions,
           * has an instance name.  This is ugly.
           */
          var->data.explicit_binding = this->layout.flags.q.explicit_binding;
-         var->data.binding = this->layout.binding;
+         unsigned qual_binding;
+         if (this->layout.flags.q.explicit_binding &&
+             process_qualifier_constant(state, &loc, "binding",
+                                        this->layout.binding,
+                                        &qual_binding, 0)) {
+            var->data.binding = qual_binding;
+         }
 
-         var->data.stream = this->layout.stream;
+         var->data.stream = qual_stream;
 
          state->symbols->add_variable(var);
          instructions->push_tail(var);
@@ -6718,7 +6773,7 @@ ast_interface_block::hir(exec_list *instructions,
          var->data.centroid = fields[i].centroid;
          var->data.sample = fields[i].sample;
          var->data.patch = fields[i].patch;
-         var->data.stream = this->layout.stream;
+         var->data.stream = qual_stream;
          var->init_interface_type(block_type);
 
          if (var_mode == ir_var_shader_in || var_mode == ir_var_uniform)
@@ -6769,7 +6824,13 @@ ast_interface_block::hir(exec_list *instructions,
           * has an instance name.  This is ugly.
           */
          var->data.explicit_binding = this->layout.flags.q.explicit_binding;
-         var->data.binding = this->layout.binding;
+         unsigned qual_binding;
+         if (this->layout.flags.q.explicit_binding &&
+             process_qualifier_constant(state, &loc, "binding",
+                                        this->layout.binding,
+                                        &qual_binding, 0)) {
+            var->data.binding = qual_binding;
+         }
 
          if (var->type->is_unsized_array()) {
             if (var->is_in_shader_storage_block()) {
@@ -6851,14 +6912,10 @@ ast_tcs_output_layout::hir(exec_list *instructions,
 {
    YYLTYPE loc = this->get_location();
 
-   /* If any tessellation control output layout declaration preceded this
-    * one, make sure it was consistent with this one.
-    */
-   if (state->tcs_output_vertices_specified &&
-       state->out_qualifier->vertices != this->vertices) {
-      _mesa_glsl_error(&loc, state,
-		       "tessellation control shader output layout does not "
-		       "match previous declaration");
+   unsigned num_vertices;
+   if (!state->out_qualifier->vertices->
+          process_qualifier_constant(state, "vertices", &num_vertices, 1)) {
+      /* return here to stop cascading incorrect error messages */
       return NULL;
    }
 
@@ -6866,8 +6923,8 @@ ast_tcs_output_layout::hir(exec_list *instructions,
     * array size, make sure the size they specified is consistent with the
     * primitive type.
     */
-   unsigned num_vertices = this->vertices;
-   if (state->tcs_output_size != 0 && state->tcs_output_size != num_vertices) {
+   if (state->tcs_output_size != 0 &&
+       state->tcs_output_size != num_vertices) {
       _mesa_glsl_error(&loc, state,
 		       "this tessellation control shader output layout "
 		       "specifies %u vertices, but a previous output "
@@ -6893,7 +6950,7 @@ ast_tcs_output_layout::hir(exec_list *instructions,
       if (var->data.max_array_access >= num_vertices) {
 	 _mesa_glsl_error(&loc, state,
 			  "this tessellation control shader output layout "
-			  "specifies %u vertices, but an access to element "
+			  "specifies %d vertices, but an access to element "
 			  "%u of output `%s' already exists", num_vertices,
 			  var->data.max_array_access, var->name);
       } else {
@@ -6974,20 +7031,6 @@ ast_cs_input_layout::hir(exec_list *instructions,
 {
    YYLTYPE loc = this->get_location();
 
-   /* If any compute input layout declaration preceded this one, make sure it
-    * was consistent with this one.
-    */
-   if (state->cs_input_local_size_specified) {
-      for (int i = 0; i < 3; i++) {
-         if (state->cs_input_local_size[i] != this->local_size[i]) {
-            _mesa_glsl_error(&loc, state,
-                             "compute shader input layout does not match"
-                             " previous declaration");
-            return NULL;
-         }
-      }
-   }
-
    /* From the ARB_compute_shader specification:
     *
     *     If the local size of the shader in any dimension is greater
@@ -7000,22 +7043,26 @@ ast_cs_input_layout::hir(exec_list *instructions,
     * report it at compile time as well.
     */
    GLuint64 total_invocations = 1;
+   unsigned qual_local_size[3];
    for (int i = 0; i < 3; i++) {
-      if (this->local_size[i] <= 0) {
-         _mesa_glsl_error(state->in_qualifier->loc, state,
-                          "invalid local_size_%c of %d specified",
-                          'x' + i, this->local_size[i]);
+      char *local_size_str = ralloc_asprintf(NULL, "invalid local_size_%c",
+                                             'x' + i);
+      if (!this->local_size[i]->
+             process_qualifier_constant(state, local_size_str,
+                                        &qual_local_size[i], 1)) {
+         ralloc_free(local_size_str);
          break;
       }
+      ralloc_free(local_size_str);
 
-      if (this->local_size[i] > state->ctx->Const.MaxComputeWorkGroupSize[i]) {
+      if (qual_local_size[i] > state->ctx->Const.MaxComputeWorkGroupSize[i]) {
          _mesa_glsl_error(&loc, state,
                           "local_size_%c exceeds MAX_COMPUTE_WORK_GROUP_SIZE"
                           " (%d)", 'x' + i,
                           state->ctx->Const.MaxComputeWorkGroupSize[i]);
          break;
       }
-      total_invocations *= this->local_size[i];
+      total_invocations *= qual_local_size[i];
       if (total_invocations >
           state->ctx->Const.MaxComputeWorkGroupInvocations) {
          _mesa_glsl_error(&loc, state,
@@ -7026,9 +7073,23 @@ ast_cs_input_layout::hir(exec_list *instructions,
       }
    }
 
+   /* If any compute input layout declaration preceded this one, make sure it
+    * was consistent with this one.
+    */
+   if (state->cs_input_local_size_specified) {
+      for (int i = 0; i < 3; i++) {
+         if (state->cs_input_local_size[i] != qual_local_size[i]) {
+            _mesa_glsl_error(&loc, state,
+                             "compute shader input layout does not match"
+                             " previous declaration");
+            return NULL;
+         }
+      }
+   }
+
    state->cs_input_local_size_specified = true;
    for (int i = 0; i < 3; i++)
-      state->cs_input_local_size[i] = this->local_size[i];
+      state->cs_input_local_size[i] = qual_local_size[i];
 
    /* We may now declare the built-in constant gl_WorkGroupSize (see
     * builtin_variable_generator::generate_constants() for why we didn't
@@ -7043,7 +7104,7 @@ ast_cs_input_layout::hir(exec_list *instructions,
    ir_constant_data data;
    memset(&data, 0, sizeof(data));
    for (int i = 0; i < 3; i++)
-      data.u[i] = this->local_size[i];
+      data.u[i] = qual_local_size[i];
    var->constant_value = new(var) ir_constant(glsl_type::uvec3_type, &data);
    var->constant_initializer =
       new(var) ir_constant(glsl_type::uvec3_type, &data);
diff --git a/src/glsl/ast_type.cpp b/src/glsl/ast_type.cpp
index 8ceb3b1..1986ccb 100644
--- a/src/glsl/ast_type.cpp
+++ b/src/glsl/ast_type.cpp
@@ -168,41 +168,23 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
    }
 
    if (q.flags.q.max_vertices) {
-      if (this->flags.q.max_vertices && this->max_vertices != q.max_vertices) {
-	 _mesa_glsl_error(loc, state,
-			  "geometry shader set conflicting max_vertices "
-			  "(%d and %d)", this->max_vertices, q.max_vertices);
-	 return false;
+      if (this->max_vertices) {
+         this->max_vertices->merge_qualifier(q.max_vertices);
+      } else {
+         this->max_vertices = q.max_vertices;
       }
-      this->max_vertices = q.max_vertices;
    }
 
    if (q.flags.q.invocations) {
-      if (this->flags.q.invocations && this->invocations != q.invocations) {
-         _mesa_glsl_error(loc, state,
-                          "geometry shader set conflicting invocations "
-                          "(%d and %d)", this->invocations, q.invocations);
-         return false;
+      if (this->invocations) {
+         this->invocations->merge_qualifier(q.invocations);
+      } else {
+         this->invocations = q.invocations;
       }
-      this->invocations = q.invocations;
    }
 
    if (state->stage == MESA_SHADER_GEOMETRY &&
        state->has_explicit_attrib_stream()) {
-      if (q.flags.q.stream && q.stream >= state->ctx->Const.MaxVertexStreams) {
-         _mesa_glsl_error(loc, state,
-                          "`stream' value is larger than MAX_VERTEX_STREAMS - 1 "
-                          "(%d > %d)",
-                          q.stream, state->ctx->Const.MaxVertexStreams - 1);
-      }
-      if (this->flags.q.explicit_stream &&
-          this->stream >= state->ctx->Const.MaxVertexStreams) {
-         _mesa_glsl_error(loc, state,
-                          "`stream' value is larger than MAX_VERTEX_STREAMS - 1 "
-                          "(%d > %d)",
-                          this->stream, state->ctx->Const.MaxVertexStreams - 1);
-      }
-
       if (!this->flags.q.explicit_stream) {
          if (q.flags.q.stream) {
             this->flags.q.stream = 1;
@@ -221,14 +203,11 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
    }
 
    if (q.flags.q.vertices) {
-      if (this->flags.q.vertices && this->vertices != q.vertices) {
-	 _mesa_glsl_error(loc, state,
-			  "tessellation control shader set conflicting "
-			  "vertices (%d and %d)",
-			  this->vertices, q.vertices);
-	 return false;
+      if (this->vertices) {
+         this->vertices->merge_qualifier(q.vertices);
+      } else {
+         this->vertices = q.vertices;
       }
-      this->vertices = q.vertices;
    }
 
    if (q.flags.q.vertex_spacing) {
@@ -265,14 +244,6 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
 
    for (int i = 0; i < 3; i++) {
       if (q.flags.q.local_size & (1 << i)) {
-         if ((this->flags.q.local_size & (1 << i)) &&
-             this->local_size[i] != q.local_size[i]) {
-            _mesa_glsl_error(loc, state,
-                             "compute shader set conflicting values for "
-                             "local_size_%c (%d and %d)", 'x' + i,
-                             this->local_size[i], q.local_size[i]);
-            return false;
-         }
          this->local_size[i] = q.local_size[i];
       }
    }
@@ -310,10 +281,9 @@ ast_type_qualifier::merge_out_qualifier(YYLTYPE *loc,
 {
    void *mem_ctx = state;
    const bool r = this->merge_qualifier(loc, state, q);
-   this->loc = loc;
 
    if (state->stage == MESA_SHADER_TESS_CTRL) {
-      node = new(mem_ctx) ast_tcs_output_layout(*loc, q.vertices);
+      node = new(mem_ctx) ast_tcs_output_layout(*loc);
    }
 
    return r;
@@ -330,7 +300,6 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
    bool create_cs_ast = false;
    ast_type_qualifier valid_in_mask;
    valid_in_mask.flags.i = 0;
-   this->loc = loc;
 
    switch (state->stage) {
    case MESA_SHADER_TESS_EVAL:
@@ -418,15 +387,13 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
       state->in_qualifier->prim_type = q.prim_type;
    }
 
-   if (this->flags.q.invocations &&
-       q.flags.q.invocations &&
-       this->invocations != q.invocations) {
-      _mesa_glsl_error(loc, state,
-                       "conflicting invocations counts specified");
-      return false;
-   } else if (q.flags.q.invocations) {
+   if (q.flags.q.invocations) {
       this->flags.q.invocations = 1;
-      this->invocations = q.invocations;
+      if (this->invocations) {
+         this->invocations->merge_qualifier(q.invocations);
+      } else {
+         this->invocations = q.invocations;
+      }
    }
 
    if (q.flags.q.early_fragment_tests) {
@@ -470,12 +437,16 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
       node = new(mem_ctx) ast_gs_input_layout(*loc, q.prim_type);
    } else if (create_cs_ast) {
       /* Infer a local_size of 1 for every unspecified dimension */
-      unsigned local_size[3];
+      ast_layout_expression *local_size[3];
       for (int i = 0; i < 3; i++) {
          if (q.flags.q.local_size & (1 << i))
             local_size[i] = q.local_size[i];
-         else
-            local_size[i] = 1;
+         else {
+            ast_expression *const_expr = new(mem_ctx)
+               ast_expression(ast_uint_constant, NULL, NULL, NULL);
+            const_expr->primary_expression.uint_constant = 1;
+            local_size[i]->layout_const_expressions.push_tail(&const_expr->link);
+         }
       }
       node = new(mem_ctx) ast_cs_input_layout(*loc, local_size);
    }
diff --git a/src/glsl/glsl_parser.yy b/src/glsl/glsl_parser.yy
index 44853b0..4186022 100644
--- a/src/glsl/glsl_parser.yy
+++ b/src/glsl/glsl_parser.yy
@@ -297,7 +297,6 @@ static bool match_layout_qualifier(const char *s1, const char *s2,
 %type <node> conditionopt
 %type <node> for_init_statement
 %type <for_rest_statement> for_rest_statement
-%type <n> integer_constant
 %type <node> layout_defaults
 
 %right THEN ELSE
@@ -1139,11 +1138,6 @@ layout_qualifier_id_list:
    }
    ;
 
-integer_constant:
-   INTCONSTANT { $$ = $1; }
-   | UINTCONSTANT { $$ = $1; }
-   ;
-
 layout_qualifier_id:
    any_identifier
    {
@@ -1440,9 +1434,18 @@ layout_qualifier_id:
          YYERROR;
       }
    }
-   | any_identifier '=' integer_constant
+   | any_identifier '=' constant_expression
    {
       memset(& $$, 0, sizeof($$));
+      void *ctx = state;
+
+      if ($3->oper != ast_int_constant &&
+          $3->oper != ast_uint_constant &&
+          !state->has_enhanced_layouts()) {
+         _mesa_glsl_error(& @1, state,
+                          "compile-time constant expressions require "
+                          "GLSL 4.40 or ARB_enhanced_layouts");
+      }
 
       if (match_layout_qualifier("location", $1, state) == 0) {
          $$.flags.q.explicit_location = 1;
@@ -1477,7 +1480,7 @@ layout_qualifier_id:
 
       if (match_layout_qualifier("max_vertices", $1, state) == 0) {
          $$.flags.q.max_vertices = 1;
-         $$.max_vertices = $3;
+         $$.max_vertices = new(ctx) ast_layout_expression(@1, $3);
 
          if (!state->is_version(150, 0)) {
             _mesa_glsl_error(& @1, state,
@@ -1511,7 +1514,7 @@ layout_qualifier_id:
                YYERROR;
             } else {
                $$.flags.q.local_size |= (1 << i);
-               $$.local_size[i] = $3;
+               $$.local_size[i] = new(ctx) ast_layout_expression(@1, $3);
             }
             break;
          }
@@ -1519,7 +1522,7 @@ layout_qualifier_id:
 
       if (match_layout_qualifier("invocations", $1, state) == 0) {
          $$.flags.q.invocations = 1;
-         $$.invocations = $3;
+         $$.invocations = new(ctx) ast_layout_expression(@1, $3);
          if (!state->is_version(400, 0) &&
              !state->ARB_gpu_shader5_enable) {
             _mesa_glsl_error(& @1, state,
@@ -1531,7 +1534,7 @@ layout_qualifier_id:
       /* Layout qualifiers for tessellation control shaders. */
       if (match_layout_qualifier("vertices", $1, state) == 0) {
          $$.flags.q.vertices = 1;
-         $$.vertices = $3;
+         $$.vertices = new(ctx) ast_layout_expression(@1, $3);
          if (!state->ARB_tessellation_shader_enable &&
              !state->is_version(400, 0)) {
             _mesa_glsl_error(& @1, state,
diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp
index 7d7f45c..b90fc68 100644
--- a/src/glsl/glsl_parser_extras.cpp
+++ b/src/glsl/glsl_parser_extras.cpp
@@ -1652,8 +1652,13 @@ set_shader_inout_layout(struct gl_shader *shader,
    switch (shader->Stage) {
    case MESA_SHADER_TESS_CTRL:
       shader->TessCtrl.VerticesOut = 0;
-      if (state->tcs_output_vertices_specified)
-         shader->TessCtrl.VerticesOut = state->out_qualifier->vertices;
+      if (state->tcs_output_vertices_specified) {
+         unsigned vertices;
+         if (state->out_qualifier->vertices->
+               process_qualifier_constant(state, "vertices", &vertices, 0)) {
+            shader->TessCtrl.VerticesOut = vertices;
+         }
+      }
       break;
    case MESA_SHADER_TESS_EVAL:
       shader->TessEval.PrimitiveMode = PRIM_UNKNOWN;
@@ -1675,12 +1680,12 @@ set_shader_inout_layout(struct gl_shader *shader,
    case MESA_SHADER_GEOMETRY:
       shader->Geom.VerticesOut = 0;
       if (state->out_qualifier->flags.q.max_vertices) {
-         if (state->out_qualifier->max_vertices < 0) {
-            _mesa_glsl_error(state->out_qualifier->loc, state,
-                             "invalid max_vertices %d specified",
-                             state->out_qualifier->max_vertices);
+         unsigned qual_max_vertices;
+         if (state->out_qualifier->max_vertices->
+               process_qualifier_constant(state, "max_vertices",
+                                          &qual_max_vertices, 0)) {
+            shader->Geom.VerticesOut = qual_max_vertices;
          }
-         shader->Geom.VerticesOut = state->out_qualifier->max_vertices;
       }
 
       if (state->gs_input_prim_type_specified) {
@@ -1697,18 +1702,20 @@ set_shader_inout_layout(struct gl_shader *shader,
 
       shader->Geom.Invocations = 0;
       if (state->in_qualifier->flags.q.invocations) {
-         if (state->in_qualifier->invocations <= 0) {
-            _mesa_glsl_error(state->in_qualifier->loc, state,
-                             "invalid invocations %d specified",
-                             state->in_qualifier->invocations);
-         } else if (state->in_qualifier->invocations >
-                    MAX_GEOMETRY_SHADER_INVOCATIONS) {
-            _mesa_glsl_error(state->in_qualifier->loc, state,
-                             "invocations (%d) exceeds "
-                             "GL_MAX_GEOMETRY_SHADER_INVOCATIONS",
-                             state->in_qualifier->invocations);
+         unsigned invocations;
+         if (state->in_qualifier->invocations->
+               process_qualifier_constant(state, "invocations",
+                                          &invocations, 1)) {
+
+            YYLTYPE loc = state->in_qualifier->invocations->get_location();
+            if (invocations > MAX_GEOMETRY_SHADER_INVOCATIONS) {
+               _mesa_glsl_error(&loc, state,
+                                "invocations (%d) exceeds "
+                                "GL_MAX_GEOMETRY_SHADER_INVOCATIONS",
+                                invocations);
+            }
+            shader->Geom.Invocations = invocations;
          }
-         shader->Geom.Invocations = state->in_qualifier->invocations;
       }
       break;
 
-- 
2.4.3



More information about the mesa-dev mailing list