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