zink: add arrayness I/O matching

When an XFB-enabled pre-raster stage is combined with a fragment
shader that addresses the array that contains the XFB variables
indirectly, there's a mismatch of arrayness that occurs between
these two stages.

Overcome this hurdle by lowering the indirectly addressed FS
array to be directly accessed through a local copy of the array.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37602>
This commit is contained in:
Utku Iseri 2025-09-26 13:22:10 +02:00 committed by Marge Bot
parent b526b971f1
commit 312372250a
2 changed files with 36 additions and 3 deletions

View file

@ -169,9 +169,6 @@ spec@ext_framebuffer_multisample@interpolation 4 non-centroid-disabled,Fail
spec@ext_framebuffer_multisample@sample-alpha-to-coverage 2 color,Fail
spec@ext_framebuffer_multisample@sample-alpha-to-coverage 4 color,Fail
# see https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37602#note_3294118
spec@ext_transform_feedback@max-varyings,Crash
spec@ext_transform_feedback@tessellation quad_strip wireframe,Fail
spec@ext_transform_feedback@tessellation quads wireframe,Fail
spec@ext_transform_feedback@tessellation triangle_fan flat_first,Fail

View file

@ -2895,6 +2895,40 @@ scalarize_vars_instr_filter(const nir_intrinsic_instr * intrin, const void *data
return (scalarize_var_locations & BITFIELD64_BIT(semantics.location)) != 0;
}
static void
split_fs_indirect_arrays(nir_shader *nir)
{
if (nir->info.stage != MESA_SHADER_FRAGMENT)
return;
nir_foreach_variable_with_modes_safe(var, nir, nir_var_shader_in | nir_var_shader_out) {
exec_node_remove(&var->node);
}
/* lower indirect loads to direct+temps and unlower back to convert arrays to slots */
NIR_PASS(_, nir, nir_lower_io_indirect_loads, nir_var_shader_in);
NIR_PASS(_, nir, nir_unlower_io_to_vars, false);
}
static bool
align_array_slot_io(nir_shader *producer, nir_shader *consumer)
{
/* walk producer outputs and compare to consumer inputs. fix pre-raster non-array: FS array mismatch. */
nir_foreach_variable_with_modes_safe(output_var, producer, nir_var_shader_out) {
nir_variable* input_var = nir_find_variable_with_location(consumer, nir_var_shader_in, output_var->data.location);
if (!input_var)
continue;
const glsl_type* output_type = nir_is_arrayed_io(output_var, producer->info.stage) ?
glsl_get_array_element(output_var->type) : output_var->type;
const glsl_type* input_type = nir_is_arrayed_io(input_var, consumer->info.stage) ?
glsl_get_array_element(input_var->type) : input_var->type;
/* XFB + FS indirect indexing, remove it. */
if (glsl_type_is_array(input_type) && !glsl_type_is_array(output_type)) {
split_fs_indirect_arrays(consumer);
return true;
}
}
return false;
}
static void
fix_var_int_floatness(nir_shader *producer, nir_shader *consumer)
{
@ -2983,6 +3017,8 @@ zink_compiler_assign_io(struct zink_screen *screen, nir_shader *producer, nir_sh
if (consumer->info.stage == MESA_SHADER_FRAGMENT && screen->driver_compiler_workarounds.needs_sanitised_layer)
do_fixup |= clamp_layer_output(producer, consumer, &io.reserved);
}
if (producer->info.has_transform_feedback_varyings && consumer->info.stage == MESA_SHADER_FRAGMENT)
do_fixup |= align_array_slot_io(producer, consumer);
nir_shader_gather_info(producer, nir_shader_get_entrypoint(producer));
if (producer->info.io_lowered && consumer->info.io_lowered) {
u_foreach_bit64(slot, producer->info.outputs_written & BITFIELD64_RANGE(VARYING_SLOT_VAR0, 31)) {