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 {

Reply via email to