glsl: process bindless/bound layout qualifiers
authorSamuel Pitoiset <samuel.pitoiset@gmail.com>
Tue, 21 Mar 2017 12:30:49 +0000 (13:30 +0100)
committerSamuel Pitoiset <samuel.pitoiset@gmail.com>
Sat, 6 May 2017 14:40:19 +0000 (16:40 +0200)
This adds bindless_sampler and bound_sampler (and respectively
bindless_image and bound_image) to the parser.

v3: - add an extra space in apply_bindless_qualifier_to_variable()
    - fix indentation in merge_qualifier()

Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
src/compiler/glsl/ast.h
src/compiler/glsl/ast_to_hir.cpp
src/compiler/glsl/ast_type.cpp
src/compiler/glsl/glsl_parser.yy
src/compiler/glsl/glsl_parser_extras.cpp
src/compiler/glsl/glsl_parser_extras.h
src/compiler/glsl/ir.cpp
src/compiler/glsl/ir.h
src/compiler/glsl/ir_print_visitor.cpp
src/mesa/main/mtypes.h

index 455cb8113cda9c5bba86ad7e3ca99ea1bf3621cd..9327e039793513e1ec1eb16090c5c8c986b7388d 100644 (file)
@@ -622,6 +622,14 @@ struct ast_type_qualifier {
           * is used.
           */
          unsigned inner_coverage:1;
+
+         /** \name Layout qualifiers for GL_ARB_bindless_texture */
+         /** \{ */
+         unsigned bindless_sampler:1;
+         unsigned bindless_image:1;
+         unsigned bound_sampler:1;
+         unsigned bound_image:1;
+         /** \} */
       }
       /** \brief Set of flags, accessed by name. */
       q;
index f301b39f89627a91f496a7a4e7106549d25089fc..53dd08fe84fa7b296c219f66d4f6af27199a4b17 100644 (file)
@@ -3456,6 +3456,69 @@ validate_array_dimensions(const glsl_type *t,
    }
 }
 
+static void
+apply_bindless_qualifier_to_variable(const struct ast_type_qualifier *qual,
+                                     ir_variable *var,
+                                     struct _mesa_glsl_parse_state *state,
+                                     YYLTYPE *loc)
+{
+   bool has_local_qualifiers = qual->flags.q.bindless_sampler ||
+                               qual->flags.q.bindless_image ||
+                               qual->flags.q.bound_sampler ||
+                               qual->flags.q.bound_image;
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "Modify Section 4.4.6 Opaque-Uniform Layout Qualifiers of the GLSL 4.30
+    *  spec"
+    *
+    * "If these layout qualifiers are applied to other types of default block
+    *  uniforms, or variables with non-uniform storage, a compile-time error
+    *  will be generated."
+    */
+   if (has_local_qualifiers && !qual->flags.q.uniform) {
+      _mesa_glsl_error(loc, state, "ARB_bindless_texture layout qualifiers "
+                       "can only be applied to default block uniforms or "
+                       "variables with uniform storage");
+      return;
+   }
+
+   /* The ARB_bindless_texture spec doesn't state anything in this situation,
+    * but it makes sense to only allow bindless_sampler/bound_sampler for
+    * sampler types, and respectively bindless_image/bound_image for image
+    * types.
+    */
+   if ((qual->flags.q.bindless_sampler || qual->flags.q.bound_sampler) &&
+       !var->type->contains_sampler()) {
+      _mesa_glsl_error(loc, state, "bindless_sampler or bound_sampler can only "
+                       "be applied to sampler types");
+      return;
+   }
+
+   if ((qual->flags.q.bindless_image || qual->flags.q.bound_image) &&
+       !var->type->contains_image()) {
+      _mesa_glsl_error(loc, state, "bindless_image or bound_image can only be "
+                       "applied to image types");
+      return;
+   }
+
+   /* The bindless_sampler/bindless_image (and respectively
+    * bound_sampler/bound_image) layout qualifiers can be set at global and at
+    * local scope.
+    */
+   if (var->type->contains_sampler() || var->type->contains_image()) {
+      var->data.bindless = qual->flags.q.bindless_sampler ||
+                           qual->flags.q.bindless_image ||
+                           state->bindless_sampler_specified ||
+                           state->bindless_image_specified;
+
+      var->data.bound = qual->flags.q.bound_sampler ||
+                        qual->flags.q.bound_image ||
+                        state->bound_sampler_specified ||
+                        state->bound_image_specified;
+   }
+}
+
 static void
 apply_layout_qualifier_to_variable(const struct ast_type_qualifier *qual,
                                    ir_variable *var,
@@ -3753,6 +3816,9 @@ apply_layout_qualifier_to_variable(const struct ast_type_qualifier *qual,
       _mesa_glsl_error(loc, state, "post_depth_coverage layout qualifier only "
                        "valid in fragment shader input layout declaration.");
    }
+
+   if (state->has_bindless())
+      apply_bindless_qualifier_to_variable(qual, var, state, loc);
 }
 
 static void
