d3d12: When adding new output varyings, write 0s

This avoids undefined behavior in some cases, and in the case
where the new output varying is actually a sysval like viewport
index, the DXIL validator will require it to be written.

Reviewed-by: Sil Vilerino <sivileri@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14881>
This commit is contained in:
Jesse Natalie 2022-02-04 08:24:02 -08:00 committed by Marge Bot
parent ccaa79a1ba
commit a3a3599a08
3 changed files with 64 additions and 0 deletions

View file

@ -535,6 +535,9 @@ create_varying_from_info(nir_shader *nir, struct d3d12_varying_info *info,
if (patch)
var->data.location += VARYING_SLOT_PATCH0;
if (mode == nir_var_shader_out)
NIR_PASS_V(nir, d3d12_write_0_to_new_varying, var);
return var;
}

View file

@ -1142,3 +1142,61 @@ d3d12_split_multistream_varyings(nir_shader *s)
return progress;
}
static void
write_0(nir_builder *b, nir_deref_instr *deref)
{
if (glsl_type_is_array_or_matrix(deref->type)) {
for (unsigned i = 0; i < glsl_get_length(deref->type); ++i)
write_0(b, nir_build_deref_array_imm(b, deref, i));
} else if (glsl_type_is_struct(deref->type)) {
for (unsigned i = 0; i < glsl_get_length(deref->type); ++i)
write_0(b, nir_build_deref_struct(b, deref, i));
} else {
nir_ssa_def *scalar = nir_imm_intN_t(b, 0, glsl_get_bit_size(deref->type));
nir_ssa_def *scalar_arr[NIR_MAX_VEC_COMPONENTS];
unsigned num_comps = glsl_get_components(deref->type);
unsigned writemask = (1 << num_comps) - 1;
for (unsigned i = 0; i < num_comps; ++i)
scalar_arr[i] = scalar;
nir_ssa_def *zero_val = nir_vec(b, scalar_arr, num_comps);
nir_store_deref(b, deref, zero_val, writemask);
}
}
void
d3d12_write_0_to_new_varying(nir_shader *s, nir_variable *var)
{
/* Skip per-vertex HS outputs */
if (s->info.stage == MESA_SHADER_TESS_CTRL && !var->data.patch)
return;
nir_foreach_function(func, s) {
if (!func->impl)
continue;
nir_builder b;
nir_builder_init(&b, func->impl);
nir_foreach_block(block, func->impl) {
b.cursor = nir_before_block(block);
if (s->info.stage != MESA_SHADER_GEOMETRY) {
write_0(&b, nir_build_deref_var(&b, var));
break;
}
nir_foreach_instr_safe(instr, block) {
if (instr->type != nir_instr_type_intrinsic)
continue;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
if (intr->intrinsic != nir_intrinsic_emit_vertex)
continue;
b.cursor = nir_before_instr(instr);
write_0(&b, nir_build_deref_var(&b, var));
}
}
nir_metadata_preserve(func->impl, nir_metadata_block_index | nir_metadata_dominance);
}
}

View file

@ -117,6 +117,9 @@ d3d12_disable_multisampling(nir_shader *s);
bool
d3d12_split_multistream_varyings(nir_shader *s);
void
d3d12_write_0_to_new_varying(nir_shader *s, nir_variable *var);
#ifdef __cplusplus
}
#endif