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