From c69b771e35fede00b6754d4578903e698715b170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20Krist=C3=B3f?= Date: Fri, 13 May 2022 21:32:12 +0200 Subject: [PATCH] radv, ac/nir: Fix multiview layer export for mesh shaders. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unfortunately, radv_lower_multiview is not suitable for mesh shaders because it can't know the mapping between API mesh shader invocations and output primitives. Additionally, when lowering view id to layer, it must be created as a per-primitive PS input. Fixes: d32656bc65a7c0165e53d551e23462d626bbf870 Signed-off-by: Timur Kristóf Reviewed-by: Samuel Pitoiset Part-of: --- src/amd/common/ac_nir.h | 3 ++- src/amd/common/ac_nir_lower_ngg.c | 16 +++++++++++++++- src/amd/vulkan/radv_pipeline.c | 12 ++++++++---- src/amd/vulkan/radv_shader.c | 11 +++++++---- src/amd/vulkan/radv_shader.h | 2 +- src/amd/vulkan/radv_shader_info.c | 6 ++++++ 6 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/amd/common/ac_nir.h b/src/amd/common/ac_nir.h index 3ef13c79687..61f9fc18af2 100644 --- a/src/amd/common/ac_nir.h +++ b/src/amd/common/ac_nir.h @@ -125,7 +125,8 @@ ac_nir_lower_ngg_gs(nir_shader *shader, void ac_nir_lower_ngg_ms(nir_shader *shader, - unsigned wave_size); + unsigned wave_size, + bool multiview); void ac_nir_apply_first_task_to_task_shader(nir_shader *shader); diff --git a/src/amd/common/ac_nir_lower_ngg.c b/src/amd/common/ac_nir_lower_ngg.c index 49abaa99b4f..8ab79e4580e 100644 --- a/src/amd/common/ac_nir_lower_ngg.c +++ b/src/amd/common/ac_nir_lower_ngg.c @@ -112,6 +112,9 @@ typedef struct nir_ssa_def *workgroup_index; + /* True if the lowering needs to insert the layer output. */ + bool insert_layer_output; + struct { /* Bitmask of components used: 4 bits per slot, 1 bit per component. */ uint32_t components_mask; @@ -2535,6 +2538,15 @@ emit_ms_finale(nir_builder *b, lower_ngg_ms_state *s) ms_emit_arrayed_outputs(b, invocation_index, s->per_primitive_outputs, s->num_per_primitive_outputs, s->prim_attr_lds_addr, s); + /* Insert layer output store if the pipeline uses multiview but the API shader doesn't write it. */ + if (s->insert_layer_output) { + nir_ssa_def *layer = nir_load_view_index(b); + const nir_io_semantics io_sem = { .location = VARYING_SLOT_LAYER, .num_slots = 1 }; + nir_store_output(b, layer, nir_imm_int(b, 0), .base = VARYING_SLOT_LAYER, .component = 0, .io_semantics = io_sem); + b->shader->info.outputs_written |= VARYING_BIT_LAYER; + b->shader->info.per_primitive_outputs |= VARYING_BIT_LAYER; + } + /* Primitive connectivity data: describes which vertices the primitive uses. */ nir_ssa_def *prim_idx_addr = nir_imul_imm(b, invocation_index, s->vertices_per_prim); nir_ssa_def *indices_loaded = nir_load_shared(b, s->vertices_per_prim, 8, prim_idx_addr, .base = s->prim_vtx_indices_addr); @@ -2697,7 +2709,8 @@ handle_smaller_ms_api_workgroup(nir_builder *b, void ac_nir_lower_ngg_ms(nir_shader *shader, - unsigned wave_size) + unsigned wave_size, + bool multiview) { unsigned vertices_per_prim = num_mesh_vertices_per_primitive(shader->info.mesh.primitive_type); @@ -2761,6 +2774,7 @@ ac_nir_lower_ngg_ms(nir_shader *shader, .numprims_lds_addr = numprims_lds_addr, .api_workgroup_size = api_workgroup_size, .hw_workgroup_size = hw_workgroup_size, + .insert_layer_output = multiview && !(shader->info.outputs_written & VARYING_BIT_LAYER), }; nir_function_impl *impl = nir_shader_get_entrypoint(shader); diff --git a/src/amd/vulkan/radv_pipeline.c b/src/amd/vulkan/radv_pipeline.c index 8093c08d8da..ce4f5efe78a 100644 --- a/src/amd/vulkan/radv_pipeline.c +++ b/src/amd/vulkan/radv_pipeline.c @@ -2873,7 +2873,6 @@ find_layer_out_var(nir_shader *nir) return var; var = nir_variable_create(nir, nir_var_shader_out, glsl_int_type(), "layer id"); - var->data.per_primitive = nir->info.stage == MESA_SHADER_MESH; var->data.location = VARYING_SLOT_LAYER; var->data.interpolation = INTERP_MODE_NONE; @@ -2883,6 +2882,13 @@ find_layer_out_var(nir_shader *nir) static bool radv_lower_multiview(nir_shader *nir) { + /* 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. + */ + if (nir->info.stage == MESA_SHADER_MESH) + return false; + nir_function_impl *impl = nir_shader_get_entrypoint(nir); bool progress = false; @@ -2924,8 +2930,6 @@ radv_lower_multiview(nir_shader *nir) /* Update outputs_written to reflect that the pass added a new output. */ nir->info.outputs_written |= BITFIELD64_BIT(VARYING_SLOT_LAYER); - if (nir->info.stage == MESA_SHADER_MESH) - nir->info.per_primitive_outputs |= BITFIELD64_BIT(VARYING_SLOT_LAYER); progress = true; if (nir->info.stage == MESA_SHADER_VERTEX) @@ -4764,7 +4768,7 @@ radv_create_shaders(struct radv_pipeline *pipeline, struct radv_pipeline_layout /* Gather info again, information such as outputs_read can be out-of-date. */ nir_shader_gather_info(stages[i].nir, nir_shader_get_entrypoint(stages[i].nir)); - radv_lower_io(device, stages[i].nir); + radv_lower_io(device, stages[i].nir, stages[MESA_SHADER_MESH].nir); stages[i].feedback.duration += os_time_get_nano() - stage_start; } diff --git a/src/amd/vulkan/radv_shader.c b/src/amd/vulkan/radv_shader.c index d4867958e1f..27b35f98b3f 100644 --- a/src/amd/vulkan/radv_shader.c +++ b/src/amd/vulkan/radv_shader.c @@ -991,7 +991,7 @@ find_layer_in_var(nir_shader *nir) */ static bool -lower_view_index(nir_shader *nir) +lower_view_index(nir_shader *nir, bool per_primitive) { bool progress = false; nir_function_impl *entry = nir_shader_get_entrypoint(nir); @@ -1011,12 +1011,15 @@ lower_view_index(nir_shader *nir) if (!layer) layer = find_layer_in_var(nir); + layer->data.per_primitive = per_primitive; b.cursor = nir_before_instr(instr); nir_ssa_def *def = nir_load_var(&b, layer); nir_ssa_def_rewrite_uses(&load->dest.ssa, def); /* Update inputs_read to reflect that the pass added a new input. */ nir->info.inputs_read |= VARYING_BIT_LAYER; + if (per_primitive) + nir->info.per_primitive_inputs |= VARYING_BIT_LAYER; nir_instr_remove(instr); progress = true; @@ -1032,13 +1035,13 @@ lower_view_index(nir_shader *nir) } void -radv_lower_io(struct radv_device *device, nir_shader *nir) +radv_lower_io(struct radv_device *device, nir_shader *nir, bool is_mesh_shading) { if (nir->info.stage == MESA_SHADER_COMPUTE) return; if (nir->info.stage == MESA_SHADER_FRAGMENT) { - NIR_PASS(_, nir, lower_view_index); + NIR_PASS(_, nir, lower_view_index, is_mesh_shading); nir_assign_io_var_locations(nir, nir_var_shader_in, &nir->num_inputs, MESA_SHADER_FRAGMENT); } @@ -1239,7 +1242,7 @@ void radv_lower_ngg(struct radv_device *device, struct radv_pipeline_stage *ngg_ info->ngg_info.esgs_ring_size, info->gs.gsvs_vertex_size, info->ngg_info.ngg_emit_size * 4u, pl_key->vs.provoking_vtx_last); } else if (nir->info.stage == MESA_SHADER_MESH) { - NIR_PASS_V(nir, ac_nir_lower_ngg_ms, info->wave_size); + NIR_PASS_V(nir, ac_nir_lower_ngg_ms, info->wave_size, pl_key->has_multiview_view_index); } else { unreachable("invalid SW stage passed to radv_lower_ngg"); } diff --git a/src/amd/vulkan/radv_shader.h b/src/amd/vulkan/radv_shader.h index 68744bde46c..0044d1e98d6 100644 --- a/src/amd/vulkan/radv_shader.h +++ b/src/amd/vulkan/radv_shader.h @@ -678,7 +678,7 @@ get_tcs_num_patches(unsigned tcs_num_input_vertices, unsigned tcs_num_output_ver return num_patches; } -void radv_lower_io(struct radv_device *device, nir_shader *nir); +void radv_lower_io(struct radv_device *device, nir_shader *nir, bool is_mesh_shading); bool radv_lower_io_to_mem(struct radv_device *device, struct radv_pipeline_stage *stage, const struct radv_pipeline_key *pl_key); diff --git a/src/amd/vulkan/radv_shader_info.c b/src/amd/vulkan/radv_shader_info.c index 6fcd773b4df..01278686367 100644 --- a/src/amd/vulkan/radv_shader_info.c +++ b/src/amd/vulkan/radv_shader_info.c @@ -509,6 +509,12 @@ radv_nir_shader_info_pass(struct radv_device *device, const struct nir_shader *n uint64_t per_vtx_mask = nir->info.outputs_written & ~nir->info.per_primitive_outputs & ~special_mask; + /* Mesh multivew is only lowered in ac_nir_lower_ngg, so we have to fake it here. */ + if (nir->info.stage == MESA_SHADER_MESH && pipeline_key->has_multiview_view_index) { + per_prim_mask |= VARYING_BIT_LAYER; + info->uses_view_index = true; + } + /* Per vertex outputs. */ outinfo->writes_pointsize = per_vtx_mask & VARYING_BIT_PSIZ; outinfo->writes_viewport_index = per_vtx_mask & VARYING_BIT_VIEWPORT;