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