index d302fc45fd7f69fd667530c54e7cddad9fcdfa05..9e3e10f33c041a624c7a67b1e170262f450378d3 100644 (file)
@@ -69,6 +69,10 @@ ast_type_qualifier::has_layout() const
           || this->flags.q.column_major
           || this->flags.q.row_major
           || this->flags.q.packed
+          || this->flags.q.bindless_sampler
+          || this->flags.q.bindless_image
+          || this->flags.q.bound_sampler
+          || this->flags.q.bound_image
           || this->flags.q.explicit_align
           || this->flags.q.explicit_component
           || this->flags.q.explicit_location
@@ -181,6 +185,33 @@ validate_point_mode(MAYBE_UNUSED const ast_type_qualifier &qualifier,
    return true;
 }
 
+static void
+merge_bindless_qualifier(YYLTYPE *loc,
+                         _mesa_glsl_parse_state *state,
+                         const ast_type_qualifier &qualifier,
+                         const ast_type_qualifier &new_qualifier)
+{
+   if (state->default_uniform_qualifier->flags.q.bindless_sampler) {
+      state->bindless_sampler_specified = true;
+      state->default_uniform_qualifier->flags.q.bindless_sampler = false;
+   }
+
+   if (state->default_uniform_qualifier->flags.q.bindless_image) {
+      state->bindless_image_specified = true;
+      state->default_uniform_qualifier->flags.q.bindless_image = false;
+   }
+
+   if (state->default_uniform_qualifier->flags.q.bound_sampler) {
+      state->bound_sampler_specified = true;
+      state->default_uniform_qualifier->flags.q.bound_sampler = false;
+   }
+
+   if (state->default_uniform_qualifier->flags.q.bound_image) {
+      state->bound_image_specified = true;
+      state->default_uniform_qualifier->flags.q.bound_image = false;
+   }
+}
+
 /**
  * This function merges duplicate layout identifiers.
  *
@@ -393,6 +424,18 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
    if (q.flags.q.local_size_variable)
       this->flags.q.local_size_variable = true;
 
+   if (q.flags.q.bindless_sampler)
+      this->flags.q.bindless_sampler = true;
+
+   if (q.flags.q.bindless_image)
+      this->flags.q.bindless_image = true;
+
+   if (q.flags.q.bound_sampler)
+      this->flags.q.bound_sampler = true;
+
+   if (q.flags.q.bound_image)
+      this->flags.q.bound_image = true;
+
    this->flags.i |= q.flags.i;
 
    if (this->flags.q.in &&
@@ -427,6 +470,12 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
       this->image_base_type = q.image_base_type;
    }
 
+   if (q.flags.q.bindless_sampler ||
+       q.flags.q.bindless_image ||
+       q.flags.q.bound_sampler ||
+       q.flags.q.bound_image)
+      merge_bindless_qualifier(loc, state, *this, q);
+
    return r;
 }
 
@@ -778,6 +827,10 @@ ast_type_qualifier::validate_flags(YYLTYPE *loc,
                     bad.flags.q.subroutine ? " subroutine" : "",
                     bad.flags.q.blend_support ? " blend_support" : "",
                     bad.flags.q.inner_coverage ? " inner_coverage" : "",
+                    bad.flags.q.bindless_sampler ? " bindless_sampler" : "",
+                    bad.flags.q.bindless_image ? " bindless_image" : "",
+                    bad.flags.q.bound_sampler ? " bound_sampler" : "",
+                    bad.flags.q.bound_image ? " bound_image" : "",
                     bad.flags.q.post_depth_coverage ? " post_depth_coverage" : "");
    return false;
 }
index e703073c9caf4b1729cc2776a6702f92e65f15a8..9cdc37eb9a30b62039d843e1f12b3a71fab78a18 100644 (file)
@@ -1589,6 +1589,27 @@ layout_qualifier_id:
          }
       }
 
+      /* Layout qualifiers for ARB_bindless_texture. */
+      if (!$$.flags.i) {
+         if (match_layout_qualifier($1, "bindless_sampler", state) == 0)
+            $$.flags.q.bindless_sampler = 1;
+         if (match_layout_qualifier($1, "bound_sampler", state) == 0)
+            $$.flags.q.bound_sampler = 1;
+
+         if (state->has_shader_image_load_store()) {
+            if (match_layout_qualifier($1, "bindless_image", state) == 0)
+               $$.flags.q.bindless_image = 1;
+            if (match_layout_qualifier($1, "bound_image", state) == 0)
+               $$.flags.q.bound_image = 1;
+         }
+
+         if ($$.flags.i && !state->has_bindless()) {
+            _mesa_glsl_error(& @1, state,
+                             "qualifier `%s` requires "
+                             "ARB_bindless_texture", $1);
+         }
+      }
+
       if (!$$.flags.i) {
          _mesa_glsl_error(& @1, state, "unrecognized layout identifier "
                           "`%s'", $1);
index b7303aba4217b91366ab0a192cafb53b4bcf40b4..d731e35e212f746e1e601903d7f0692df812dcb5 100644 (file)
@@ -307,6 +307,12 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
       ctx->Const.AllowGLSLExtensionDirectiveMidShader;
 
    this->cs_input_local_size_variable_specified = false;
+
+   /* ARB_bindless_texture */
+   this->bindless_sampler_specified = false;
+   this->bindless_image_specified = false;
+   this->bound_sampler_specified = false;
+   this->bound_image_specified = false;
 }
 
 /**
@@ -1849,6 +1855,11 @@ set_shader_inout_layout(struct gl_shader *shader,
       /* Nothing to do. */
       break;
    }
