<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Mon, Oct 8, 2018 at 10:22 AM Alejandro Piñeiro <<a href="mailto:apinheiro@igalia.com">apinheiro@igalia.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I was not able to finish trying to get ARB_gl_spirv using this pass. The<br>
major difference is that on ARB_gl_spirv (and afaiu on GLSL too) we are<br>
merging the info of all the available xfb varyings from all the stages,<br>
while this pass gathers info from a individual nir shader (so one<br>
individual stage).<br>
<br>
Having said so, while using this pass, I found some issues/questions,<br>
see below inline.<br>
<br>
<br>
On 05/10/18 16:13, Jason Ekstrand wrote:<br>
> This is different from the GL_ARB_spirv pass because it generates a much<br>
> simpler data structure that isn't tied to OpenGL and mtypes.h.<br>
> ---<br>
>  src/compiler/Makefile.sources          |   4 +-<br>
>  src/compiler/nir/meson.build           |   2 +<br>
>  src/compiler/nir/nir_gather_xfb_info.c | 150 +++++++++++++++++++++++++<br>
>  src/compiler/nir/nir_xfb_info.h        |  59 ++++++++++<br>
>  4 files changed, 214 insertions(+), 1 deletion(-)<br>
>  create mode 100644 src/compiler/nir/nir_gather_xfb_info.c<br>
>  create mode 100644 src/compiler/nir/nir_xfb_info.h<br>
><br>
> diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources<br>
> index d3b06564832..46ed5e47b46 100644<br>
> --- a/src/compiler/Makefile.sources<br>
> +++ b/src/compiler/Makefile.sources<br>
> @@ -216,6 +216,7 @@ NIR_FILES = \<br>
>       nir/nir_format_convert.h \<br>
>       nir/nir_from_ssa.c \<br>
>       nir/nir_gather_info.c \<br>
> +     nir/nir_gather_xfb_info.c \<br>
>       nir/nir_gs_count_vertices.c \<br>
>       nir/nir_inline_functions.c \<br>
>       nir/nir_instr_set.c \<br>
> @@ -307,7 +308,8 @@ NIR_FILES = \<br>
>       nir/nir_validate.c \<br>
>       nir/nir_vla.h \<br>
>       nir/nir_worklist.c \<br>
> -     nir/nir_worklist.h<br>
> +     nir/nir_worklist.h \<br>
> +     nir/nir_xfb_info.h<br>
>  <br>
>  SPIRV_GENERATED_FILES = \<br>
>       spirv/spirv_info.c \<br>
> diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build<br>
> index 090aa7a628f..b416e561eb0 100644<br>
> --- a/src/compiler/nir/meson.build<br>
> +++ b/src/compiler/nir/meson.build<br>
> @@ -100,6 +100,7 @@ files_libnir = files(<br>
>    'nir_format_convert.h',<br>
>    'nir_from_ssa.c',<br>
>    'nir_gather_info.c',<br>
> +  'nir_gather_xfb_info.c',<br>
>    'nir_gs_count_vertices.c',<br>
>    'nir_inline_functions.c',<br>
>    'nir_instr_set.c',<br>
> @@ -192,6 +193,7 @@ files_libnir = files(<br>
>    'nir_vla.h',<br>
>    'nir_worklist.c',<br>
>    'nir_worklist.h',<br>
> +  'nir_xfb_info.h',<br>
>    '../spirv/GLSL.ext.AMD.h',<br>
>    '../spirv/GLSL.std.450.h',<br>
>    '../spirv/gl_spirv.c',<br>
> diff --git a/src/compiler/nir/nir_gather_xfb_info.c b/src/compiler/nir/nir_gather_xfb_info.c<br>
> new file mode 100644<br>
> index 00000000000..a53703bb9bf<br>
> --- /dev/null<br>
> +++ b/src/compiler/nir/nir_gather_xfb_info.c<br>
> @@ -0,0 +1,150 @@<br>
> +/*<br>
> + * Copyright © 2018 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 DEALINGS<br>
> + * IN THE SOFTWARE.<br>
> + */<br>
> +<br>
> +#include "nir_xfb_info.h"<br>
> +<br>
> +#include <util/u_math.h><br>
> +<br>
> +static void<br>
> +add_var_xfb_outputs(nir_xfb_info *xfb,<br>
> +                    nir_variable *var,<br>
> +                    unsigned *location,<br>
> +                    unsigned *offset,<br>
> +                    const struct glsl_type *type)<br>
> +{<br>
> +   if (glsl_type_is_array(type) || glsl_type_is_matrix(type)) {<br>
> +      unsigned length = glsl_get_length(type);<br>
> +      const struct glsl_type *child_type = glsl_get_array_element(type);<br>
> +      for (unsigned i = 0; i < length; i++)<br>
> +         add_var_xfb_outputs(xfb, var, location, offset, child_type);<br>
> +   } else if (glsl_type_is_struct(type)) {<br>
> +      unsigned length = glsl_get_length(type);<br>
> +      for (unsigned i = 0; i < length; i++) {<br>
> +         const struct glsl_type *child_type = glsl_get_struct_field(type, i);<br>
> +         add_var_xfb_outputs(xfb, var, location, offset, child_type);<br>
> +      }<br>
> +   } else {<br>
> +      assert(var->data.xfb_buffer < NIR_MAX_XFB_BUFFERS);<br>
> +      if (xfb->buffers_written & (1 << var->data.xfb_buffer)) {<br>
> +         assert(xfb->strides[var->data.xfb_buffer] == var->data.xfb_stride);<br>
> +         assert(xfb->buffer_to_stream[var->data.xfb_buffer] == var->data.stream);<br>
> +      } else {<br>
> +         xfb->buffers_written |= (1 << var->data.xfb_buffer);<br>
> +         xfb->strides[var->data.xfb_buffer] = var->data.xfb_stride;<br>
> +         xfb->buffer_to_stream[var->data.xfb_buffer] = var->data.stream;<br>
> +      }<br>
> +<br>
> +      assert(var->data.stream < NIR_MAX_XFB_STREAMS);<br>
> +      xfb->streams_written |= (1 << var->data.stream);<br>
> +<br>
> +      unsigned comp_slots = glsl_get_component_slots(type);<br>
> +      unsigned attrib_slots = DIV_ROUND_UP(comp_slots, 4);<br>
> +      assert(attrib_slots == glsl_count_attribute_slots(type, false));<br>
> +<br>
> +      /* Ensure that we don't have, for instance, a dvec2 with a location_frac<br>
> +       * of 2 which would make it crass a location boundary even though it<br>
> +       * fits in a single slot.  However, you can have a dvec3 which crosses<br>
> +       * the slot boundary with a location_frac of 2.<br>
> +       */<br>
> +      assert(DIV_ROUND_UP(var->data.location_frac + comp_slots, 4) == attrib_slots);<br>
> +<br>
> +      assert(var->data.location_frac + comp_slots <= 8);<br>
> +      uint8_t comp_mask = ((1 << comp_slots) - 1) << var->data.location_frac;<br>
> +<br>
> +      assert(attrib_slots <= 2);<br>
> +      for (unsigned s = 0; s < attrib_slots; s++) {<br>
> +         nir_xfb_output_info *output = &xfb->outputs[xfb->output_count++];<br>
> +<br>
> +         output->buffer = var->data.xfb_buffer;<br>
> +         output->offset = *offset;<br>
> +         output->location = *location;<br>
> +         output->component_mask = (comp_mask >> (s * 4)) & 0xf;<br>
> +<br>
> +         (*location)++;<br>
> +         *offset += comp_slots * 4;<br>
> +      }<br>
> +   }<br>
> +}<br>
> +<br>
> +static int<br>
> +compare_xfb_output_offsets(const void *_a, const void *_b)<br>
> +{<br>
> +   const nir_xfb_output_info *a = _a, *b = _b;<br>
> +   return a->offset - b->offset;<br>
> +}<br>
> +<br>
> +nir_xfb_info *<br>
> +nir_gather_xfb_info(const nir_shader *shader, void *mem_ctx)<br>
> +{<br>
> +   assert(shader->info.stage == MESA_SHADER_VERTEX ||<br>
> +          shader->info.stage == MESA_SHADER_TESS_EVAL ||<br>
> +          shader->info.stage == MESA_SHADER_GEOMETRY);<br>
> +<br>
> +   /* Compute the number of outputs we have.  This is simply the number of<br>
> +    * cumulative locations consumed by all the variables.  If a location is<br>
> +    * represented by multiple variables, then they each count separately in<br>
> +    * number of outputs.<br>
> +    */<br>
> +   unsigned num_outputs = 0;<br>
> +   nir_foreach_variable(var, &shader->outputs) {<br>
> +      if (var->data.explicit_xfb_buffer ||<br>
> +          var->data.explicit_xfb_stride) {<br>
> +         assert(var->data.explicit_xfb_buffer &&<br>
> +                var->data.explicit_xfb_stride &&<br>
> +                var->data.explicit_offset);<br>
<br>
OpenGL specific: FWIW, I'm getting this assert raised really easy. It<br>
seems that glslangValidator adds a implicitly-generated output for<br>
gl_PerVertex, and although it sets the stride and buffer, it doesn't do<br>
the same for the offset. Will check a little glslang later, and likely<br>
open a issue for it.<br></blockquote><div><br></div><div>Yes, there are GLSLang bugs.  I believe those are getting addressed.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +         num_outputs += glsl_count_attribute_slots(var->type, false);<br>
> +      }<br>
> +   }<br>
> +   if (num_outputs == 0)<br>
> +      return NULL;<br>
> +<br>
> +   nir_xfb_info *xfb = rzalloc_size(mem_ctx, nir_xfb_info_size(num_outputs));<br>
> +<br>
> +   /* Walk the list of outputs and add them to the array */<br>
> +   nir_foreach_variable(var, &shader->outputs) {<br>
> +      if (var->data.explicit_xfb_buffer ||<br>
> +          var->data.explicit_xfb_stride) {<br>
> +         unsigned location = var->data.location;<br>
> +         unsigned offset = var->data.offset;<br>
> +         add_var_xfb_outputs(xfb, var, &location, &offset, var->type);<br>
> +      }<br>
> +   }<br>
> +   assert(xfb->output_count == num_outputs);<br>
> +<br>
> +   /* Everything is easier in the state setup code if the list is sorted in<br>
> +    * order of output offset.<br>
> +    */<br>
> +   qsort(xfb->outputs, xfb->output_count, sizeof(xfb->outputs[0]),<br>
> +         compare_xfb_output_offsets);<br>
> +<br>
> +   /* Finally, do a sanity check */<br>
> +   unsigned max_offset[NIR_MAX_XFB_BUFFERS] = { };<br>
> +   for (unsigned i = 0; i < xfb->output_count; i++) {<br>
> +      assert(xfb->outputs[i].offset >= max_offset[xfb->outputs[i].buffer]);<br>
<br>
Shouldn't this be offset <= max_offset?<br></blockquote><div><br></div><div>No, this sanity check (which I should have commented better) is checking for overlap.  Since we know that the array is already sorted by offset, we can easily check for overlap by asserting that the offsets are monotonically increasing on a per-buffer basis.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +      assert(xfb->outputs[i].component_mask != 0);<br>
> +      unsigned slots = util_bitcount(xfb->outputs[i].component_mask);<br>
> +      max_offset[xfb->outputs[i].buffer] = xfb->outputs[i].offset + slots * 4;<br>
<br>
Additionally, I'm getting the previous assert triggered with tests using<br>
doubles, so I'm guessing if we are taking into account them here.<br></blockquote><div><br></div><div>That's very possible.  This hasn't been tested with doubles though I did think about them while writing it.  The component_mask is supposed to be in 32-bit units so any doubles should show up as two slots per component.  So, yes, I'm sure there's a bug and we need better testing before this lands.</div><div><br></div><div>--Jason<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +   }<br>
> +<br>
> +   return xfb;<br>
> +}<br>
> diff --git a/src/compiler/nir/nir_xfb_info.h b/src/compiler/nir/nir_xfb_info.h<br>
> new file mode 100644<br>
> index 00000000000..9b543df5f47<br>
> --- /dev/null<br>
> +++ b/src/compiler/nir/nir_xfb_info.h<br>
> @@ -0,0 +1,59 @@<br>
> +/*<br>
> + * Copyright © 2018 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 DEALINGS<br>
> + * IN THE SOFTWARE.<br>
> + */<br>
> +<br>
> +#ifndef NIR_XFB_INFO_H<br>
> +#define NIR_XFB_INFO_H<br>
> +<br>
> +#include "nir.h"<br>
> +<br>
> +#define NIR_MAX_XFB_BUFFERS 4<br>
> +#define NIR_MAX_XFB_STREAMS 4<br>
> +<br>
> +typedef struct {<br>
> +   uint8_t buffer;<br>
> +   uint16_t offset;<br>
> +   uint8_t location;<br>
> +   uint8_t component_mask;<br>
> +} nir_xfb_output_info;<br>
> +<br>
> +typedef struct {<br>
> +   uint8_t buffers_written;<br>
> +   uint8_t streams_written;<br>
> +<br>
> +   uint16_t strides[NIR_MAX_XFB_BUFFERS];<br>
> +   uint8_t buffer_to_stream[NIR_MAX_XFB_STREAMS];<br>
> +<br>
> +   uint16_t output_count;<br>
> +   nir_xfb_output_info outputs[0];<br>
> +} nir_xfb_info;<br>
> +<br>
> +static inline size_t<br>
> +nir_xfb_info_size(uint16_t output_count)<br>
> +{<br>
> +   return sizeof(nir_xfb_info) + sizeof(nir_xfb_output_info) * output_count;<br>
> +}<br>
> +<br>
> +nir_xfb_info *<br>
> +nir_gather_xfb_info(const nir_shader *shader, void *mem_ctx);<br>
> +<br>
> +#endif /* NIR_XFB_INFO_H */<br>
<br>
<br>
</blockquote></div></div>