<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">Acked-by: Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br><br>On Mon, Apr 24, 2017 at 8:28 AM, Rob Clark <span dir="ltr"><<a href="mailto:robdclark@gmail.com" target="_blank">robdclark@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This is equivalent to what mesa/st does in glsl_to_tgsi.  For most hw<br>
there isn't a particularly good reason to treat these differently.<br>
<br>
Signed-off-by: Rob Clark <<a href="mailto:robdclark@gmail.com">robdclark@gmail.com</a>><br>
---<br>
v2: do the interface_type thing properly<br>
<br>
 src/compiler/Makefile.sources                |   1 +<br>
 src/compiler/nir/nir.h                       |   1 +<br>
 src/compiler/nir/nir_lower_<wbr>atomics_to_ssbo.c | 222 +++++++++++++++++++++++++++<br>
 3 files changed, 224 insertions(+)<br>
 create mode 100644 src/compiler/nir/nir_lower_<wbr>atomics_to_ssbo.c<br>
<br>
diff --git a/src/compiler/Makefile.<wbr>sources b/src/compiler/Makefile.<wbr>sources<br>
index 2455d4e..b2a3a42 100644<br>
--- a/src/compiler/Makefile.<wbr>sources<br>
+++ b/src/compiler/Makefile.<wbr>sources<br>
@@ -208,6 +208,7 @@ NIR_FILES = \<br>
        nir/nir_lower_64bit_packing.c \<br>
        nir/nir_lower_alu_to_scalar.c \<br>
        nir/nir_lower_atomics.c \<br>
+       nir/nir_lower_atomics_to_ssbo.<wbr>c \<br>
        nir/nir_lower_bitmap.c \<br>
        nir/nir_lower_clamp_color_<wbr>outputs.c \<br>
        nir/nir_lower_clip.c \<br>
diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h<br>
index ce5b434..be35930 100644<br>
--- a/src/compiler/nir/nir.h<br>
+++ b/src/compiler/nir/nir.h<br>
@@ -2546,6 +2546,7 @@ void nir_lower_bitmap(nir_shader *shader, const nir_lower_bitmap_options *option<br>
<br>
 bool nir_lower_atomics(nir_shader *shader,<br>
                        const struct gl_shader_program *shader_program);<br>
+bool nir_lower_atomics_to_ssbo(nir_<wbr>shader *shader, unsigned ssbo_offset);<br>
 bool nir_lower_to_source_mods(nir_<wbr>shader *shader);<br>
<br>
 bool nir_lower_gs_intrinsics(nir_<wbr>shader *shader);<br>
diff --git a/src/compiler/nir/nir_lower_<wbr>atomics_to_ssbo.c b/src/compiler/nir/nir_lower_<wbr>atomics_to_ssbo.c<br>
new file mode 100644<br>
index 0000000..2c04485<br>
--- /dev/null<br>
+++ b/src/compiler/nir/nir_lower_<wbr>atomics_to_ssbo.c<br>
@@ -0,0 +1,222 @@<br>
+/*<br>
+ * Copyright © 2017 Red Hat<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 DEALINGS<br>
+ * IN THE SOFTWARE.<br>
+ *<br>
+ * Authors:<br>
+ *    Rob Clark <<a href="mailto:robclark@freedesktop.org">robclark@freedesktop.org</a>><br>
+ */<br>
+<br>
+#include "nir.h"<br>
+#include "nir_builder.h"<br>
+<br>
+/*<br>
+ * Remap atomic counters to SSBOs.  Atomic counters get remapped to<br>
+ * SSBO binding points [0..ssbo_offset) and the original SSBOs are<br>
+ * remapped to [ssbo_offset..n) (mostly to align with what mesa/st<br>
+ * does.<br>
+ */<br>
+<br>
+static bool<br>
+lower_instr(nir_intrinsic_<wbr>instr *instr, unsigned ssbo_offset, nir_builder *b)<br>
+{<br>
+   nir_intrinsic_op op;<br>
+   switch (instr->intrinsic) {<br>
+   case nir_intrinsic_ssbo_atomic_add:<br>
+   case nir_intrinsic_ssbo_atomic_<wbr>imin:<br>
+   case nir_intrinsic_ssbo_atomic_<wbr>umin:<br>
+   case nir_intrinsic_ssbo_atomic_<wbr>imax:<br>
+   case nir_intrinsic_ssbo_atomic_<wbr>umax:<br>
+   case nir_intrinsic_ssbo_atomic_and:<br>
+   case nir_intrinsic_ssbo_atomic_or:<br>
+   case nir_intrinsic_ssbo_atomic_xor:<br>
+   case nir_intrinsic_ssbo_atomic_<wbr>exchange:<br>
+   case nir_intrinsic_ssbo_atomic_<wbr>comp_swap:<br>
+   case nir_intrinsic_store_ssbo:<br>
+   case nir_intrinsic_load_ssbo:<br>
+      /* keep same opcode, remap buffer_index */<br>
+      op = instr->intrinsic;<br>
+      break;<br>
+   case nir_intrinsic_atomic_counter_<wbr>inc:<br>
+   case nir_intrinsic_atomic_counter_<wbr>add:<br>
+   case nir_intrinsic_atomic_counter_<wbr>dec:<br>
+      /* inc and dec get remapped to add: */<br>
+      op = nir_intrinsic_ssbo_atomic_add;<br>
+      break;<br>
+   case nir_intrinsic_atomic_counter_<wbr>read:<br>
+      op = nir_intrinsic_load_ssbo;<br>
+      break;<br>
+   case nir_intrinsic_atomic_counter_<wbr>min:<br>
+      op = nir_intrinsic_ssbo_atomic_<wbr>umin;<br>
+      break;<br>
+   case nir_intrinsic_atomic_counter_<wbr>max:<br>
+      op = nir_intrinsic_ssbo_atomic_<wbr>umax;<br>
+      break;<br>
+   case nir_intrinsic_atomic_counter_<wbr>and:<br>
+      op = nir_intrinsic_ssbo_atomic_and;<br>
+      break;<br>
+   case nir_intrinsic_atomic_counter_<wbr>or:<br>
+      op = nir_intrinsic_ssbo_atomic_or;<br>
+      break;<br>
+   case nir_intrinsic_atomic_counter_<wbr>xor:<br>
+      op = nir_intrinsic_ssbo_atomic_xor;<br>
+      break;<br>
+   case nir_intrinsic_atomic_counter_<wbr>exchange:<br>
+      op = nir_intrinsic_ssbo_atomic_<wbr>exchange;<br>
+      break;<br>
+   case nir_intrinsic_atomic_counter_<wbr>comp_swap:<br>
+      op = nir_intrinsic_ssbo_atomic_<wbr>comp_swap;<br>
+      break;<br>
+   default:<br>
+      return false;<br>
+   }<br>
+<br>
+   b->cursor = nir_before_instr(&instr-><wbr>instr);<br>
+<br>
+   /* easy case, just remap SSBO buffer index: */<br>
+   if (op == instr->intrinsic) {<br>
+      unsigned srcn = (op == nir_intrinsic_store_ssbo) ? 1 : 0;<br></blockquote><div><br></div><div>Maybe call this idx_src?  Also, this whole chunk could go in the switch statement rather than breaking and handling it here.  Might be a bit more clear.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      nir_ssa_def *old_idx = nir_ssa_for_src(b, instr->src[srcn], 1);<br>
+      nir_ssa_def *new_idx = nir_iadd(b, old_idx, nir_imm_int(b, ssbo_offset));<br>
+      nir_instr_rewrite_src(&instr-><wbr>instr,<br>
+                            &instr->src[srcn],<br>
+                            nir_src_for_ssa(new_idx));<br>
+<br>
+      return true;<br>
+   }<br>
+<br>
+   nir_ssa_def *buffer = nir_imm_int(b, nir_intrinsic_base(instr));<br>
+   nir_ssa_def *temp = NULL;<br>
+   nir_intrinsic_instr *new_instr =<br>
+         nir_intrinsic_instr_create(<wbr>ralloc_parent(instr), op);<br>
+<br>
+   /* a couple instructions need special handling since they don't map<br>
+    * 1:1 with ssbo atomics<br>
+    */<br>
+   switch (instr->intrinsic) {<br>
+   case nir_intrinsic_atomic_counter_<wbr>inc:<br>
+      /* remapped to ssbo_atomic_add: { buffer_idx, offset, +1 } */<br>
+      temp = nir_imm_int(b, +1);<br>
+      new_instr->src[0] = nir_src_for_ssa(buffer);<br>
+      new_instr->src[1] = instr->src[0];<br>
+      new_instr->src[2] = nir_src_for_ssa(temp);<br>
+      break;<br>
+   case nir_intrinsic_atomic_counter_<wbr>dec:<br>
+      /* remapped to ssbo_atomic_add: { buffer_idx, offset, -1 } */<br>
+      /* NOTE semantic difference so we adjust the return value below */<br>
+      temp = nir_imm_int(b, -1);<br>
+      new_instr->src[0] = nir_src_for_ssa(buffer);<br>
+      new_instr->src[1] = instr->src[0];<br>
+      new_instr->src[2] = nir_src_for_ssa(temp);<br>
+      break;<br>
+   case nir_intrinsic_atomic_counter_<wbr>read:<br>
+      /* remapped to load_ssbo: { buffer_idx, offset } */<br>
+      new_instr->src[0] = nir_src_for_ssa(buffer);<br>
+      new_instr->src[1] = instr->src[0];<br>
+      break;<br>
+   default:<br>
+      /* remapped to ssbo_atomic_x: { buffer_idx, offset, data, (compare)? } */<br>
+      new_instr->src[0] = nir_src_for_ssa(buffer);<br>
+      new_instr->src[1] = instr->src[0];<br>
+      new_instr->src[2] = instr->src[1];<br>
+      if (op == nir_intrinsic_ssbo_atomic_<wbr>comp_swap)<br>
+         new_instr->src[3] = instr->src[2];<br>
+      break;<br>
+   }<br>
+<br>
+   nir_ssa_dest_init(&new_instr-><wbr>instr, &new_instr->dest,<br>
+                     instr->dest.ssa.num_<wbr>components,<br>
+                     instr->dest.ssa.bit_size, NULL);<br>
+   nir_instr_insert_before(&<wbr>instr->instr, &new_instr->instr);<br>
+   nir_instr_remove(&instr-><wbr>instr);<br>
+<br>
+   if (instr->intrinsic == nir_intrinsic_atomic_counter_<wbr>dec) {<br>
+      b->cursor = nir_after_instr(&new_instr-><wbr>instr);<br>
+      nir_ssa_def *result = nir_iadd(b, &new_instr->dest.ssa, temp);<br>
+      nir_ssa_def_rewrite_uses(&<wbr>instr->dest.ssa, nir_src_for_ssa(result));<br>
+   } else {<br>
+      nir_ssa_def_rewrite_uses(&<wbr>instr->dest.ssa, nir_src_for_ssa(&new_instr-><wbr>dest.ssa));<br>
+   }<br>
+<br>
+   return true;<br>
+}<br>
+<br>
+bool<br>
+nir_lower_atomics_to_ssbo(<wbr>nir_shader *shader, unsigned ssbo_offset)<br>
+{<br>
+   bool progress = false;<br>
+<br>
+   nir_foreach_function(function, shader) {<br>
+      if (function->impl) {<br>
+         nir_builder builder;<br>
+         nir_builder_init(&builder, function->impl);<br>
+         nir_foreach_block(block, function->impl) {<br>
+            nir_foreach_instr_safe(instr, block) {<br>
+               if (instr->type == nir_instr_type_intrinsic)<br>
+                  progress |= lower_instr(nir_instr_as_<wbr>intrinsic(instr),<br>
+                                          ssbo_offset, &builder);<br>
+            }<br>
+         }<br>
+<br>
+         nir_metadata_preserve(<wbr>function->impl, nir_metadata_block_index |<br>
+                                               nir_metadata_dominance);<br>
+      }<br>
+   }<br>
+<br>
+   if (progress) {<br>
+      /* replace atomic_uint uniforms with ssbo's: */<br>
+      unsigned replaced = 0;<br>
+      nir_foreach_variable_safe(var, &shader->uniforms) {<br>
+         if (glsl_get_base_type(var->type) == GLSL_TYPE_ATOMIC_UINT) {<br>
+            exec_node_remove(&var->node);<br>
+<br>
+            if (replaced & (1 << var->data.binding))<br>
+               continue;<br>
+<br>
+            nir_variable *ssbo;<br>
+            char name[16];<br>
+<br>
+            /* A length of 0 is used to denote unsized arrays */<br>
+            const struct glsl_type *type = glsl_array_type(glsl_uint_<wbr>type(), 0);<br>
+<br>
+            snprintf(name, sizeof(name), "counter%d", var->data.binding);<br>
+<br>
+            ssbo = nir_variable_create(shader, nir_var_shader_storage,<br>
+                                       type, name);<br>
+            ssbo->data.binding = var->data.binding;<br>
+<br>
+            struct glsl_struct_field field = {<br>
+                  .type = type,<br>
+                  .name = "counters",<br>
+                  .location = -1,<br>
+            };<br>
+<br>
+            ssbo->interface_type =<br>
+                  glsl_interface_type(&field, 1, GLSL_INTERFACE_PACKING_STD430,<br>
+                                      false, "counters");<br>
+<br>
+            replaced |= (1 << var->data.binding);<br>
+         }<br>
+      }<br>
+   }<br>
+<br>
+   return progress;<br>
+}<br>
+<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.9.3<br>
<br>
</font></span></blockquote></div><br></div></div>