+
+   shader->bindless_sampler = state->bindless_sampler_specified;
+   shader->bindless_image = state->bindless_image_specified;
+   shader->bound_sampler = state->bound_sampler_specified;
+   shader->bound_image = state->bound_image_specified;
 }
 
 extern "C" {
index 6045a6128e6b4828ff9f735f24af6617897d46e8..3a84d655b14c16dbddd917e6763d1cd03b965193 100644 (file)
@@ -427,6 +427,16 @@ struct _mesa_glsl_parse_state {
     */
    bool cs_input_local_size_variable_specified;
 
+   /**
+    * True if a shader declare bindless_sampler/bindless_image, and
+    * respectively bound_sampler/bound_image at global scope as specified by
+    * ARB_bindless_texture.
+    */
+   bool bindless_sampler_specified;
+   bool bindless_image_specified;
+   bool bound_sampler_specified;
+   bool bound_image_specified;
+
    /**
     * Output layout qualifiers from GLSL 1.50 (geometry shader controls),
     * and GLSL 4.00 (tessellation control shader).
index 5b38a71149433a8c71b72205e56cd972cea3df36..590d2ad1c4b6895349313bcc6a5f06bc21ecd3cc 100644 (file)
@@ -1729,6 +1729,8 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name,
    this->data.memory_restrict = false;
    this->data.from_ssbo_unsized_array = false;
    this->data.fb_fetch_output = false;
+   this->data.bindless = false;
+   this->data.bound = false;
 
    if (type != NULL) {
       if (type->is_interface())
index 5a5729cdbe3700c8c5901f8f7c2d664a33a03a74..7e125e60d424465cd0d18ab233875f3ac30dbfcb 100644 (file)
@@ -849,6 +849,18 @@ public:
        */
       unsigned fb_fetch_output:1;
 
+      /**
+       * Non-zero if this variable is considered bindless as defined by
+       * ARB_bindless_texture.
+       */
+      unsigned bindless:1;
+
+      /**
+       * Non-zero if this variable is considered bound as defined by
+       * ARB_bindless_texture.
+       */
+      unsigned bound:1;
+
       /**
        * Emit a warning if this variable is accessed.
        */
index 6c1c86a58287c31cc53559bc4f53c14c4c98dc77..f8d0dc4dec267462043c1578e130affe0311d564 100644 (file)
@@ -193,6 +193,8 @@ void ir_print_visitor::visit(ir_variable *ir)
    const char *const patc = (ir->data.patch) ? "patch " : "";
    const char *const inv = (ir->data.invariant) ? "invariant " : "";
    const char *const prec = (ir->data.precise) ? "precise " : "";
+   const char *const bindless = (ir->data.bindless) ? "bindless " : "";
+   const char *const bound = (ir->data.bound) ? "bound " : "";
    const char *const mode[] = { "", "uniform ", "shader_storage ",
                                 "shader_shared ", "shader_in ", "shader_out ",
                                 "in ", "out ", "inout ",
@@ -201,9 +203,9 @@ void ir_print_visitor::visit(ir_variable *ir)
    const char *const interp[] = { "", "smooth", "flat", "noperspective" };
    STATIC_ASSERT(ARRAY_SIZE(interp) == INTERP_MODE_COUNT);
 
-   fprintf(f, "(%s%s%s%s%s%s%s%s%s%s%s) ",
-           binding, loc, component, cent, samp, patc, inv, prec, mode[ir->data.mode],
-           stream,
+   fprintf(f, "(%s%s%s%s%s%s%s%s%s%s%s%s%s) ",
+           binding, loc, component, cent, bindless, bound, samp, patc, inv,
+           prec, mode[ir->data.mode], stream,
            interp[ir->data.interpolation]);
 
    print_type(f, ir->type);
index 79c7e50a1bf6fcd9d6fff479b51abd73ec2e9e5b..0d594bf436fd23443cb477740e57223e2aa54a38 100644 (file)
@@ -2547,6 +2547,16 @@ struct gl_shader
    bool origin_upper_left;
    bool pixel_center_integer;
 
+   /**
+    * Whether bindless_sampler/bindless_image, and respectively
+    * bound_sampler/bound_image are declared at global scope as defined by
+    * ARB_bindless_texture.
+    */
+   bool bindless_sampler;
+   bool bindless_image;
+   bool bound_sampler;
+   bool bound_image;
+
    /** Global xfb_stride out qualifier if any */
    GLuint TransformFeedbackBufferStride[MAX_FEEDBACK_BUFFERS];