Mesa (master): zink: handle partial writes to shader outputs

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Dec 22 13:56:10 UTC 2020


Module: Mesa
Branch: master
Commit: 6324699e67a65b7412e607878f5043e07e898091
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=6324699e67a65b7412e607878f5043e07e898091

Author: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Date:   Thu Jul 23 09:20:36 2020 -0400

zink: handle partial writes to shader outputs

this is super gross. spirv doesn't provide any facility for doing per-component
writes, which means all components of a value must be written every time

to this end, we need to manually split both the src and dst composites and
do per-component access for each store in order to accurately handle both
non-sequential wrmasks (which could be handled by nir_lower_wrmasks, yes, but
we aren't using it) as well as partial wrmasks

see also mesa/mesa#4006

Reviewed-by: Erik Faye-Lund <kusmabite at gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8152>

---

 .../drivers/zink/nir_to_spirv/nir_to_spirv.c       | 32 +++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

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 f52bd3cbfaf..c3bc7a13a77 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
@@ -1766,8 +1766,38 @@ emit_store_deref(struct ntv_context *ctx, nir_intrinsic_instr *intr)
    SpvId ptr = get_src(ctx, &intr->src[0]);
    SpvId src = get_src(ctx, &intr->src[1]);
 
-   SpvId type = get_glsl_type(ctx, nir_src_as_deref(intr->src[0])->type);
+   const struct glsl_type *gtype = nir_src_as_deref(intr->src[0])->type;
+   SpvId type = get_glsl_type(ctx, gtype);
    nir_variable *var = nir_deref_instr_get_variable(nir_src_as_deref(intr->src[0]));
+   unsigned num_writes = util_bitcount(nir_intrinsic_write_mask(intr));
+   unsigned wrmask = nir_intrinsic_write_mask(intr);
+   if (num_writes && num_writes != intr->num_components) {
+      /* no idea what we do if this fails */
+      assert(glsl_type_is_array(gtype) || glsl_type_is_vector(gtype));
+
+      /* this is a partial write, so we have to loop and do a per-component write */
+      SpvId result_type;
+      SpvId member_type;
+      if (glsl_type_is_vector(gtype)) {
+         result_type = get_glsl_basetype(ctx, glsl_get_base_type(gtype));
+         member_type = get_uvec_type(ctx, 32, 1);
+      } else
+         member_type = result_type = get_glsl_type(ctx, glsl_get_array_element(gtype));
+      SpvId ptr_type = spirv_builder_type_pointer(&ctx->builder,
+                                                  SpvStorageClassOutput,
+                                                  result_type);
+      for (unsigned i = 0; i < 4; i++)
+         if ((wrmask >> i) & 1) {
+            SpvId idx = emit_uint_const(ctx, 32, i);
+            SpvId val = spirv_builder_emit_composite_extract(&ctx->builder, member_type, src, &i, 1);
+            val = emit_bitcast(ctx, result_type, val);
+            SpvId member = spirv_builder_emit_access_chain(&ctx->builder, ptr_type,
+                                                           ptr, &idx, 1);
+            spirv_builder_emit_store(&ctx->builder, member, val);
+         }
+      return;
+
+   }
    SpvId result;
    if (ctx->stage == MESA_SHADER_FRAGMENT && var->data.location == FRAG_RESULT_SAMPLE_MASK) {
       src = emit_bitcast(ctx, type, src);



More information about the mesa-commit mailing list