<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>