mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-07 13:38:06 +02:00
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>
This commit is contained in:
parent
2d56b3214d
commit
95a90b359a
2 changed files with 88 additions and 1 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue