<div dir="ltr">On 15 September 2013 00:10, 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:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">---<br>
 src/glsl/Makefile.sources |   1 +<br>
 src/glsl/link_atomics.cpp | 190 ++++++++++++++++++++++++++++++++++++++++++++++<br>
 src/glsl/linker.cpp       |  15 ++++<br>
 src/glsl/linker.h         |   7 ++<br>
 4 files changed, 213 insertions(+)<br>
 create mode 100644 src/glsl/link_atomics.cpp<br>
<br>
diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources<br>
index 2f7bfa1..197d081 100644<br>
--- a/src/glsl/Makefile.sources<br>
+++ b/src/glsl/Makefile.sources<br>
@@ -47,6 +47,7 @@ LIBGLSL_FILES = \<br>
        $(GLSL_SRCDIR)/ir_validate.cpp \<br>
        $(GLSL_SRCDIR)/ir_variable_refcount.cpp \<br>
        $(GLSL_SRCDIR)/linker.cpp \<br>
+       $(GLSL_SRCDIR)/link_atomics.cpp \<br>
        $(GLSL_SRCDIR)/link_functions.cpp \<br>
        $(GLSL_SRCDIR)/link_interface_blocks.cpp \<br>
        $(GLSL_SRCDIR)/link_uniforms.cpp \<br>
