[Mesa-dev] [PATCH 19/23] glsl: Add image built-in function generator.

Francisco Jerez currojerez at riseup.net
Tue Nov 26 00:02:35 PST 2013


Because of the combinatorial explosion of different image built-ins
with different image dimensionalities and base data types, enumerating
all the 242 possibilities would be annoying and a waste of .text
space.  Instead use a special path in the built-in builder that loops
over all the known image types.
---
 src/glsl/builtin_functions.cpp | 378 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 378 insertions(+)

diff --git a/src/glsl/builtin_functions.cpp b/src/glsl/builtin_functions.cpp
index a1a338d..760e264 100644
--- a/src/glsl/builtin_functions.cpp
+++ b/src/glsl/builtin_functions.cpp
@@ -334,12 +334,20 @@ shader_atomic_counters(const _mesa_glsl_parse_state *state)
    return state->ARB_shader_atomic_counters_enable;
 }
 
+static bool
+shader_image_load_store(const _mesa_glsl_parse_state *state)
+{
+   return state->ARB_shader_image_load_store_enable;
+}
+
 /** @} */
 
 /******************************************************************************/
 
 namespace {
 
+class image_builtin_builder;
+
 /**
  * builtin_builder: A singleton object representing the core of the built-in
  * function module.
@@ -406,6 +414,13 @@ private:
    /** Create a new function and add the given signatures. */
    void add_function(const char *name, ...);
 
+   /**
+    * Create a new function calling \param func for each known image
+    * type to generate its signatures.
+    */
+   void add_image_function(const char *name,
+                           const image_builtin_builder &func);
+
    ir_function_signature *new_sig(const glsl_type *return_type,
                                   builtin_available_predicate avail,
                                   int num_params, ...);
@@ -569,6 +584,11 @@ private:
    ir_function_signature *_atomic_op(const char *intrinsic,
                                      builtin_available_predicate avail);
 
+   ir_function_signature *_memory_barrier_intrinsic(
+      builtin_available_predicate avail);
+   ir_function_signature *_memory_barrier(
+      builtin_available_predicate avail);
+
 #undef B0
 #undef B1
 #undef B2
@@ -576,6 +596,171 @@ private:
 #undef BA1
 #undef BA2
    /** @} */
+
+   friend class image_builtin_builder;
+};
+
+/**
+ * Functor that generates image load, store or atomic built-in
+ * signatures given some settings.
+ */
+class image_builtin_builder
+{
+public:
+   image_builtin_builder(builtin_builder &bld)
+      : bld(bld),
+        _emit_stub(false),
+        _intrinsic_name(NULL),
+        _has_return(false),
+        _has_arguments(0),
+        _has_vector_data_type(false),
+        _has_float_data_type(false),
+        _read_only(false),
+        _write_only(false)
+   {
+   }
+
+   /**
+    * Build a stub function that calls \c intrinsic_name forwarding
+    * arguments and return type.
+    */
+   image_builtin_builder &
+   emit_stub(const char *intrinsic_name)
+   {
+      _emit_stub = true;
+      _intrinsic_name = intrinsic_name;
+      return *this;
+   }
+
+   image_builtin_builder &
+   has_return()
+   {
+      _has_return = true;
+      return *this;
+   }
+
+   image_builtin_builder &
+   has_arguments(unsigned n)
+   {
+      _has_arguments = n;
+      return *this;
+   }
+
+   image_builtin_builder &
+   has_vector_data_type()
+   {
+      _has_vector_data_type = true;
+      return *this;
+   }
+
+   image_builtin_builder &
+   has_float_data_type()
+   {
+      _has_float_data_type = true;
+      return *this;
+   }
+
+   image_builtin_builder &
+   read_only()
+   {
+      _read_only = true;
+      return *this;
+   }
+
+   image_builtin_builder &
+   write_only()
+   {
+      _write_only = true;
+      return *this;
+   }
+
+   /**
+    * Generate the image built-in.
+    */
+   ir_function_signature *
+   operator()(const glsl_type *image_type) const
+   {
+      if (image_type->fields.image.type == GLSL_TYPE_FLOAT &&
+          !_has_float_data_type)
+         return NULL;
+
+      ir_function_signature *sig = create_signature(image_type);
+
+      if (_emit_stub) {
+         ir_factory body(&sig->body, bld.mem_ctx);
+         ir_function *f = bld.shader->symbols->get_function(_intrinsic_name);
+
+         if (_has_return) {
+            ir_variable *ret_val =
+               body.make_temp(sig->return_type, "_ret_val");
+            body.emit(bld.call(f, ret_val, sig->parameters));
+            body.emit(ret(ret_val));
+         } else {
+            body.emit(bld.call(f, NULL, sig->parameters));
+         }
+
+         sig->is_defined = true;
+
+      } else {
+         sig->is_intrinsic = true;
+      }
+
+      return sig;
+   }
+
+private:
+   ir_function_signature *
+   create_signature(const glsl_type *image_type) const
+   {
+      const glsl_type *data_type =
+         glsl_type::get_instance(image_type->fields.image.type,
+                                 (_has_vector_data_type ? 4 : 1), 1);
+      const glsl_type *ret_type = (_has_return ? data_type :
+                                   glsl_type::void_type);
+
+      /* Addressing arguments that are always present. */
+      ir_variable *image = bld.in_var(image_type, "image");
+      ir_variable *coord = bld.in_var(
+         glsl_type::ivec(image_type->coordinate_components()), "coord");
+
+      ir_function_signature *sig =
+         bld.new_sig(ret_type, shader_image_load_store, 2, image, coord);
+
+      /* Sample index for multisample images. */
+      if (image_type->fields.image.dimension == GLSL_IMAGE_DIM_MS)
+         sig->parameters.push_tail(
+            bld.in_var(glsl_type::int_type, "sample"));
+
+      /* Data arguments. */
+      for (unsigned i = 0; i < _has_arguments; ++i)
+         sig->parameters.push_tail(
+            bld.in_var(data_type, ralloc_asprintf(NULL, "arg%d", i)));
+
+      /* Set the maximal set of qualifiers allowed for this image
+       * built-in.  Function calls with arguments having fewer
+       * qualifiers than present in the prototype are allowed by the
+       * spec, but not with more, i.e. this will make the compiler
+       * accept everything that needs to be accepted, and reject cases
+       * like loads from write-only or stores to read-only images.
+       */
+      image->image.read_only = _read_only;
+      image->image.write_only = _write_only;
+      image->image.coherent = true;
+      image->image._volatile = true;
+      image->image._restrict = true;
+
+      return sig;
+   }
+
+   builtin_builder &bld;
+   bool _emit_stub;
+   const char *_intrinsic_name;
+   bool _has_return;
+   unsigned _has_arguments;
+   bool _has_vector_data_type;
+   bool _has_float_data_type;
+   bool _read_only;
+   bool _write_only;
 };
 
 } /* anonymous namespace */
