Mesa (main): zink: improve/expand manual xfb emission

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Jun 10 02:49:40 UTC 2022


Module: Mesa
Branch: main
Commit: 24725e572eb7814d3cf279b5733d1ea5c4f55cf6
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=24725e572eb7814d3cf279b5733d1ea5c4f55cf6

Author: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Date:   Fri May 20 20:12:57 2022 -0400

zink: improve/expand manual xfb emission

I left this semi-unfinished back when I discovered that I could blast
out xfb values inline with variable declarations, but this is not viable
for all scenarios, so it has to work and it has to be able to pass cts

Reviewed-by: Adam Jackson <ajax at redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16669>

---

 .../drivers/zink/nir_to_spirv/nir_to_spirv.c       | 236 ++++++++++++++++-----
 1 file changed, 178 insertions(+), 58 deletions(-)

diff --git a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c
index 18521103f10..aa4b58be82f 100644
--- a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c
+++ b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c
@@ -1490,79 +1490,199 @@ emit_so_outputs(struct ntv_context *ctx,
 
       SpvId result;
 
-      for (unsigned c = 0; c < so_output.num_components; c++) {
-         components[c] = so_output.start_component + c;
-         /* this is the second half of a 2 * vec4 array */
-         if (slot == VARYING_SLOT_CLIP_DIST1)
-            components[c] += 4;
-      }
-
+      /* this is the type being indexed into */
       const struct glsl_type *bare_type = glsl_without_array(out_type);
-      if (glsl_type_is_struct_or_ifc(bare_type)) {
-         uint32_t base_slot = (location & ~so_output.start_component) / 4;
-         unsigned slot_idx = slot - base_slot;
-         unsigned struct_slots = glsl_count_vec4_slots(bare_type, false, false);
-         unsigned array_idx = slot_idx / struct_slots;
-         slot_idx %= glsl_count_vec4_slots(bare_type, false, false);
-         src = spirv_builder_emit_composite_extract(&ctx->builder, get_glsl_type(ctx, bare_type), src, &array_idx, 1);
-         /* need to find the vec4 that's being exported by this slot */
-         while (glsl_type_is_struct_or_ifc(bare_type))
-            bare_type = unroll_struct_type(ctx, bare_type, &slot_idx, &src, &out_type);
-         output_type = get_glsl_type(ctx, out_type);
-         if (glsl_type_is_vector_or_scalar(out_type))
-            src = emit_bitcast(ctx, type, src);
-         else if (glsl_type_is_array(out_type)) {
-             for (unsigned c = 0; c < so_output.num_components; c++) {
-                uint32_t member = so_output.start_component + c;
-                SpvId base_type = get_glsl_basetype(ctx, glsl_get_base_type(glsl_without_array_or_matrix(out_type)));
-                components[c] = spirv_builder_emit_composite_extract(&ctx->builder, base_type, src, &member, 1);
-             }
-             if (so_output.num_components > 1)
-                src = spirv_builder_emit_composite_construct(&ctx->builder, type, components, so_output.num_components);
-             else
-                src = components[0];
-             out_type = glsl_vector_type(GLSL_TYPE_UINT, so_output.num_components);
-             output_type = type;
+      /* this is the array index into matrix types */
+      unsigned matrix_offset = so_output.register_index;
+      do {
+         if (glsl_type_is_struct_or_ifc(bare_type)) {
+            uint32_t base_slot = (location & ~so_output.start_component) / 4;
+            /* this is the slot index into the "current" value */
+            unsigned slot_idx = slot - base_slot;
+            unsigned struct_slots = glsl_count_vec4_slots(bare_type, false, false);
+            unsigned array_idx = slot_idx / struct_slots;
+            bool first = true;
+            slot_idx %= glsl_count_vec4_slots(bare_type, false, false);
+            if (glsl_type_is_array(out_type))
+               src = spirv_builder_emit_composite_extract(&ctx->builder, get_glsl_type(ctx, bare_type), src, &array_idx, 1);
+            /* need to find the vec4 that's being exported by this slot */
+            while (glsl_type_is_struct_or_ifc(bare_type)) {
+               /* a struct may have nested arrays of structs: handle them inline here */
+               if (!first && glsl_type_is_array(out_type)) {
+                  struct_slots = glsl_count_vec4_slots(bare_type, false, false);
+                  array_idx = slot_idx / struct_slots;
+                  src = spirv_builder_emit_composite_extract(&ctx->builder, get_glsl_type(ctx, bare_type), src, &array_idx, 1);
+                  slot_idx -= array_idx * struct_slots;
+               }
+               /* unroll this level of struct:
+                * - slot_idx is incremented to reflect the current value
+                * - unwrap src
+                * - out_type is the array type if src is an array
+                */
+               bare_type = unroll_struct_type(ctx, bare_type, &slot_idx, &src, &out_type);
+               first = false;
+            }
+            /* update to the matrix row index */
+            matrix_offset = slot_idx;
+            output_type = get_glsl_type(ctx, out_type);
+            if (glsl_type_is_vector_or_scalar(out_type)) {
+               /* this is a simple case: handle below */
+               if (glsl_get_vector_elements(out_type) * glsl_get_bit_size(out_type) == so_output.num_components * 32) {
+                  src = emit_bitcast(ctx, type, src);
+                  out_type = glsl_vector_type(GLSL_TYPE_UINT, so_output.num_components);
+                  output_type = get_glsl_type(ctx, out_type);
+               }
+            } else if (glsl_type_is_array(out_type)) {
+                /* this should be impossible */
+                if (glsl_type_is_struct(bare_type))
+                   unreachable("zink: gross nested struct array struct arrays in xfb!");
+                SpvId base_type = get_glsl_basetype(ctx, glsl_get_base_type(bare_type));
+                if (glsl_type_is_scalar(bare_type)) {
+                   /* this wouldn't make sense */
+                   assert(so_output.start_component == 0);
+
+                   if (glsl_type_is_64bit(bare_type)) {
+                      /* 64bit components count as 2 so outputs: bitcast to vec2 and extract */
+                      unsigned idx = 0;
+                      for (unsigned c = 0; idx < so_output.num_components; c++) {
+                         uint32_t member = slot_idx + c;
+                         SpvId conv = spirv_builder_emit_composite_extract(&ctx->builder, base_type, src, &member, 1);
+                         SpvId val = emit_bitcast(ctx, get_uvec_type(ctx, 32, 2), conv);
+                         unsigned v = 0;
+                         components[idx++] = spirv_builder_emit_composite_extract(&ctx->builder, get_uvec_type(ctx, 32, 1), val, &v, 1);
+                         v = 1;
+                         components[idx++] = spirv_builder_emit_composite_extract(&ctx->builder, get_uvec_type(ctx, 32, 1), val, &v, 1);
+                      }
+                      result = spirv_builder_emit_composite_construct(&ctx->builder, type, components, so_output.num_components);
+                   } else {
+                      /* array of scalars: each one is its own slot */
+                      for (unsigned c = 0; c < so_output.num_components; c++) {
+                         uint32_t member = slot_idx + c;
+                         components[c] = spirv_builder_emit_composite_extract(&ctx->builder, base_type, src, &member, 1);
+                      }
+                   }
+                } else if (glsl_type_is_matrix(bare_type)) {
+                   /* nested matrix type: unwrap, update matrix offset, select a vec, handle below */
+                   unsigned mat_slots = glsl_count_attribute_slots(bare_type, false);
+                   array_idx = matrix_offset / mat_slots;
+                   output_type = get_glsl_type(ctx, bare_type);
+                   out_type = bare_type;
+                   src = spirv_builder_emit_composite_extract(&ctx->builder, output_type, src, &array_idx, 1);
+                   matrix_offset %= mat_slots;
+                   unsigned real_offset = glsl_type_is_64bit(bare_type) ? matrix_offset / 2 : matrix_offset;
+                   /* store for later */
+                   if (glsl_type_is_64bit(bare_type))
+                      matrix_offset %= 2;
+                   assert(real_offset < glsl_get_matrix_columns(bare_type));
+                   out_type = glsl_without_array_or_matrix(out_type);
+                   output_type = get_glsl_type(ctx, out_type);
+                   src = spirv_builder_emit_composite_extract(&ctx->builder, output_type, src, &real_offset, 1);
+                   break;
+                } else {
+                   assert(glsl_type_is_vector(bare_type));
+                   /* just extract the right vec and let it be handled below */
+                   unsigned vec_slots = glsl_count_attribute_slots(bare_type, false);
+                   unsigned idx = matrix_offset / vec_slots;
+                   matrix_offset %= vec_slots;
+                   output_type = get_glsl_type(ctx, bare_type);
+                   out_type = bare_type;
+                   src = spirv_builder_emit_composite_extract(&ctx->builder, output_type, src, &idx, 1);
+                   break;
+                }
+                if (so_output.num_components > 1)
+                   src = spirv_builder_emit_composite_construct(&ctx->builder, type, components, so_output.num_components);
+                else
+                   src = components[0];
+                out_type = glsl_vector_type(GLSL_TYPE_UINT, so_output.num_components);
+                output_type = type;
+            }
          }
-      }
+      } while (0);
       assert(!glsl_type_is_struct_or_ifc(out_type));
 
-      /* if we're emitting a scalar or the type we're emitting matches the output's original type and we're
-       * emitting the same number of components, then we can skip any sort of conversion here
-       */
-      if (glsl_type_is_scalar(out_type) || (type == output_type && glsl_get_length(out_type) == so_output.num_components))
+      if (!glsl_type_is_64bit(out_type) &&
+          (glsl_type_is_scalar(out_type) ||
+           (type == output_type &&
+            (glsl_type_is_vector(out_type) && glsl_get_vector_elements(out_type) == so_output.num_components))))
+         /* if we're emitting a scalar or the type we're emitting matches the output's original type and we're
+          * emitting the same number of components, then we can skip any sort of conversion here
+          */
          result = src;
       else {
-         /* OpCompositeExtract can only extract scalars for our use here */
-         if (so_output.num_components == 1) {
-            result = spirv_builder_emit_composite_extract(&ctx->builder, type, src, components, so_output.num_components);
+         /* OpCompositeExtract can only extract scalars for our use here,
+          * but not from arrays since they have different packing rules
+          */
+         if (so_output.num_components == 1 && !glsl_type_is_array(out_type)) {
+            unsigned component = so_output.start_component;
+            result = spirv_builder_emit_composite_extract(&ctx->builder, type, src, &component, so_output.num_components);
          } else if (glsl_type_is_vector(out_type)) {
-            /* OpVectorShuffle can select vector members into a differently-sized vector */
-            result = spirv_builder_emit_vector_shuffle(&ctx->builder, type,
-                                                             src, src,
-                                                             components, so_output.num_components);
+            if (glsl_type_is_64bit(out_type)) {
+               /* 64bit components count as 2 so outputs: bitcast to vec2 and extract */
+               unsigned idx = 0;
+               for (unsigned c = 0; idx < so_output.num_components; c++) {
+                  uint32_t member = so_output.start_component + (matrix_offset * 2) + c;
+                  SpvId base_type = get_glsl_basetype(ctx, glsl_get_base_type(out_type));
+                  SpvId conv = spirv_builder_emit_composite_extract(&ctx->builder, base_type, src, &member, 1);
+                  SpvId val = emit_bitcast(ctx, get_uvec_type(ctx, 32, 2), conv);
+                  unsigned v = 0;
+                  components[idx++] = spirv_builder_emit_composite_extract(&ctx->builder, get_uvec_type(ctx, 32, 1), val, &v, 1);
+                  v = 1;
+                  components[idx++] = spirv_builder_emit_composite_extract(&ctx->builder, get_uvec_type(ctx, 32, 1), val, &v, 1);
+               }
+               result = spirv_builder_emit_composite_construct(&ctx->builder, get_uvec_type(ctx, 32, so_output.num_components), components, so_output.num_components);
+            } else {
+               for (unsigned c = 0; c < so_output.num_components; c++) {
+                  components[c] = so_output.start_component + c;
+                  /* this is the second half of a 2 * vec4 array */
+                  if (slot == VARYING_SLOT_CLIP_DIST1)
+                     components[c] += 4;
+               }
+               /* OpVectorShuffle can select vector members into a differently-sized vector */
+               result = spirv_builder_emit_vector_shuffle(&ctx->builder, type,
+                                                                src, src,
+                                                                components, so_output.num_components);
+            }
          } else {
              assert(glsl_type_is_array_or_matrix(out_type));
-             ASSERTED const struct glsl_type *bare_type = glsl_without_array(out_type);
+             const struct glsl_type *bare_type = glsl_without_array(out_type);
              assert(!glsl_type_is_struct_or_ifc(bare_type));
-             /* for arrays, we need to manually extract each desired member
+             if (glsl_type_is_matrix(out_type)) {
+                /* for matrices, the xfb output will never be more than one vec4 from a single row */
+                unsigned vec_size = glsl_get_vector_elements(out_type);
+                SpvId vec_type = get_fvec_type(ctx, glsl_get_bit_size(out_type), vec_size);
+                if (glsl_type_is_64bit(out_type) && vec_size > 2) {
+                   /* dvec3/dvec4 uses 2 slots per row: normalize matrix offset */
+                   matrix_offset /= 2;
+                }
+                src = spirv_builder_emit_composite_extract(&ctx->builder, vec_type, src, &matrix_offset, 1);
+                out_type = glsl_vector_type(glsl_get_base_type(out_type), glsl_get_vector_elements(out_type));
+             }
+             /* for arrays (or matrix rows), we need to manually extract each desired member
               * and re-pack them into the desired output type
               */
-             for (unsigned c = 0; c < so_output.num_components; c++) {
-                uint32_t member[2];
-                unsigned member_idx = 0;
-                if (glsl_type_is_matrix(out_type)) {
-                   member_idx = 1;
-                   member[0] = so_output.register_index;
-                }
-                member[member_idx] = so_output.start_component + c;
-                SpvId base_type = get_glsl_basetype(ctx, glsl_get_base_type(glsl_without_array_or_matrix(out_type)));
+             unsigned idx = 0;
+             for (unsigned c = 0; idx < so_output.num_components; c++) {
+                uint32_t member = so_output.start_component + c;
+                SpvId base_type = get_glsl_basetype(ctx, glsl_get_base_type(bare_type));
 
                 if (slot == VARYING_SLOT_CLIP_DIST1)
-                   member[member_idx] += 4;
-                components[c] = spirv_builder_emit_composite_extract(&ctx->builder, base_type, src, member, 1 + member_idx);
+                   member += 4;
+                components[idx] = spirv_builder_emit_composite_extract(&ctx->builder, base_type, src, &member, 1);
+                if (glsl_type_is_64bit(bare_type)) {
+                   /* 64bit components count as 2 so outputs: bitcast to vec2 and extract */
+                   SpvId val = emit_bitcast(ctx, get_uvec_type(ctx, 32, 2), components[idx]);
+                   unsigned v = 0;
+                   components[idx++] = spirv_builder_emit_composite_extract(&ctx->builder, get_uvec_type(ctx, 32, 1), val, &v, 1);
+                   v = 1;
+                   components[idx++] = spirv_builder_emit_composite_extract(&ctx->builder, get_uvec_type(ctx, 32, 1), val, &v, 1);
+                } else {
+                   idx++;
+                }
              }
-             result = spirv_builder_emit_composite_construct(&ctx->builder, type, components, so_output.num_components);
+             if (so_output.num_components > 1)
+                result = spirv_builder_emit_composite_construct(&ctx->builder, get_uvec_type(ctx, 32, so_output.num_components), components, so_output.num_components);
+             else
+                result = components[0];
          }
       }
 



More information about the mesa-commit mailing list