Module: Mesa Branch: main Commit: 95a90b359a4eee5b2a1d92a9b625ef21e4fba085 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=95a90b359a4eee5b2a1d92a9b625ef21e4fba085
Author: Jesse Natalie <[email protected]> Date: Wed Jan 11 10:53:45 2023 -0800 spirv2dxil: Implement lowering for multiview D3D's view instancing is an optional feature, and even when it's supported, it only goes up to 4 views, where Vulkan requires a minimum of 6 supported views. So, we need to have a path for handling the cases where we can't use the native feature. In this mode, pass the view ID as a runtime var. The caller is then responsible for looping the draw calls and filling out the constant buffer value correctly for each draw. When we get to the last pre-rast stage, we'll additionally want to write out gl_Layer to select the right RTV array slice. Lastly, for the fragment shader, if there's any input attachments, those get loaded using the RTV slice instead of the view ID. RTV slice input into the PS is done with a signature entry (which must be output from the previous stage) rather than a system value. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20650> --- src/microsoft/spirv_to_dxil/dxil_spirv_nir.c | 83 +++++++++++++++++++++++++++- src/microsoft/spirv_to_dxil/spirv_to_dxil.h | 6 ++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/microsoft/spirv_to_dxil/dxil_spirv_nir.c b/src/microsoft/spirv_to_dxil/dxil_spirv_nir.c index fd6b8c82f11..7674682e4ee 100644 --- a/src/microsoft/spirv_to_dxil/dxil_spirv_nir.c +++ b/src/microsoft/spirv_to_dxil/dxil_spirv_nir.c @@ -153,6 +153,11 @@ lower_shader_system_values(struct nir_builder *builder, nir_instr *instr, case nir_intrinsic_load_draw_id: offset = offsetof(struct dxil_spirv_vertex_runtime_data, draw_id); break; + case nir_intrinsic_load_view_index: + if (!conf->lower_view_index) + return false; + offset = offsetof(struct dxil_spirv_vertex_runtime_data, view_index); + break; default: return false; } @@ -733,6 +738,78 @@ dxil_spirv_compute_pntc(nir_shader *nir) pos); } +static bool +lower_view_index_to_rt_layer_instr(nir_builder *b, nir_instr *instr, void *data) +{ + if (instr->type != nir_instr_type_intrinsic) + return false; + nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); + if (intr->intrinsic != nir_intrinsic_store_deref) + return false; + + nir_variable *var = nir_intrinsic_get_var(intr, 0); + if (!var || + var->data.mode != nir_var_shader_out || + var->data.location != VARYING_SLOT_LAYER) + return false; + + b->cursor = nir_before_instr(instr); + nir_ssa_def *layer = intr->src[1].ssa; + nir_ssa_def *new_layer = nir_iadd(b, layer, + nir_load_view_index(b)); + nir_instr_rewrite_src_ssa(instr, &intr->src[1], new_layer); + return true; +} + +static bool +add_layer_write(nir_builder *b, nir_instr *instr, void *data) +{ + if (instr) { + if (instr->type != nir_instr_type_intrinsic) + return false; + nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); + if (intr->intrinsic != nir_intrinsic_emit_vertex && + intr->intrinsic != nir_intrinsic_emit_vertex_with_counter) + return false; + b->cursor = nir_before_instr(instr); + } + nir_variable *var = (nir_variable *)data; + nir_store_var(b, var, nir_load_view_index(b), 0x1); + return true; +} + +static void +lower_view_index_to_rt_layer(nir_shader *nir) +{ + bool existing_write = + nir_shader_instructions_pass(nir, + lower_view_index_to_rt_layer_instr, + nir_metadata_block_index | + nir_metadata_dominance | + nir_metadata_loop_analysis, NULL); + + if (existing_write) + return; + + nir_variable *var = nir_variable_create(nir, nir_var_shader_out, + glsl_uint_type(), "gl_Layer"); + var->data.location = VARYING_SLOT_LAYER; + var->data.interpolation = INTERP_MODE_FLAT; + if (nir->info.stage == MESA_SHADER_GEOMETRY) { + nir_shader_instructions_pass(nir, + add_layer_write, + nir_metadata_block_index | + nir_metadata_dominance | + nir_metadata_loop_analysis, var); + } else { + nir_function_impl *func = nir_shader_get_entrypoint(nir); + nir_builder b; + nir_builder_init(&b, func); + b.cursor = nir_after_block(nir_impl_last_block(func)); + add_layer_write(&b, NULL, var); + } +} + void dxil_spirv_nir_link(nir_shader *nir, nir_shader *prev_stage_nir, const struct dxil_spirv_runtime_conf *conf, @@ -806,6 +883,9 @@ dxil_spirv_nir_passes(nir_shader *nir, ARRAY_SIZE(system_values)); } + if (conf->lower_view_index_to_rt_layer) + NIR_PASS_V(nir, lower_view_index_to_rt_layer); + *requires_runtime_data = false; NIR_PASS(*requires_runtime_data, nir, dxil_spirv_nir_lower_shader_system_values, @@ -815,7 +895,8 @@ dxil_spirv_nir_passes(nir_shader *nir, NIR_PASS_V(nir, nir_lower_input_attachments, &(nir_input_attachment_options){ .use_fragcoord_sysval = false, - .use_layer_id_sysval = true, + .use_layer_id_sysval = !conf->lower_view_index, + .use_view_id_for_layer = !conf->lower_view_index, }); /* This will lower load_helper to a memoized is_helper if needed; otherwise, load_helper diff --git a/src/microsoft/spirv_to_dxil/spirv_to_dxil.h b/src/microsoft/spirv_to_dxil/spirv_to_dxil.h index 8a602dc1ba7..a95bffaaa4e 100644 --- a/src/microsoft/spirv_to_dxil/spirv_to_dxil.h +++ b/src/microsoft/spirv_to_dxil/spirv_to_dxil.h @@ -114,6 +114,7 @@ struct dxil_spirv_vertex_runtime_data { uint32_t draw_id; float viewport_width; float viewport_height; + uint32_t view_index; }; enum dxil_spirv_yz_flip_mode { @@ -161,6 +162,11 @@ struct dxil_spirv_runtime_conf { // Force sample rate shading on a fragment shader bool force_sample_rate_shading; + + // View index needs to be lowered to a UBO lookup + bool lower_view_index; + // View index also needs to be forwarded to RT layer output + bool lower_view_index_to_rt_layer; }; struct dxil_spirv_debug_options {
