<div dir="ltr">On 26 November 2013 00:02, Francisco Jerez <span dir="ltr"><<a href="mailto:currojerez@riseup.net" target="_blank">currojerez@riseup.net</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Because of the combinatorial explosion of different image built-ins<br>
with different image dimensionalities and base data types, enumerating<br>
all the 242 possibilities would be annoying and a waste of .text<br>
space.  Instead use a special path in the built-in builder that loops<br>
over all the known image types.<br>
---<br>
 src/glsl/builtin_functions.cpp | 378 +++++++++++++++++++++++++++++++++++++++++<br>
 1 file changed, 378 insertions(+)<br>
<br>
diff --git a/src/glsl/builtin_functions.cpp b/src/glsl/builtin_functions.cpp<br>
index a1a338d..760e264 100644<br>
--- a/src/glsl/builtin_functions.cpp<br>
+++ b/src/glsl/builtin_functions.cpp<br>
@@ -334,12 +334,20 @@ shader_atomic_counters(const _mesa_glsl_parse_state *state)<br>
    return state->ARB_shader_atomic_counters_enable;<br>
 }<br>
<br>
+static bool<br>
+shader_image_load_store(const _mesa_glsl_parse_state *state)<br>
+{<br>
+   return state->ARB_shader_image_load_store_enable;<br></blockquote><div><br></div><div>As in the previous patch, let's make this "state->is_version(420, 0) || state->ARB_shader_image_load_store_enable" so that the right thing will happen when we get to GLSL version 4.20.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+}<br>
+<br>
 /** @} */<br>
<br>
 /******************************************************************************/<br>
<br>
 namespace {<br>
<br>
+class image_builtin_builder;<br>
+<br>
 /**<br>
  * builtin_builder: A singleton object representing the core of the built-in<br>
  * function module.<br>
@@ -406,6 +414,13 @@ private:<br>
    /** Create a new function and add the given signatures. */<br>
    void add_function(const char *name, ...);<br>
<br>
+   /**<br>
+    * Create a new function calling \param func for each known image<br>
+    * type to generate its signatures.<br>
+    */<br>
+   void add_image_function(const char *name,<br>
+                           const image_builtin_builder &func);<br>
+<br>
    ir_function_signature *new_sig(const glsl_type *return_type,<br>
                                   builtin_available_predicate avail,<br>
                                   int num_params, ...);<br>
@@ -569,6 +584,11 @@ private:<br>
    ir_function_signature *_atomic_op(const char *intrinsic,<br>
                                      builtin_available_predicate avail);<br>
<br>
+   ir_function_signature *_memory_barrier_intrinsic(<br>
+      builtin_available_predicate avail);<br>
+   ir_function_signature *_memory_barrier(<br>
+      builtin_available_predicate avail);<br>
+<br>
 #undef B0<br>
 #undef B1<br>
 #undef B2<br>
@@ -576,6 +596,171 @@ private:<br>
 #undef BA1<br>
 #undef BA2<br>
    /** @} */<br>
+<br>
+   friend class image_builtin_builder;<br>
+};<br>
+<br>
+/**<br>
+ * Functor that generates image load, store or atomic built-in<br>
+ * signatures given some settings.<br>
+ */<br>
+class image_builtin_builder<br>
+{<br>
+public:<br>
+   image_builtin_builder(builtin_builder &bld)<br>
+      : bld(bld),<br>
+        _emit_stub(false),<br>
+        _intrinsic_name(NULL),<br>
+        _has_return(false),<br>
+        _has_arguments(0),<br>
+        _has_vector_data_type(false),<br>
+        _has_float_data_type(false),<br>
+        _read_only(false),<br>
+        _write_only(false)<br>
+   {<br>
+   }<br>
+<br>
+   /**<br>
+    * Build a stub function that calls \c intrinsic_name forwarding<br>
+    * arguments and return type.<br>
+    */<br>
+   image_builtin_builder &<br>
+   emit_stub(const char *intrinsic_name)<br>
+   {<br>
+      _emit_stub = true;<br>
+      _intrinsic_name = intrinsic_name;<br>
+      return *this;<br>
+   }<br>
+<br>
+   image_builtin_builder &<br>
+   has_return()<br>
+   {<br>
+      _has_return = true;<br>
+      return *this;<br>
+   }<br>
+<br>
+   image_builtin_builder &<br>
+   has_arguments(unsigned n)<br>
+   {<br>
+      _has_arguments = n;<br>
+      return *this;<br>
+   }<br>
+<br>
+   image_builtin_builder &<br>
+   has_vector_data_type()<br>
+   {<br>
+      _has_vector_data_type = true;<br>
+      return *this;<br>
+   }<br>
+<br>
+   image_builtin_builder &<br>
+   has_float_data_type()<br>
+   {<br>
+      _has_float_data_type = true;<br>
+      return *this;<br>
+   }<br></blockquote><div><br></div><div>has_float_data_type is a confusing name.  What this boolean really represents is the fact that the function in question *supports* floating point images.  Functions having this property may or may not have float point data types involved in their signatures depending on the image type.  I'd suggest changing the name to "supports_floating_point_images".<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+   image_builtin_builder &<br>
+   read_only()<br>
+   {<br>
+      _read_only = true;<br>
+      return *this;<br>
+   }<br>
+<br>
+   image_builtin_builder &<br>
+   write_only()<br>
+   {<br>
+      _write_only = true;<br>
+      return *this;<br>
+   }<br>
+<br>
+   /**<br>
+    * Generate the image built-in.<br>
+    */<br>
+   ir_function_signature *<br>
+   operator()(const glsl_type *image_type) const<br>
+   {<br>
+      if (image_type->fields.image.type == GLSL_TYPE_FLOAT &&<br>
+          !_has_float_data_type)<br>
+         return NULL;<br>
+<br>
+      ir_function_signature *sig = create_signature(image_type);<br>
+<br>
+      if (_emit_stub) {<br>
+         ir_factory body(&sig->body, bld.mem_ctx);<br>
+         ir_function *f = bld.shader->symbols->get_function(_intrinsic_name);<br>
+<br>
+         if (_has_return) {<br>
+            ir_variable *ret_val =<br>
+               body.make_temp(sig->return_type, "_ret_val");<br>
+            body.emit(bld.call(f, ret_val, sig->parameters));<br>
+            body.emit(ret(ret_val));<br>
+         } else {<br>
+            body.emit(bld.call(f, NULL, sig->parameters));<br>
+         }<br>
+<br>
+         sig->is_defined = true;<br>
+<br>
+      } else {<br>
+         sig->is_intrinsic = true;<br>
+      }<br>
+<br>
+      return sig;<br>
+   }<br>
+<br>
+private:<br>
+   ir_function_signature *<br>
+   create_signature(const glsl_type *image_type) const<br>
+   {<br>
+      const glsl_type *data_type =<br>
+         glsl_type::get_instance(image_type->fields.image.type,<br>
+                                 (_has_vector_data_type ? 4 : 1), 1);<br>
+      const glsl_type *ret_type = (_has_return ? data_type :<br>
+                                   glsl_type::void_type);<br>
+<br>
+      /* Addressing arguments that are always present. */<br>
+      ir_variable *image = bld.in_var(image_type, "image");<br>
+      ir_variable *coord = bld.in_var(<br>
+         glsl_type::ivec(image_type->coordinate_components()), "coord");<br>
+<br>
+      ir_function_signature *sig =<br>
+         bld.new_sig(ret_type, shader_image_load_store, 2, image, coord);<br>
+<br>
+      /* Sample index for multisample images. */<br>
+      if (image_type->fields.image.dimension == GLSL_IMAGE_DIM_MS)<br>
+         sig->parameters.push_tail(<br>
+            bld.in_var(glsl_type::int_type, "sample"));<br>
+<br>
+      /* Data arguments. */<br>
+      for (unsigned i = 0; i < _has_arguments; ++i)<br>
+         sig->parameters.push_tail(<br>
+            bld.in_var(data_type, ralloc_asprintf(NULL, "arg%d", i)));<br>
+<br>
+      /* Set the maximal set of qualifiers allowed for this image<br>
+       * built-in.  Function calls with arguments having fewer<br>
+       * qualifiers than present in the prototype are allowed by the<br>
+       * spec, but not with more, i.e. this will make the compiler<br>
+       * accept everything that needs to be accepted, and reject cases<br>
+       * like loads from write-only or stores to read-only images.<br>
+       */<br>
+      image->image.read_only = _read_only;<br>
+      image->image.write_only = _write_only;<br>
+      image->image.coherent = true;<br>
+      image->image._volatile = true;<br>
+      image->image._restrict = true;<br>
+<br>
+      return sig;<br>
+   }<br>
+<br>
+   builtin_builder &bld;<br>
+   bool _emit_stub;<br>
+   const char *_intrinsic_name;<br>
+   bool _has_return;<br>
+   unsigned _has_arguments;<br>
+   bool _has_vector_data_type;<br>
+   bool _has_float_data_type;<br>
+   bool _read_only;<br>
+   bool _write_only;<br>
 };<br></blockquote><div><br></div><div>I see a few downsides to this approach:<br><br></div><div>- There is unnecessary code duplication between builtin_builder::create_intrinsics() and builtin_builder::create_builtins().  Both of them create the same set of functions using the same parameters, with the only difference being the function names and whether emit_stub() is called.  Furthermore, if the names passed to emit_stub() in create_builtins() have to match the function names used in create_intrinsics().<br>
<br></div><div>- builtin_builder::create_intrinsics() and builtin_builder::create_builtins() create the same set of image_builtin_builder objects every time they are called.  I think the code would be easier to follow if the set of image_builtin_builter objects were declared as a static const table.<br>
<br></div><div>- Currently we don't have any precedent for the use of the fluent interface style in Mesa.  While I'm not opposed to it on principle, I don't think this particular use of it is very compelling, and I'd prefer to delay introducing it until we have a case where the benefit is clearer.<br>
<br><br></div><div>Here's what I would recommend doing instead:<br><br></div><div>- Change image_builtin_builder to a plain struct, and remove the fluent setter functions for setting its fields.<br></div><div><br>- Remove the emit_stub boolean and instead make it an argument to add_image_function().<br>
<br>- Remove the name parameter to add_image_function(), and instead store both the intrinsic name and the builtin name as separate fields in the struct.  add_image_function() will choose which name to use based on its emit_stub argument.<br>
</div><div><br></div><div>- At toplevel in buildin_functions.cpp, declare a static const array of image_builtin_builder objects, one for each image function.<br><br></div><div>- In builtin_builder::create_intrinsics(), loop through the static array of image_builtin_builders, calling add_image_function() on each and passing false for emit_stub.<br>
<br></div><div>- In builtin_builder::create_builtins(), loop through the static array of image_builtin_builders, calling add_image_function() on each and passing true for emit_stub.<br></div></div></div></div>