diff --git a/src/glsl/link_atomics.cpp b/src/glsl/link_atomics.cpp<br>
new file mode 100644<br>
index 0000000..a623454<br>
--- /dev/null<br>
+++ b/src/glsl/link_atomics.cpp<br>
@@ -0,0 +1,190 @@<br>
+/*<br>
+ * Copyright İ 2013 Intel Corporation<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the "Software"),<br>
+ * to deal in the Software without restriction, including without limitation<br>
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
+ * and/or sell copies of the Software, and to permit persons to whom the<br>
+ * Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER<br>
+ * DEALINGS IN THE SOFTWARE.<br>
+ */<br>
+<br>
+#include <vector><br>
+#include <map><br>
+<br>
+#include "ir.h"<br>
+#include "ir_uniform.h"<br>
+#include "linker.h"<br>
+#include "program/hash_table.h"<br>
+<br>
+namespace {<br>
+   struct active_atomic_counter {<br>
+      active_atomic_counter(unsigned id, ir_variable *var) :<br>
+         id(id), var(var) {}<br>
+<br>
+      unsigned id;<br>
+      ir_variable *var;<br>
+   };<br>
+<br>
+   typedef std::vector<active_atomic_counter> active_atomic_counters_t;<br>
+<br>
+   struct active_atomic_buffer {<br>
+      active_atomic_buffer() : stage_references(), size(0) {}<br>
+<br>
+      active_atomic_counters_t counters;<br>
+      unsigned stage_references[MESA_SHADER_TYPES]; <br></blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      unsigned size;<br>
+   };<br>
+<br>
+   typedef std::map<unsigned, active_atomic_buffer> active_atomic_buffers_t;<br></blockquote><div><br></div><div>It would be really helpful to have some comments above these structs and their members indicating how they relate to the constructs in the language.<br>
<br></div><div>Also, if I'm understanding correctly, these data structures don't actually represent buffers, but rather represent binding points that buffers will later be bound to, so I'd also recommend renaming active_atomic_buffer -> active_atomic_binding_point and active_atomic_buffers_t -> active_atomic_binding_points_t, to be more in line with the language used in the spec.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+   /**<br>
+    * Construct a collection of active_atomic_buffer structures<br>
+    * indexed by binding point.  Each entry includes a collection of<br>
+    * active_atomic_counters that represent the set of atomic counters<br>
+    * determined to be contained within the same buffer.<br>
+    */<br>
+   active_atomic_buffers_t<br>
+   find_active_atomic_counters(struct gl_shader_program *prog) {<br>
+      active_atomic_buffers_t abs;<br>
+<br>
+      for (unsigned i = 0; i < MESA_SHADER_TYPES; ++i) {<br>
+         struct gl_shader *sh = prog->_LinkedShaders[i];<br>
+         if (sh == NULL)<br>
+            continue;<br>
+<br>
+         foreach_list(node, sh->ir) {<br>
+            ir_variable *var = ((ir_instruction *)node)->as_variable();<br>
+<br>
+            if (var && var->type->atomic_size()) {<br>
+               unsigned id;<br>
+               bool found = prog->UniformHash->get(id, var->name);<br>
+               assert(found);<br>
+               active_atomic_buffer &ab = abs[var->binding];<br>
+<br>
+               ab.counters.push_back(active_atomic_counter(id, var));<br></blockquote><div><br></div><div>Are uniform id's unique across program stages?  If not, it seems like we are losing information here.<br></div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+               ab.stage_references[i]++;<br>
+               ab.size = std::max(ab.size, var->atomic.offset +<br>
+                                  var->type->atomic_size());<br>
+            }<br>
+         }<br>
+      }<br>
+<br>
+      return abs;<br>
+   }<br>
+}<br>
+<br>
+void<br>
+link_assign_atomic_counter_resources(struct gl_shader_program *prog)<br>
+{<br>
+   active_atomic_buffers_t abs = find_active_atomic_counters(prog);<br>
+<br>
+   prog->AtomicBuffers = rzalloc_array(prog, gl_active_atomic_buffer,<br>
+                                       abs.size());<br>
+   prog->NumAtomicBuffers = abs.size();<br></blockquote><div><br></div><div>Similar to my comments above, I'd recommend renaming these to prog->AtomicBindingPoints and prog->NumAtomicBindingPoints.<br></div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+   unsigned i = 0;<br>
+   for (active_atomic_buffers_t::iterator it = abs.begin();<br>
+        it != abs.end(); ++it, ++i) {<br>
+      active_atomic_buffer &ab = it->second;<br>
+      gl_active_atomic_buffer &mab = prog->AtomicBuffers[i];<br>
+<br>
+      /* Assign buffer-specific fields. */<br>
+      mab.Binding = it->first;<br>
+      mab.MinimumSize = ab.size;<br>
+      mab.Uniforms = rzalloc_array(prog->AtomicBuffers, GLuint,<br>
+                                   ab.counters.size());<br>
+      mab.NumUniforms = ab.counters.size();<br>
+<br>
+      /* Assign counter-specific fields. */<br>
+      unsigned j = 0;<br>
+      for (active_atomic_counters_t::iterator jt = ab.counters.begin();<br>
+           jt != ab.counters.end(); ++jt, ++j) {<br>
+         ir_variable *var = jt->var;<br>
+         gl_uniform_storage &storage = prog->UniformStorage[jt->id];<br>
+<br>
+         mab.Uniforms[j] = jt->id;<br>
+         var->atomic.buffer_index = i;<br>
+         storage.atomic_buffer_index = i;<br>
+         storage.offset = var->atomic.offset;<br>
+         storage.array_stride = (var->type->is_array() ?<br>
+                                 var->type->element_type()->atomic_size() : 0);<br>
+      }<br>
+<br>
+      /* Assign stage-specific fields. */<br>
+      for (j = 0; j < MESA_SHADER_TYPES; ++j)<br>
+         mab.StageReferences[j] =<br>
+            (ab.stage_references[j] ? GL_TRUE : GL_FALSE);<br>
+   }<br>
+}<br>
+<br>
+void<br>
+link_check_atomic_counter_resources(struct gl_context *ctx,<br>
+                                    struct gl_shader_program *prog)<br>
+{<br></blockquote><div><br></div><div>Since this function relies so heavily on the assumption that the three shader types are vertex, geometry, and fragment, can we add a:<br><br></div><div>STATIC_ASSERT(MESA_SHADER_TYPES == 3);<br>
<br>here?  That way in the future when we add tessellation shaders we won't forget to fix it.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+   static const char *shader_names[MESA_SHADER_TYPES] = {<br>
+      "vertex", "geometry", "fragment"<br>
+   };<br>
+   const unsigned max_atomic_counters[MESA_SHADER_TYPES] = {<br>
+      ctx->Const.VertexProgram.MaxAtomicCounters,<br>
+      ctx->Const.GeometryProgram.MaxAtomicCounters,<br>
+      ctx->Const.FragmentProgram.MaxAtomicCounters<br>
+   };<br>
+   const unsigned max_atomic_buffers[MESA_SHADER_TYPES] = {<br>
+      ctx->Const.VertexProgram.MaxAtomicBuffers,<br>
+      ctx->Const.GeometryProgram.MaxAtomicBuffers,<br>
+      ctx->Const.FragmentProgram.MaxAtomicBuffers<br>
+   };<br>
+   active_atomic_buffers_t abs = find_active_atomic_counters(prog);<br>
+   unsigned atomic_counters[MESA_SHADER_TYPES] = {};<br>
+   unsigned atomic_buffers[MESA_SHADER_TYPES] = {};<br>
+   unsigned total_atomic_counters = 0;<br>
+   unsigned total_atomic_buffers = 0;<br>
+<br>
+   /* Sum the required resources.  Note that this counts buffers and<br>
+    * counters referenced by several shader stages multiple times<br>
+    * against the combined limit -- That's the behavior the spec<br>
+    * requires. */<br></blockquote><div><br></div><div>Style nit-pick: for multi-line comments we put the trailing "*/" on a line by itself.<br><br></div><div>With those minor issues addressed, the patch is:<br>
<br>Reviewed-by: Paul Berry <<a href="mailto:stereotype441@gmail.com">stereotype441@gmail.com</a>><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+   for (active_atomic_buffers_t::iterator it = abs.begin();<br>
+        it != abs.end(); ++it) {<br>
+      for (unsigned j = 0; j < MESA_SHADER_TYPES; ++j) {<br>
+         const unsigned n = it->second.stage_references[j];<br>
+<br>
+         if (n) {<br>
+            atomic_counters[j] += n;<br>
+            total_atomic_counters += n;<br>
+            atomic_buffers[j]++;<br>
+            total_atomic_buffers++;<br>
+         }<br>
+      }<br>
+   }<br>
+<br>
+   /* Check that they are within the supported limits. */<br>
+   for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {<br>
+      if (atomic_counters[i] > max_atomic_counters[i])<br>
+         linker_error(prog, "Too many %s shader atomic counters",<br>
+                      shader_names[i]);<br>
+<br>
+      if (atomic_buffers[i] > max_atomic_buffers[i])<br>
+         linker_error(prog, "Too many %s shader atomic counter buffers",<br>
+                      shader_names[i]);<br>
+   }<br>
+<br>
+   if (total_atomic_counters > ctx->Const.MaxCombinedAtomicCounters)<br>
+      linker_error(prog, "Too many combined atomic counters");<br>
+<br>
+   if (total_atomic_buffers > ctx->Const.MaxCombinedAtomicBuffers)<br>
+      linker_error(prog, "Too many combined atomic buffers");<br>
+}<br>
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp<br>
index 8a143fd..c317f46 100644<br>
--- a/src/glsl/linker.cpp<br>
+++ b/src/glsl/linker.cpp<br>
@@ -668,6 +668,14 @@ cross_validate_globals(struct gl_shader_program *prog,<br>
                existing->explicit_binding = true;<br>
             }<br>