@@ -684,6 +869,64 @@ builtin_builder::create_intrinsics()
    add_function("__intrinsic_atomic_predecrement",
                 _atomic_intrinsic(shader_atomic_counters),
                 NULL);
+
+   add_image_function("__intrinsic_image_load",
+                      image_builtin_builder(*this)
+                      .has_return()
+                      .has_vector_data_type()
+                      .has_float_data_type()
+                      .read_only());
+
+   add_image_function("__intrinsic_image_store",
+                      image_builtin_builder(*this)
+                      .has_arguments(1)
+                      .has_vector_data_type()
+                      .has_float_data_type()
+                      .write_only());
+
+   add_image_function("__intrinsic_image_atomic_add",
+                      image_builtin_builder(*this)
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("__intrinsic_image_atomic_min",
+                      image_builtin_builder(*this)
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("__intrinsic_image_atomic_max",
+                      image_builtin_builder(*this)
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("__intrinsic_image_atomic_and",
+                      image_builtin_builder(*this)
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("__intrinsic_image_atomic_or",
+                      image_builtin_builder(*this)
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("__intrinsic_image_atomic_xor",
+                      image_builtin_builder(*this)
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("__intrinsic_image_atomic_exchange",
+                      image_builtin_builder(*this)
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("__intrinsic_image_atomic_comp_swap",
+                      image_builtin_builder(*this)
+                      .has_return()
+                      .has_arguments(2));
+
+   add_function("__intrinsic_memory_barrier",
+                _memory_barrier_intrinsic(shader_image_load_store),
+                NULL);
 }
 
 /**
@@ -2106,6 +2349,74 @@ builtin_builder::create_builtins()
                            shader_atomic_counters),
                 NULL);
 
+   add_image_function("imageLoad",
+                      image_builtin_builder(*this)
+                      .emit_stub("__intrinsic_image_load")
+                      .has_return()
+                      .has_vector_data_type()
+                      .has_float_data_type()
+                      .read_only());
+
+   add_image_function("imageStore",
+                      image_builtin_builder(*this)
+                      .emit_stub("__intrinsic_image_store")
+                      .has_arguments(1)
+                      .has_vector_data_type()
+                      .has_float_data_type()
+                      .write_only());
+
+   add_image_function("imageAtomicAdd",
+                      image_builtin_builder(*this)
+                      .emit_stub("__intrinsic_image_atomic_add")
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("imageAtomicMin",
+                      image_builtin_builder(*this)
+                      .emit_stub("__intrinsic_image_atomic_min")
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("imageAtomicMax",
+                      image_builtin_builder(*this)
+                      .emit_stub("__intrinsic_image_atomic_max")
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("imageAtomicAnd",
+                      image_builtin_builder(*this)
+                      .emit_stub("__intrinsic_image_atomic_and")
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("imageAtomicOr",
+                      image_builtin_builder(*this)
+                      .emit_stub("__intrinsic_image_atomic_or")
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("imageAtomicXor",
+                      image_builtin_builder(*this)
+                      .emit_stub("__intrinsic_image_atomic_xor")
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("imageAtomicExchange",
+                      image_builtin_builder(*this)
+                      .emit_stub("__intrinsic_image_atomic_exchange")
+                      .has_return()
+                      .has_arguments(1));
+
+   add_image_function("imageAtomicCompSwap",
+                      image_builtin_builder(*this)
+                      .emit_stub("__intrinsic_image_atomic_comp_swap")
+                      .has_return()
+                      .has_arguments(2));
+
+   add_function("memoryBarrier",
+                _memory_barrier(shader_image_load_store),
+                NULL);
+
 #undef F
 #undef FI
 #undef FIU
@@ -2139,6 +2450,57 @@ builtin_builder::add_function(const char *name, ...)
    shader->symbols->add_function(f);
 }
 
+void
+builtin_builder::add_image_function(const char *name,
+                                    const image_builtin_builder &proc)
+{
+   static const glsl_type *const types[] = {
+      glsl_type::image1D_type,
+      glsl_type::image2D_type,
+      glsl_type::image3D_type,
+      glsl_type::image2DRect_type,
+      glsl_type::imageCube_type,
+      glsl_type::imageBuffer_type,
+      glsl_type::image1DArray_type,
+      glsl_type::image2DArray_type,
+      glsl_type::imageCubeArray_type,
+      glsl_type::image2DMS_type,
+      glsl_type::image2DMSArray_type,
+      glsl_type::iimage1D_type,
+      glsl_type::iimage2D_type,
+      glsl_type::iimage3D_type,
+      glsl_type::iimage2DRect_type,
+      glsl_type::iimageCube_type,
+      glsl_type::iimageBuffer_type,
+      glsl_type::iimage1DArray_type,
+      glsl_type::iimage2DArray_type,
+      glsl_type::iimageCubeArray_type,
+      glsl_type::iimage2DMS_type,
+      glsl_type::iimage2DMSArray_type,
+      glsl_type::uimage1D_type,
+      glsl_type::uimage2D_type,
+      glsl_type::uimage3D_type,
+      glsl_type::uimage2DRect_type,
+      glsl_type::uimageCube_type,
+      glsl_type::uimageBuffer_type,
+      glsl_type::uimage1DArray_type,
+      glsl_type::uimage2DArray_type,
+      glsl_type::uimageCubeArray_type,
+      glsl_type::uimage2DMS_type,
+      glsl_type::uimage2DMSArray_type
+   };
+   ir_function *f = new(mem_ctx) ir_function(name);
+
+   for (unsigned i = 0; i < Elements(types); ++i) {
+      ir_function_signature *sig = proc(types[i]);
+
+      if (sig)
+         f->add_signature(sig);
+   }
+
+   shader->symbols->add_function(f);
+}
+
 ir_variable *
 builtin_builder::in_var(const glsl_type *type, const char *name)
 {
@@ -3991,6 +4353,22 @@ builtin_builder::_atomic_op(const char *intrinsic,
    return sig;
 }
 
+ir_function_signature *
+builtin_builder::_memory_barrier_intrinsic(builtin_available_predicate avail)
+{
+   MAKE_INTRINSIC(glsl_type::void_type, avail, 0);
+   return sig;
+}
+
+ir_function_signature *
+builtin_builder::_memory_barrier(builtin_available_predicate avail)
+{
+   MAKE_SIG(glsl_type::void_type, avail, 0);
+   body.emit(call(shader->symbols->get_function("__intrinsic_memory_barrier"),
+                  NULL, sig->parameters));
+   return sig;
+}
+
 /** @} */
 
 /******************************************************************************/
-- 
1.8.3.4



More information about the mesa-dev mailing list