<div dir="ltr">On 29 October 2013 16:37, 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"><div class="im">v2: Add comments on the purpose of the auxiliary data structures.<br>
    Check for atomic counter overlaps.  Use the contains_atomic()<br>
    convenience method.  Add static assert with the number of expected<br>
    shader stages.<br>
<br>
</div>v3: Don't resize atomic arrays.<br>
<div class="im">---<br>
 src/glsl/Makefile.sources |   1 +<br>
 src/glsl/link_atomics.cpp | 237 ++++++++++++++++++++++++++++++++++++++++++++++<br>
</div> src/glsl/linker.cpp       |  17 +++-<br>
 src/glsl/linker.h         |   7 ++<br>
 4 files changed, 261 insertions(+), 1 deletion(-)<br>
<div><div class="h5"> 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..5a3d769<br>
--- /dev/null<br>
+++ b/src/glsl/link_atomics.cpp<br>
@@ -0,0 +1,237 @@<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 <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>
+   /*<br>
+    * Atomic counter as seen by the program.<br>
+    */<br>
+   struct active_atomic_counter {<br>
+      active_atomic_counter() : id(), var() {}<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>
+   /**<br>
+    * Active atomic buffer indexed by offset.<br>
+    */<br>
+   typedef std::map<unsigned, active_atomic_counter> active_atomic_counters_t;<br>
+<br>
+   /*<br>
+    * Atomic counter buffer referenced by the program.  There is a one<br>
+    * to one correspondence between these and the objects that can be<br>
+    * queried using glGetActiveAtomicCounterBufferiv().<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>
+      unsigned size;<br>
+   };<br>
+<br>
+   /**<br>
+    * Active atomic buffer indexed by binding point.<br>
+    */<br>
+   typedef std::map<unsigned, active_atomic_buffer> active_atomic_buffers_t;<br>
+<br>
+   bool<br>
+   check_atomic_counters_overlap(const ir_variable *x, const ir_variable *y)<br>
+   {<br>
+      return ((x->atomic.offset >= y->atomic.offset &&<br>
+               x->atomic.offset < y->atomic.offset + y->type->atomic_size()) ||<br>
+              (y->atomic.offset >= x->atomic.offset &&<br>
+               y->atomic.offset < x->atomic.offset + x->type->atomic_size()));<br>
+   }<br>
+<br>
+   bool<br>
+   check_atomic_counter_location(const active_atomic_buffer &ab,<br>
+                                 const ir_variable *var)<br>
+   {<br>
+      active_atomic_counters_t::const_iterator adjacent =<br>
+         ab.counters.upper_bound(var->atomic.offset);<br>
+<br>
+      if ((adjacent != ab.counters.end() &&<br>
+           check_atomic_counters_overlap(adjacent->second.var, var)) ||<br>
+          (adjacent != ab.counters.begin() &&<br>
+           check_atomic_counters_overlap((--adjacent)->second.var, var))) {<br>
+         /* Overlapping counter found, it must be a reference to the<br>
+          * same counter from a different shader stage.<br>
+          */<br>
+         return !strcmp(var->name, adjacent->second.var->name);<br></div></div></blockquote><div><br></div><div>Personally I prefer "strcmp(...) == 0" to "!strcmp(...)" because with the latter, I'm liable to accidentally turn it around in my brain and think it means "strings not equal".  But I won't be a stickler about it.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5">
+      } else {<br>
+         return true;<br>
+      }<br>
+   }<br>
+<br>
+   active_atomic_buffers_t<br>
+   find_active_atomic_counters(struct gl_shader_program *prog)<br>
+   {<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->contains_atomic()) {<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>
+               if (check_atomic_counter_location(ab, var)) {<br>
+                  ab.counters[var->atomic.offset] =<br>
+                     active_atomic_counter(id, var);<br>
+                  ab.stage_references[i]++;<br>
+                  ab.size = std::max(ab.size, var->atomic.offset +<br>
+                                     var->type->atomic_size());<br>
+               } else {<br>
+                  linker_error(prog, "Atomic counter %s declared at offset %d "<br>
+                               "which is already in use.", var->name,<br>
+                               var->atomic.offset);<br>
+               }<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>
+<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->second.var;<br>
+         gl_uniform_storage &storage = prog->UniformStorage[jt-><a href="http://second.id" target="_blank">second.id</a>];<br>
+<br>
+         mab.Uniforms[j] = jt-><a href="http://second.id" target="_blank">second.id</a>;<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>
+   STATIC_ASSERT(MESA_SHADER_TYPES == 3);<br>
+   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>
+    */<br>
+   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>
</div></div>index 495a2ab..bbff2b7 100644<br>
--- a/src/glsl/linker.cpp<br>
+++ b/src/glsl/linker.cpp<br>
@@ -674,6 +674,14 @@ cross_validate_globals(struct gl_shader_program *prog,<br>
<div class="im">                existing->explicit_binding = true;<br>
             }<br>
<br>
+            if (var->type->contains_atomic() &&<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>
</div>@@ -1509,7 +1517,7 @@ update_array_sizes(struct gl_shader_program *prog)<br>
          * will not be eliminated.  Since we always do std140, just<br>
          * don't resize arrays in UBOs.<br>
          */<br>
-        if (var->is_in_uniform_block())<br>
+        if (var->is_in_uniform_block() || var->type->contains_atomic())<br></blockquote><div><br></div><div>Can you please update the comment above this "if" statement to explain why we're not resizing arrays containing atomics?<br>
<br></div><div>WIth that change, the patch is:<br><br></div><div>Reviewed-by: Paul Berry <<a href="mailto:stereotype441@gmail.com">stereotype441@gmail.com</a>><br><br></div><div>As with the previous patch, I don't think we can land this until we resolve the open question about whether STL is allowed in Mesa.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
            continue;<br>
<br>
         unsigned int size = var->max_array_access;<br>
@@ -2014,6 +2022,10 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)<br>
<div class="im">       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>
</div>@@ -2365,9 +2377,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)<br>
<div class="im"><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>
</div>index 887cd33..3380151 100644<br>
--- a/src/glsl/linker.h<br>
+++ b/src/glsl/linker.h<br>
@@ -69,6 +69,13 @@ validate_interstage_interface_blocks(struct gl_shader_program *prog,<br>
<div class="HOEnZb"><div class="h5">                                      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>
--<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>
</div></div></blockquote></div><br></div></div>