<br>
+            if (var->type->atomic_size() &&<br>
+                var->atomic.offset != existing->atomic.offset) {<br>
+               linker_error(prog, "offset specifications for %s "<br>
+                            "`%s' have differing values\n",<br>
+                            mode_string(var), var->name);<br>
+               return;<br>
+            }<br>
+<br>
            /* Validate layout qualifiers for gl_FragDepth.<br>
             *<br>
             * From the AMD/ARB_conservative_depth specs:<br>
@@ -1857,6 +1865,10 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)<br>
       prog->UniformBlockStageIndex[i] = NULL;<br>
    }<br>
<br>
+   ralloc_free(prog->AtomicBuffers);<br>
+   prog->AtomicBuffers = NULL;<br>
+   prog->NumAtomicBuffers = 0;<br>
+<br>
    /* Separate the shaders into groups based on their type.<br>
     */<br>
    struct gl_shader **vert_shader_list;<br>
@@ -2211,9 +2223,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)<br>
<br>
    update_array_sizes(prog);<br>
    link_assign_uniform_locations(prog);<br>
+   link_assign_atomic_counter_resources(prog);<br>
    store_fragdepth_layout(prog);<br>
<br>
    check_resources(ctx, prog);<br>
+   link_check_atomic_counter_resources(ctx, prog);<br>
+<br>
    if (!prog->LinkStatus)<br>
       goto done;<br>
<br>
diff --git a/src/glsl/linker.h b/src/glsl/linker.h<br>
index 8a0027d..893294a 100644<br>
--- a/src/glsl/linker.h<br>
+++ b/src/glsl/linker.h<br>
@@ -70,6 +70,13 @@ validate_interstage_interface_blocks(struct gl_shader_program *prog,<br>
                                      const gl_shader *producer,<br>
                                      const gl_shader *consumer);<br>
<br>
+extern void<br>
+link_assign_atomic_counter_resources(struct gl_shader_program *prog);<br>
+<br>
+extern void<br>
+link_check_atomic_counter_resources(struct gl_context *ctx,<br>
+                                    struct gl_shader_program *prog);<br>
+<br>
 /**<br>
  * Class for processing all of the leaf fields of a variable that corresponds<br>
  * to a program resource.<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.3.4<br>
<br>
_______________________________________________<br>
mesa-dev mailing list<br>
<a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev" target="_blank">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</font></span></blockquote></div><br></div></div>