From 6f8656ec64cdd2495d0610770bc29caad199cdf8 Mon Sep 17 00:00:00 2001 From: Jesse Natalie Date: Mon, 20 Apr 2026 13:54:18 -0700 Subject: [PATCH] microsoft/compiler: Back-propagate interpolator modes from FS Part-of: --- src/gallium/drivers/d3d12/d3d12_compiler.cpp | 3 ++ src/microsoft/compiler/dxil_nir.c | 30 ++++++++++++++++++++ src/microsoft/compiler/dxil_nir.h | 2 ++ src/microsoft/spirv_to_dxil/dxil_spirv_nir.c | 2 ++ 4 files changed, 37 insertions(+) diff --git a/src/gallium/drivers/d3d12/d3d12_compiler.cpp b/src/gallium/drivers/d3d12/d3d12_compiler.cpp index 8ade408bc7d..0f4247b094b 100644 --- a/src/gallium/drivers/d3d12/d3d12_compiler.cpp +++ b/src/gallium/drivers/d3d12/d3d12_compiler.cpp @@ -1177,6 +1177,9 @@ select_shader_variant(struct d3d12_selection_context *sel_ctx, d3d12_shader_sele /* Remove not-read outputs and re-sort */ if (next) { + if (next->stage == MESA_SHADER_FRAGMENT) + dxil_nir_propagate_interp_to_outputs(new_nir_variant, next->initial); + NIR_PASS(_, new_nir_variant, dxil_nir_kill_unused_outputs, key.next_varying_inputs, next->initial->info.patch_inputs_read, key.next_varying_frac_inputs); dxil_reassign_driver_locations(new_nir_variant, nir_var_shader_out, key.next_varying_inputs, diff --git a/src/microsoft/compiler/dxil_nir.c b/src/microsoft/compiler/dxil_nir.c index c84b6c34278..44312ee2619 100644 --- a/src/microsoft/compiler/dxil_nir.c +++ b/src/microsoft/compiler/dxil_nir.c @@ -2876,3 +2876,33 @@ dxil_nir_kill_unused_outputs(nir_shader *shader, uint64_t next_stage_read_mask, progress |= nir_remove_dead_variables(shader, nir_var_shader_out, &options); return progress; } + +void +dxil_nir_propagate_interp_to_outputs(nir_shader *prev_stage_nir, + const nir_shader *fs_nir) +{ + /* Work around a bug in some D3D12 drivers where the interpolation mode on + * outputs of the previous shader stage must match the interpolation mode on + * the corresponding fragment shader inputs. Back-propagate interpolation + * qualifiers (interpolation, centroid, sample) from FS inputs to the + * previous stage's outputs. + */ + assert(fs_nir->info.stage == MESA_SHADER_FRAGMENT); + + nir_foreach_variable_with_modes(fs_input, fs_nir, nir_var_shader_in) { + unsigned loc = fs_input->data.location; + + /* Skip system values - only propagate for user varyings */ + if (loc < VARYING_SLOT_VAR0) + continue; + + nir_foreach_variable_with_modes(prev_output, prev_stage_nir, + nir_var_shader_out) { + if (prev_output->data.location == loc) { + prev_output->data.interpolation = fs_input->data.interpolation; + prev_output->data.centroid = fs_input->data.centroid; + prev_output->data.sample = fs_input->data.sample; + } + } + } +} diff --git a/src/microsoft/compiler/dxil_nir.h b/src/microsoft/compiler/dxil_nir.h index 267aa88f19d..6f1e3292143 100644 --- a/src/microsoft/compiler/dxil_nir.h +++ b/src/microsoft/compiler/dxil_nir.h @@ -89,6 +89,8 @@ bool dxil_nir_kill_undefined_varyings(nir_shader *shader, uint64_t prev_stage_wr uint32_t prev_stage_patch_written_mask, const BITSET_WORD *prev_stage_frac_output_mask); bool dxil_nir_kill_unused_outputs(nir_shader *shader, uint64_t next_stage_read_mask, uint32_t next_stage_patch_read_mask, const BITSET_WORD *next_stage_frac_input_mask); +void dxil_nir_propagate_interp_to_outputs(nir_shader *prev_stage_nir, + const nir_shader *fs_nir); #ifdef __cplusplus } diff --git a/src/microsoft/spirv_to_dxil/dxil_spirv_nir.c b/src/microsoft/spirv_to_dxil/dxil_spirv_nir.c index 460af16e43b..27974c108f7 100644 --- a/src/microsoft/spirv_to_dxil/dxil_spirv_nir.c +++ b/src/microsoft/spirv_to_dxil/dxil_spirv_nir.c @@ -804,6 +804,8 @@ dxil_spirv_nir_link(nir_shader *nir, nir_shader *prev_stage_nir, NIR_PASS(_, nir, dxil_spirv_compute_pntc); metadata->requires_runtime_data = true; } + + dxil_nir_propagate_interp_to_outputs(prev_stage_nir, nir); } NIR_PASS(_, nir, dxil_nir_kill_undefined_varyings, prev_stage_nir->info.outputs_written, prev_stage_nir->info.patch_outputs_written, NULL);