From 180c1b924e1ed3a2918fad9c5cbb653524de8233 Mon Sep 17 00:00:00 2001 From: Bas Nieuwenhuizen Date: Wed, 16 Aug 2017 09:09:56 +0200 Subject: [PATCH] ac/nir: Add shader support for multiviews. It uses an user SGPR to pass the view index to the shaders, except for the fragment shader where we use layer=view (which comes in handy when we want to do the NV ext that allows us to execute pre-FS stages once instead of per view). Reviewed-by: Dave Airlie --- src/amd/common/ac_nir_to_llvm.c | 38 ++++++++++++++++++++++++++++++++- src/amd/common/ac_nir_to_llvm.h | 4 +++- src/amd/common/ac_shader_info.c | 3 +++ src/amd/common/ac_shader_info.h | 1 + 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/amd/common/ac_nir_to_llvm.c b/src/amd/common/ac_nir_to_llvm.c index c0c4f3a78d4..664d83bd2ea 100644 --- a/src/amd/common/ac_nir_to_llvm.c +++ b/src/amd/common/ac_nir_to_llvm.c @@ -90,6 +90,7 @@ struct nir_to_llvm_context { LLVMValueRef descriptor_sets[AC_UD_MAX_SETS]; LLVMValueRef ring_offsets; LLVMValueRef push_constants; + LLVMValueRef view_index; LLVMValueRef num_work_groups; LLVMValueRef workgroup_ids; LLVMValueRef local_invocation_ids; @@ -744,6 +745,8 @@ static void create_function(struct nir_to_llvm_context *ctx) if (ctx->shader_info->info.vs.needs_draw_id) add_user_sgpr_argument(&args, ctx->i32, &ctx->abi.draw_id); // draw id } + if (ctx->shader_info->info.needs_multiview_view_index || (!ctx->options->key.vs.as_es && !ctx->options->key.vs.as_ls && ctx->options->key.has_multiview_view_index)) + add_user_sgpr_argument(&args, ctx->i32, &ctx->view_index); if (ctx->options->key.vs.as_es) add_sgpr_argument(&args, ctx->i32, &ctx->es2gs_offset); // es2gs offset else if (ctx->options->key.vs.as_ls) @@ -760,6 +763,8 @@ static void create_function(struct nir_to_llvm_context *ctx) add_user_sgpr_argument(&args, ctx->i32, &ctx->tcs_out_offsets); // tcs out offsets add_user_sgpr_argument(&args, ctx->i32, &ctx->tcs_out_layout); // tcs out layout add_user_sgpr_argument(&args, ctx->i32, &ctx->tcs_in_layout); // tcs in layout + if (ctx->shader_info->info.needs_multiview_view_index) + add_user_sgpr_argument(&args, ctx->i32, &ctx->view_index); add_sgpr_argument(&args, ctx->i32, &ctx->oc_lds); // param oc lds add_sgpr_argument(&args, ctx->i32, &ctx->tess_factor_offset); // tess factor offset add_vgpr_argument(&args, ctx->i32, &ctx->tcs_patch_id); // patch id @@ -767,6 +772,8 @@ static void create_function(struct nir_to_llvm_context *ctx) break; case MESA_SHADER_TESS_EVAL: add_user_sgpr_argument(&args, ctx->i32, &ctx->tcs_offchip_layout); // tcs offchip layout + if (ctx->shader_info->info.needs_multiview_view_index || (!ctx->options->key.tes.as_es && ctx->options->key.has_multiview_view_index)) + add_user_sgpr_argument(&args, ctx->i32, &ctx->view_index); if (ctx->options->key.tes.as_es) { add_sgpr_argument(&args, ctx->i32, &ctx->oc_lds); // OC LDS add_sgpr_argument(&args, ctx->i32, NULL); // @@ -783,6 +790,8 @@ static void create_function(struct nir_to_llvm_context *ctx) case MESA_SHADER_GEOMETRY: add_user_sgpr_argument(&args, ctx->i32, &ctx->gsvs_ring_stride); // gsvs stride add_user_sgpr_argument(&args, ctx->i32, &ctx->gsvs_num_entries); // gsvs num entires + if (ctx->shader_info->info.needs_multiview_view_index) + add_user_sgpr_argument(&args, ctx->i32, &ctx->view_index); add_sgpr_argument(&args, ctx->i32, &ctx->gs2vs_offset); // gs2vs offset add_sgpr_argument(&args, ctx->i32, &ctx->gs_wave_id); // wave id add_vgpr_argument(&args, ctx->i32, &ctx->gs_vtx_offset[0]); // vtx0 @@ -894,6 +903,8 @@ static void create_function(struct nir_to_llvm_context *ctx) set_userdata_location_shader(ctx, AC_UD_VS_BASE_VERTEX_START_INSTANCE, &user_sgpr_idx, vs_num); } + if (ctx->view_index) + set_userdata_location_shader(ctx, AC_UD_VIEW_INDEX, &user_sgpr_idx, 1); if (ctx->options->key.vs.as_ls) { set_userdata_location_shader(ctx, AC_UD_VS_LS_TCS_IN_LAYOUT, &user_sgpr_idx, 1); } @@ -902,13 +913,19 @@ static void create_function(struct nir_to_llvm_context *ctx) break; case MESA_SHADER_TESS_CTRL: set_userdata_location_shader(ctx, AC_UD_TCS_OFFCHIP_LAYOUT, &user_sgpr_idx, 4); + if (ctx->view_index) + set_userdata_location_shader(ctx, AC_UD_VIEW_INDEX, &user_sgpr_idx, 1); declare_tess_lds(ctx); break; case MESA_SHADER_TESS_EVAL: set_userdata_location_shader(ctx, AC_UD_TES_OFFCHIP_LAYOUT, &user_sgpr_idx, 1); + if (ctx->view_index) + set_userdata_location_shader(ctx, AC_UD_VIEW_INDEX, &user_sgpr_idx, 1); break; case MESA_SHADER_GEOMETRY: set_userdata_location_shader(ctx, AC_UD_GS_VS_RING_STRIDE_ENTRIES, &user_sgpr_idx, 2); + if (ctx->view_index) + set_userdata_location_shader(ctx, AC_UD_VIEW_INDEX, &user_sgpr_idx, 1); break; case MESA_SHADER_FRAGMENT: if (ctx->shader_info->info.ps.needs_sample_positions) { @@ -4022,6 +4039,9 @@ static void visit_intrinsic(struct ac_nir_context *ctx, case nir_intrinsic_load_draw_id: result = ctx->abi->draw_id; break; + case nir_intrinsic_load_view_index: + result = ctx->nctx->view_index ? ctx->nctx->view_index : ctx->ac.i32_0; + break; case nir_intrinsic_load_invocation_id: if (ctx->stage == MESA_SHADER_TESS_CTRL) result = unpack_param(&ctx->ac, ctx->nctx->tcs_rel_ids, 8, 5); @@ -5068,7 +5088,8 @@ handle_fs_inputs(struct nir_to_llvm_context *ctx, unsigned index = 0; - if (ctx->shader_info->info.ps.uses_input_attachments) + if (ctx->shader_info->info.ps.uses_input_attachments || + ctx->shader_info->info.needs_multiview_view_index) ctx->input_mask |= 1ull << VARYING_SLOT_LAYER; for (unsigned i = 0; i < RADEON_LLVM_MAX_INPUTS; ++i) { @@ -5103,6 +5124,9 @@ handle_fs_inputs(struct nir_to_llvm_context *ctx, if (ctx->input_mask & (1 << VARYING_SLOT_LAYER)) ctx->shader_info->fs.layer_input = true; ctx->shader_info->fs.input_mask = ctx->input_mask >> VARYING_SLOT_VAR0; + + if (ctx->shader_info->info.needs_multiview_view_index) + ctx->view_index = ctx->inputs[radeon_llvm_reg_index_soa(VARYING_SLOT_LAYER, 0)]; } static LLVMValueRef @@ -5507,6 +5531,18 @@ handle_vs_outputs_post(struct nir_to_llvm_context *ctx, LLVMValueRef psize_value = NULL, layer_value = NULL, viewport_index_value = NULL; int i; + if (ctx->options->key.has_multiview_view_index) { + LLVMValueRef* tmp_out = &ctx->nir->outputs[radeon_llvm_reg_index_soa(VARYING_SLOT_LAYER, 0)]; + if(!*tmp_out) { + for(unsigned i = 0; i < 4; ++i) + ctx->nir->outputs[radeon_llvm_reg_index_soa(VARYING_SLOT_LAYER, i)] = + si_build_alloca_undef(&ctx->ac, ctx->ac.f32, ""); + } + + LLVMBuildStore(ctx->builder, to_float(&ctx->ac, ctx->view_index), *tmp_out); + ctx->output_mask |= 1ull << VARYING_SLOT_LAYER; + } + memset(outinfo->vs_output_param_offset, AC_EXP_PARAM_UNDEFINED, sizeof(outinfo->vs_output_param_offset)); diff --git a/src/amd/common/ac_nir_to_llvm.h b/src/amd/common/ac_nir_to_llvm.h index a6e01782ba8..6621d7bc5ad 100644 --- a/src/amd/common/ac_nir_to_llvm.h +++ b/src/amd/common/ac_nir_to_llvm.h @@ -70,6 +70,7 @@ struct ac_shader_variant_key { struct ac_tes_variant_key tes; struct ac_tcs_variant_key tcs; }; + bool has_multiview_view_index; }; struct ac_nir_compiler_options { @@ -92,7 +93,8 @@ enum ac_ud_index { AC_UD_SCRATCH_RING_OFFSETS = 0, AC_UD_PUSH_CONSTANTS = 1, AC_UD_INDIRECT_DESCRIPTOR_SETS = 2, - AC_UD_SHADER_START = 3, + AC_UD_VIEW_INDEX = 3, + AC_UD_SHADER_START = 4, AC_UD_VS_VERTEX_BUFFERS = AC_UD_SHADER_START, AC_UD_VS_BASE_VERTEX_START_INSTANCE, AC_UD_VS_LS_TCS_IN_LAYOUT, diff --git a/src/amd/common/ac_shader_info.c b/src/amd/common/ac_shader_info.c index ca59965e2db..979b120b731 100644 --- a/src/amd/common/ac_shader_info.c +++ b/src/amd/common/ac_shader_info.c @@ -51,6 +51,9 @@ gather_intrinsic_info(nir_intrinsic_instr *instr, struct ac_shader_info *info) case nir_intrinsic_load_sample_pos: info->ps.force_persample = true; break; + case nir_intrinsic_load_view_index: + info->needs_multiview_view_index = true; + break; case nir_intrinsic_vulkan_resource_index: info->desc_set_used_mask |= (1 << nir_intrinsic_desc_set(instr)); break; diff --git a/src/amd/common/ac_shader_info.h b/src/amd/common/ac_shader_info.h index 886b5e84b57..c1d36a667ee 100644 --- a/src/amd/common/ac_shader_info.h +++ b/src/amd/common/ac_shader_info.h @@ -30,6 +30,7 @@ struct ac_nir_compiler_options; struct ac_shader_info { bool needs_push_constants; uint32_t desc_set_used_mask; + bool needs_multiview_view_index; struct { bool has_vertex_buffers; /* needs vertex buffers and base/start */ bool needs_draw_id;