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@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8152>
This commit is contained in:
Mike Blumenkrantz 2020-07-23 09:20:36 -04:00 committed by Marge Bot
parent 334759d850
commit 6324699e67

View file

@ -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);