mesa/st: add implicit zeroing of clipdistance array

GL drivers have an implicit default of "in bounds" for unwritten clipdistance
values, but some (layered) drivers have to deal with api mismatch which
prevents that implicit value from being used after the shader
gets mangled by various compiler passes

to avoid issues here, write out all members of the clipdistance array
with zeroes at the very start of the shader such that any values the
shader actually writes will naturally overwrite the implicit zero and
any unwritten values will now be written as zero

fixes #6845

Reviewed-by: Jesse Natalie <jenatali@microsoft.com>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17498>
This commit is contained in:
Mike Blumenkrantz 2022-07-12 13:57:31 -04:00 committed by Marge Bot
parent 071d335ca2
commit 48491386ff
1 changed files with 38 additions and 0 deletions

View File

@ -290,6 +290,40 @@ st_can_remove_varying_before_linking(nir_variable *var, void *data)
return true;
}
static void
zero_array_members(nir_builder *b, nir_variable *var)
{
nir_deref_instr *deref = nir_build_deref_var(b, var);
nir_ssa_def *zero = nir_imm_zero(b, 4, 32);
for (int i = 0; i < glsl_array_size(var->type); i++) {
nir_deref_instr *arr = nir_build_deref_array_imm(b, deref, i);
uint32_t mask = BITFIELD_MASK(glsl_get_vector_elements(arr->type));
nir_store_deref(b, arr, nir_channels(b, zero, mask), mask);
}
}
/* GL has an implicit default of 0 for unwritten gl_ClipDistance members;
* to achieve this, write 0 to all members at the start of the shader and
* let them be naturally overwritten later
*/
static bool
st_nir_zero_initialize_clip_distance(nir_shader *nir)
{
nir_variable *clip_dist0 = nir_find_variable_with_location(nir, nir_var_shader_out, VARYING_SLOT_CLIP_DIST0);
nir_variable *clip_dist1 = nir_find_variable_with_location(nir, nir_var_shader_out, VARYING_SLOT_CLIP_DIST1);
if (!clip_dist0 && !clip_dist1)
return false;
nir_builder b;
nir_function_impl *impl = nir_shader_get_entrypoint(nir);
nir_builder_init(&b, impl);
b.cursor = nir_before_block(nir_start_block(impl));
if (clip_dist0)
zero_array_members(&b, clip_dist0);
if (clip_dist1)
zero_array_members(&b, clip_dist1);
return true;
}
/* First third of converting glsl_to_nir.. this leaves things in a pre-
* nir_lower_io state, so that shader variants can more easily insert/
* replace variables, etc.
@ -339,6 +373,10 @@ st_nir_preprocess(struct st_context *st, struct gl_program *prog,
NIR_PASS_V(nir, st_nir_add_point_size);
}
if (stage < MESA_SHADER_FRAGMENT && stage != MESA_SHADER_TESS_CTRL &&
(nir->info.outputs_written & (VARYING_BIT_CLIP_DIST0 | VARYING_BIT_CLIP_DIST1)))
NIR_PASS_V(nir, st_nir_zero_initialize_clip_distance);
struct nir_remove_dead_variables_options opts;
bool is_sso = nir->info.separate_shader;
opts.can_remove_var_data = &is_sso;