radv: export multi view index as layer after lowering io

Reviewed-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40982>
This commit is contained in:
Georg Lehmann 2026-04-15 15:04:53 +02:00 committed by Marge Bot
parent 8e74c0020e
commit ae2213fa6d
2 changed files with 34 additions and 91 deletions

View file

@ -10,77 +10,53 @@
#include "nir_builder.h"
#include "radv_nir.h"
static nir_variable *
find_layer_out_var(nir_shader *nir)
static void
export_multiview(nir_builder *b)
{
nir_variable *var = nir_find_variable_with_location(nir, nir_var_shader_out, VARYING_SLOT_LAYER);
if (var != NULL)
return var;
nir_io_semantics io_sem = {
.location = VARYING_SLOT_LAYER,
.num_slots = 1,
.no_varying = true,
};
var = nir_variable_create(nir, nir_var_shader_out, glsl_int_type(), "layer id");
var->data.location = VARYING_SLOT_LAYER;
var->data.interpolation = INTERP_MODE_NONE;
nir_store_output(b, nir_load_view_index(b), nir_imm_int(b, 0), .component = 0, .src_type = nir_type_int32,
.io_semantics = io_sem);
return var;
b->shader->info.outputs_written |= VARYING_BIT_LAYER;
}
static bool
export_multiview_per_emit(nir_builder *b, nir_intrinsic_instr *intr, void *unused)
{
if (intr->intrinsic != nir_intrinsic_emit_vertex_with_counter)
return false;
b->cursor = nir_before_instr(&intr->instr);
export_multiview(b);
return true;
}
bool
radv_nir_export_multiview(nir_shader *nir)
{
nir_function_impl *impl = nir_shader_get_entrypoint(nir);
bool progress = false;
nir_builder b = nir_builder_create(impl);
/* This pass is not suitable for mesh shaders, because it can't know the mapping between API mesh
* shader invocations and output primitives. Needs to be handled in ac_nir_lower_ngg.
*/
assert(nir->info.stage == MESA_SHADER_VERTEX || nir->info.stage == MESA_SHADER_TESS_EVAL ||
nir->info.stage == MESA_SHADER_GEOMETRY);
/* Iterate in reverse order since there should be only one deref store to POS after
* lower_io_to_temporaries for vertex shaders and inject the layer there. For geometry shaders,
* the layer is injected right before every emit_vertex_with_counter.
*/
nir_variable *layer = NULL;
nir_foreach_block_reverse (block, impl) {
nir_foreach_instr_reverse (instr, block) {
if (instr->type != nir_instr_type_intrinsic)
continue;
/* The shader shouldn't write gl_Layer itself. */
assert(!(nir->info.outputs_written & VARYING_BIT_LAYER));
if (nir->info.stage == MESA_SHADER_GEOMETRY) {
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
if (intr->intrinsic != nir_intrinsic_emit_vertex_with_counter)
continue;
if (nir->info.stage == MESA_SHADER_GEOMETRY) {
/* For geometry shaders, the layer is injected right before every emit_vertex_with_counter. */
return nir_shader_intrinsics_pass(nir, export_multiview_per_emit, nir_metadata_control_flow, NULL);
} else {
nir_function_impl *impl = nir_shader_get_entrypoint(nir);
b.cursor = nir_before_instr(instr);
} else {
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
if (intr->intrinsic != nir_intrinsic_store_deref)
continue;
nir_builder b = nir_builder_at(nir_after_impl(impl));
export_multiview(&b);
nir_variable *var = nir_intrinsic_get_var(intr, 0);
if (var->data.mode != nir_var_shader_out || var->data.location != VARYING_SLOT_POS)
continue;
b.cursor = nir_after_instr(instr);
}
if (!layer)
layer = find_layer_out_var(nir);
nir_store_var(&b, layer, nir_load_view_index(&b), 1);
/* Update outputs_written to reflect that the pass added a new output. */
nir->info.outputs_written |= VARYING_BIT_LAYER;
progress = true;
if (nir->info.stage == MESA_SHADER_VERTEX)
break;
}
if (nir->info.stage == MESA_SHADER_VERTEX && progress)
break;
return nir_progress(true, impl, nir_metadata_control_flow);
}
return nir_progress(progress, impl, nir_metadata_control_flow);
}

View file

@ -1211,17 +1211,6 @@ static const mesa_shader_stage graphics_shader_order[] = {
MESA_SHADER_FRAGMENT,
};
static void
radv_link_vs(struct radv_shader_stage *vs_stage, struct radv_shader_stage *next_stage,
const struct radv_graphics_state_key *gfx_state)
{
assert(vs_stage->nir->info.stage == MESA_SHADER_VERTEX);
if (radv_should_export_multiview(vs_stage, gfx_state)) {
NIR_PASS(_, vs_stage->nir, radv_nir_export_multiview);
}
}
static void
radv_link_tcs(struct radv_shader_stage *tcs_stage, struct radv_shader_stage *tes_stage,
const struct radv_graphics_state_key *gfx_state)
@ -1236,28 +1225,6 @@ radv_link_tcs(struct radv_shader_stage *tcs_stage, struct radv_shader_stage *tes
merge_tess_info(&tes_stage->nir->info, &tcs_stage->nir->info);
}
static void
radv_link_tes(struct radv_shader_stage *tes_stage, struct radv_shader_stage *next_stage,
const struct radv_graphics_state_key *gfx_state)
{
assert(tes_stage->nir->info.stage == MESA_SHADER_TESS_EVAL);
if (radv_should_export_multiview(tes_stage, gfx_state)) {
NIR_PASS(_, tes_stage->nir, radv_nir_export_multiview);
}
}
static void
radv_link_gs(struct radv_shader_stage *gs_stage, struct radv_shader_stage *fs_stage,
const struct radv_graphics_state_key *gfx_state)
{
assert(gs_stage->nir->info.stage == MESA_SHADER_GEOMETRY);
if (radv_should_export_multiview(gs_stage, gfx_state)) {
NIR_PASS(_, gs_stage->nir, radv_nir_export_multiview);
}
}
static bool
radv_pipeline_needs_noop_fs(struct radv_graphics_pipeline *pipeline, const struct radv_graphics_state_key *gfx_state)
{
@ -1286,16 +1253,13 @@ radv_graphics_shaders_link(const struct radv_device *device, const struct radv_g
switch (s) {
case MESA_SHADER_VERTEX:
radv_link_vs(&stages[s], next_stage, gfx_state);
break;
case MESA_SHADER_TESS_CTRL:
radv_link_tcs(&stages[s], next_stage, gfx_state);
break;
case MESA_SHADER_TESS_EVAL:
radv_link_tes(&stages[s], next_stage, gfx_state);
break;
case MESA_SHADER_GEOMETRY:
radv_link_gs(&stages[s], next_stage, gfx_state);
break;
case MESA_SHADER_TASK:
break;
@ -2671,6 +2635,9 @@ radv_graphics_shaders_compile(struct radv_device *device, struct vk_pipeline_cac
BITSET_TEST(stages[i].nir->info.system_values_read, SYSTEM_VALUE_DRAW_ID))
radv_nir_lower_draw_id_to_zero(stages[i].nir);
if (i != MESA_SHADER_MESH && radv_should_export_multiview(&stages[i], gfx_state))
NIR_PASS(_, stages[i].nir, radv_nir_export_multiview);
uint64_t remove_as_varying = 0;
uint64_t remove_as_sysval = 0;