diff options
Diffstat (limited to 'src/shader_recompiler')
| -rw-r--r-- | src/shader_recompiler/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_spirv.cpp | 13 | ||||
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp | 2 | ||||
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp | 35 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/translate_program.cpp | 81 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/translate_program.h | 9 | ||||
| -rw-r--r-- | src/shader_recompiler/host_translate_info.h | 3 | ||||
| -rw-r--r-- | src/shader_recompiler/ir_opt/layer_pass.cpp | 68 | ||||
| -rw-r--r-- | src/shader_recompiler/ir_opt/passes.h | 1 | ||||
| -rw-r--r-- | src/shader_recompiler/shader_info.h | 3 |
10 files changed, 196 insertions, 20 deletions
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 545d69c7e..8cd584154 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -221,6 +221,7 @@ add_library(shader_recompiler STATIC | |||
| 221 | ir_opt/dual_vertex_pass.cpp | 221 | ir_opt/dual_vertex_pass.cpp |
| 222 | ir_opt/global_memory_to_storage_buffer_pass.cpp | 222 | ir_opt/global_memory_to_storage_buffer_pass.cpp |
| 223 | ir_opt/identity_removal_pass.cpp | 223 | ir_opt/identity_removal_pass.cpp |
| 224 | ir_opt/layer_pass.cpp | ||
| 224 | ir_opt/lower_fp16_to_fp32.cpp | 225 | ir_opt/lower_fp16_to_fp32.cpp |
| 225 | ir_opt/lower_int64_to_int32.cpp | 226 | ir_opt/lower_int64_to_int32.cpp |
| 226 | ir_opt/passes.h | 227 | ir_opt/passes.h |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 265ac9c85..0f86a8004 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp | |||
| @@ -402,8 +402,10 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct | |||
| 402 | ctx.AddCapability(spv::Capability::SparseResidency); | 402 | ctx.AddCapability(spv::Capability::SparseResidency); |
| 403 | } | 403 | } |
| 404 | if (info.uses_demote_to_helper_invocation && profile.support_demote_to_helper_invocation) { | 404 | if (info.uses_demote_to_helper_invocation && profile.support_demote_to_helper_invocation) { |
| 405 | ctx.AddExtension("SPV_EXT_demote_to_helper_invocation"); | 405 | if (profile.supported_spirv < 0x00010600) { |
| 406 | ctx.AddCapability(spv::Capability::DemoteToHelperInvocationEXT); | 406 | ctx.AddExtension("SPV_EXT_demote_to_helper_invocation"); |
| 407 | } | ||
| 408 | ctx.AddCapability(spv::Capability::DemoteToHelperInvocation); | ||
| 407 | } | 409 | } |
| 408 | if (info.stores[IR::Attribute::ViewportIndex]) { | 410 | if (info.stores[IR::Attribute::ViewportIndex]) { |
| 409 | ctx.AddCapability(spv::Capability::MultiViewport); | 411 | ctx.AddCapability(spv::Capability::MultiViewport); |
| @@ -426,12 +428,11 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct | |||
| 426 | if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id || | 428 | if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id || |
| 427 | info.uses_subgroup_shuffles) && | 429 | info.uses_subgroup_shuffles) && |
| 428 | profile.support_vote) { | 430 | profile.support_vote) { |
| 429 | ctx.AddExtension("SPV_KHR_shader_ballot"); | 431 | ctx.AddCapability(spv::Capability::GroupNonUniformBallot); |
| 430 | ctx.AddCapability(spv::Capability::SubgroupBallotKHR); | 432 | ctx.AddCapability(spv::Capability::GroupNonUniformShuffle); |
| 431 | if (!profile.warp_size_potentially_larger_than_guest) { | 433 | if (!profile.warp_size_potentially_larger_than_guest) { |
| 432 | // vote ops are only used when not taking the long path | 434 | // vote ops are only used when not taking the long path |
| 433 | ctx.AddExtension("SPV_KHR_subgroup_vote"); | 435 | ctx.AddCapability(spv::Capability::GroupNonUniformVote); |
| 434 | ctx.AddCapability(spv::Capability::SubgroupVoteKHR); | ||
| 435 | } | 436 | } |
| 436 | } | 437 | } |
| 437 | if (info.uses_int64_bit_atomics && profile.support_int64_atomics) { | 438 | if (info.uses_int64_bit_atomics && profile.support_int64_atomics) { |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp index 7ad0b08ac..fb2c792c1 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp | |||
| @@ -12,7 +12,7 @@ void EmitJoin(EmitContext&) { | |||
| 12 | 12 | ||
| 13 | void EmitDemoteToHelperInvocation(EmitContext& ctx) { | 13 | void EmitDemoteToHelperInvocation(EmitContext& ctx) { |
| 14 | if (ctx.profile.support_demote_to_helper_invocation) { | 14 | if (ctx.profile.support_demote_to_helper_invocation) { |
| 15 | ctx.OpDemoteToHelperInvocationEXT(); | 15 | ctx.OpDemoteToHelperInvocation(); |
| 16 | } else { | 16 | } else { |
| 17 | const Id kill_label{ctx.OpLabel()}; | 17 | const Id kill_label{ctx.OpLabel()}; |
| 18 | const Id impossible_label{ctx.OpLabel()}; | 18 | const Id impossible_label{ctx.OpLabel()}; |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp index 7cbbbfaa6..2c90f2368 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | namespace Shader::Backend::SPIRV { | 7 | namespace Shader::Backend::SPIRV { |
| 8 | namespace { | 8 | namespace { |
| 9 | Id SubgroupScope(EmitContext& ctx) { | ||
| 10 | return ctx.Const(static_cast<u32>(spv::Scope::Subgroup)); | ||
| 11 | } | ||
| 12 | |||
| 9 | Id GetThreadId(EmitContext& ctx) { | 13 | Id GetThreadId(EmitContext& ctx) { |
| 10 | return ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id); | 14 | return ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id); |
| 11 | } | 15 | } |
| @@ -49,8 +53,9 @@ Id GetMaxThreadId(EmitContext& ctx, Id thread_id, Id clamp, Id segmentation_mask | |||
| 49 | } | 53 | } |
| 50 | 54 | ||
| 51 | Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) { | 55 | Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) { |
| 52 | return ctx.OpSelect(ctx.U32[1], in_range, | 56 | return ctx.OpSelect( |
| 53 | ctx.OpSubgroupReadInvocationKHR(ctx.U32[1], value, src_thread_id), value); | 57 | ctx.U32[1], in_range, |
| 58 | ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id), value); | ||
| 54 | } | 59 | } |
| 55 | 60 | ||
| 56 | Id GetUpperClamp(EmitContext& ctx, Id invocation_id, Id clamp) { | 61 | Id GetUpperClamp(EmitContext& ctx, Id invocation_id, Id clamp) { |
| @@ -71,40 +76,46 @@ Id EmitLaneId(EmitContext& ctx) { | |||
| 71 | 76 | ||
| 72 | Id EmitVoteAll(EmitContext& ctx, Id pred) { | 77 | Id EmitVoteAll(EmitContext& ctx, Id pred) { |
| 73 | if (!ctx.profile.warp_size_potentially_larger_than_guest) { | 78 | if (!ctx.profile.warp_size_potentially_larger_than_guest) { |
| 74 | return ctx.OpSubgroupAllKHR(ctx.U1, pred); | 79 | return ctx.OpGroupNonUniformAll(ctx.U1, SubgroupScope(ctx), pred); |
| 75 | } | 80 | } |
| 76 | const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; | 81 | const Id mask_ballot{ |
| 82 | ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)}; | ||
| 77 | const Id active_mask{WarpExtract(ctx, mask_ballot)}; | 83 | const Id active_mask{WarpExtract(ctx, mask_ballot)}; |
| 78 | const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; | 84 | const Id ballot{ |
| 85 | WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))}; | ||
| 79 | const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; | 86 | const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; |
| 80 | return ctx.OpIEqual(ctx.U1, lhs, active_mask); | 87 | return ctx.OpIEqual(ctx.U1, lhs, active_mask); |
| 81 | } | 88 | } |
| 82 | 89 | ||
| 83 | Id EmitVoteAny(EmitContext& ctx, Id pred) { | 90 | Id EmitVoteAny(EmitContext& ctx, Id pred) { |
| 84 | if (!ctx.profile.warp_size_potentially_larger_than_guest) { | 91 | if (!ctx.profile.warp_size_potentially_larger_than_guest) { |
| 85 | return ctx.OpSubgroupAnyKHR(ctx.U1, pred); | 92 | return ctx.OpGroupNonUniformAny(ctx.U1, SubgroupScope(ctx), pred); |
| 86 | } | 93 | } |
| 87 | const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; | 94 | const Id mask_ballot{ |
| 95 | ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)}; | ||
| 88 | const Id active_mask{WarpExtract(ctx, mask_ballot)}; | 96 | const Id active_mask{WarpExtract(ctx, mask_ballot)}; |
| 89 | const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; | 97 | const Id ballot{ |
| 98 | WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))}; | ||
| 90 | const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; | 99 | const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; |
| 91 | return ctx.OpINotEqual(ctx.U1, lhs, ctx.u32_zero_value); | 100 | return ctx.OpINotEqual(ctx.U1, lhs, ctx.u32_zero_value); |
| 92 | } | 101 | } |
| 93 | 102 | ||
| 94 | Id EmitVoteEqual(EmitContext& ctx, Id pred) { | 103 | Id EmitVoteEqual(EmitContext& ctx, Id pred) { |
| 95 | if (!ctx.profile.warp_size_potentially_larger_than_guest) { | 104 | if (!ctx.profile.warp_size_potentially_larger_than_guest) { |
| 96 | return ctx.OpSubgroupAllEqualKHR(ctx.U1, pred); | 105 | return ctx.OpGroupNonUniformAllEqual(ctx.U1, SubgroupScope(ctx), pred); |
| 97 | } | 106 | } |
| 98 | const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; | 107 | const Id mask_ballot{ |
| 108 | ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)}; | ||
| 99 | const Id active_mask{WarpExtract(ctx, mask_ballot)}; | 109 | const Id active_mask{WarpExtract(ctx, mask_ballot)}; |
| 100 | const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; | 110 | const Id ballot{ |
| 111 | WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))}; | ||
| 101 | const Id lhs{ctx.OpBitwiseXor(ctx.U32[1], ballot, active_mask)}; | 112 | const Id lhs{ctx.OpBitwiseXor(ctx.U32[1], ballot, active_mask)}; |
| 102 | return ctx.OpLogicalOr(ctx.U1, ctx.OpIEqual(ctx.U1, lhs, ctx.u32_zero_value), | 113 | return ctx.OpLogicalOr(ctx.U1, ctx.OpIEqual(ctx.U1, lhs, ctx.u32_zero_value), |
| 103 | ctx.OpIEqual(ctx.U1, lhs, active_mask)); | 114 | ctx.OpIEqual(ctx.U1, lhs, active_mask)); |
| 104 | } | 115 | } |
| 105 | 116 | ||
| 106 | Id EmitSubgroupBallot(EmitContext& ctx, Id pred) { | 117 | Id EmitSubgroupBallot(EmitContext& ctx, Id pred) { |
| 107 | const Id ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], pred)}; | 118 | const Id ballot{ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred)}; |
| 108 | if (!ctx.profile.warp_size_potentially_larger_than_guest) { | 119 | if (!ctx.profile.warp_size_potentially_larger_than_guest) { |
| 109 | return ctx.OpCompositeExtract(ctx.U32[1], ballot, 0U); | 120 | return ctx.OpCompositeExtract(ctx.U32[1], ballot, 0U); |
| 110 | } | 121 | } |
diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index 376aae0ea..3adbd2b16 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/settings.h" | 9 | #include "common/settings.h" |
| 10 | #include "shader_recompiler/exception.h" | 10 | #include "shader_recompiler/exception.h" |
| 11 | #include "shader_recompiler/frontend/ir/basic_block.h" | 11 | #include "shader_recompiler/frontend/ir/basic_block.h" |
| 12 | #include "shader_recompiler/frontend/ir/ir_emitter.h" | ||
| 12 | #include "shader_recompiler/frontend/ir/post_order.h" | 13 | #include "shader_recompiler/frontend/ir/post_order.h" |
| 13 | #include "shader_recompiler/frontend/maxwell/structured_control_flow.h" | 14 | #include "shader_recompiler/frontend/maxwell/structured_control_flow.h" |
| 14 | #include "shader_recompiler/frontend/maxwell/translate/translate.h" | 15 | #include "shader_recompiler/frontend/maxwell/translate/translate.h" |
| @@ -233,6 +234,8 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo | |||
| 233 | Optimization::VerificationPass(program); | 234 | Optimization::VerificationPass(program); |
| 234 | } | 235 | } |
| 235 | Optimization::CollectShaderInfoPass(env, program); | 236 | Optimization::CollectShaderInfoPass(env, program); |
| 237 | Optimization::LayerPass(program, host_info); | ||
| 238 | |||
| 236 | CollectInterpolationInfo(env, program); | 239 | CollectInterpolationInfo(env, program); |
| 237 | AddNVNStorageBuffers(program); | 240 | AddNVNStorageBuffers(program); |
| 238 | return program; | 241 | return program; |
| @@ -331,4 +334,82 @@ void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& run | |||
| 331 | } | 334 | } |
| 332 | } | 335 | } |
| 333 | 336 | ||
| 337 | IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool, | ||
| 338 | ObjectPool<IR::Block>& block_pool, | ||
| 339 | const HostTranslateInfo& host_info, | ||
| 340 | IR::Program& source_program, | ||
| 341 | Shader::OutputTopology output_topology) { | ||
| 342 | IR::Program program; | ||
| 343 | program.stage = Stage::Geometry; | ||
| 344 | program.output_topology = output_topology; | ||
| 345 | switch (output_topology) { | ||
| 346 | case OutputTopology::PointList: | ||
| 347 | program.output_vertices = 1; | ||
| 348 | break; | ||
| 349 | case OutputTopology::LineStrip: | ||
| 350 | program.output_vertices = 2; | ||
| 351 | break; | ||
| 352 | default: | ||
| 353 | program.output_vertices = 3; | ||
| 354 | break; | ||
| 355 | } | ||
| 356 | |||
| 357 | program.is_geometry_passthrough = false; | ||
| 358 | program.info.loads.mask = source_program.info.stores.mask; | ||
| 359 | program.info.stores.mask = source_program.info.stores.mask; | ||
| 360 | program.info.stores.Set(IR::Attribute::Layer, true); | ||
| 361 | program.info.stores.Set(source_program.info.emulated_layer, false); | ||
| 362 | |||
| 363 | IR::Block* current_block = block_pool.Create(inst_pool); | ||
| 364 | auto& node{program.syntax_list.emplace_back()}; | ||
| 365 | node.type = IR::AbstractSyntaxNode::Type::Block; | ||
| 366 | node.data.block = current_block; | ||
| 367 | |||
| 368 | IR::IREmitter ir{*current_block}; | ||
| 369 | for (u32 i = 0; i < program.output_vertices; i++) { | ||
| 370 | // Assign generics from input | ||
| 371 | for (u32 j = 0; j < 32; j++) { | ||
| 372 | if (!program.info.stores.Generic(j)) { | ||
| 373 | continue; | ||
| 374 | } | ||
| 375 | |||
| 376 | const IR::Attribute attr = IR::Attribute::Generic0X + (j * 4); | ||
| 377 | ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); | ||
| 378 | ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); | ||
| 379 | ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); | ||
| 380 | ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); | ||
| 381 | } | ||
| 382 | |||
| 383 | // Assign position from input | ||
| 384 | const IR::Attribute attr = IR::Attribute::PositionX; | ||
| 385 | ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); | ||
| 386 | ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); | ||
| 387 | ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); | ||
| 388 | ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); | ||
| 389 | |||
| 390 | // Assign layer | ||
| 391 | ir.SetAttribute(IR::Attribute::Layer, ir.GetAttribute(source_program.info.emulated_layer), | ||
| 392 | ir.Imm32(0)); | ||
| 393 | |||
| 394 | // Emit vertex | ||
| 395 | ir.EmitVertex(ir.Imm32(0)); | ||
| 396 | } | ||
| 397 | ir.EndPrimitive(ir.Imm32(0)); | ||
| 398 | |||
| 399 | IR::Block* return_block{block_pool.Create(inst_pool)}; | ||
| 400 | IR::IREmitter{*return_block}.Epilogue(); | ||
| 401 | current_block->AddBranch(return_block); | ||
| 402 | |||
| 403 | auto& merge{program.syntax_list.emplace_back()}; | ||
| 404 | merge.type = IR::AbstractSyntaxNode::Type::Block; | ||
| 405 | merge.data.block = return_block; | ||
| 406 | program.syntax_list.emplace_back().type = IR::AbstractSyntaxNode::Type::Return; | ||
| 407 | |||
| 408 | program.blocks = GenerateBlocks(program.syntax_list); | ||
| 409 | program.post_order_blocks = PostOrder(program.syntax_list.front()); | ||
| 410 | Optimization::SsaRewritePass(program); | ||
| 411 | |||
| 412 | return program; | ||
| 413 | } | ||
| 414 | |||
| 334 | } // namespace Shader::Maxwell | 415 | } // namespace Shader::Maxwell |
diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.h b/src/shader_recompiler/frontend/maxwell/translate_program.h index 02ede8c9c..497afe7cb 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.h +++ b/src/shader_recompiler/frontend/maxwell/translate_program.h | |||
| @@ -25,4 +25,13 @@ namespace Shader::Maxwell { | |||
| 25 | 25 | ||
| 26 | void ConvertLegacyToGeneric(IR::Program& program, const RuntimeInfo& runtime_info); | 26 | void ConvertLegacyToGeneric(IR::Program& program, const RuntimeInfo& runtime_info); |
| 27 | 27 | ||
| 28 | // Maxwell v1 and older Nvidia cards don't support setting gl_Layer from non-geometry stages. | ||
| 29 | // This creates a workaround by setting the layer as a generic output and creating a | ||
| 30 | // passthrough geometry shader that reads the generic and sets the layer. | ||
| 31 | [[nodiscard]] IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool, | ||
| 32 | ObjectPool<IR::Block>& block_pool, | ||
| 33 | const HostTranslateInfo& host_info, | ||
| 34 | IR::Program& source_program, | ||
| 35 | Shader::OutputTopology output_topology); | ||
| 36 | |||
| 28 | } // namespace Shader::Maxwell | 37 | } // namespace Shader::Maxwell |
diff --git a/src/shader_recompiler/host_translate_info.h b/src/shader_recompiler/host_translate_info.h index cc1500690..d5d279554 100644 --- a/src/shader_recompiler/host_translate_info.h +++ b/src/shader_recompiler/host_translate_info.h | |||
| @@ -13,7 +13,8 @@ struct HostTranslateInfo { | |||
| 13 | bool support_float16{}; ///< True when the device supports 16-bit floats | 13 | bool support_float16{}; ///< True when the device supports 16-bit floats |
| 14 | bool support_int64{}; ///< True when the device supports 64-bit integers | 14 | bool support_int64{}; ///< True when the device supports 64-bit integers |
| 15 | bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered | 15 | bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered |
| 16 | bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers | 16 | bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers |
| 17 | bool support_viewport_index_layer{}; ///< True when the device supports gl_Layer in VS | ||
| 17 | }; | 18 | }; |
| 18 | 19 | ||
| 19 | } // namespace Shader | 20 | } // namespace Shader |
diff --git a/src/shader_recompiler/ir_opt/layer_pass.cpp b/src/shader_recompiler/ir_opt/layer_pass.cpp new file mode 100644 index 000000000..4574f7cf2 --- /dev/null +++ b/src/shader_recompiler/ir_opt/layer_pass.cpp | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <bit> | ||
| 6 | #include <optional> | ||
| 7 | |||
| 8 | #include <boost/container/small_vector.hpp> | ||
| 9 | |||
| 10 | #include "shader_recompiler/environment.h" | ||
| 11 | #include "shader_recompiler/frontend/ir/basic_block.h" | ||
| 12 | #include "shader_recompiler/frontend/ir/breadth_first_search.h" | ||
| 13 | #include "shader_recompiler/frontend/ir/ir_emitter.h" | ||
| 14 | #include "shader_recompiler/host_translate_info.h" | ||
| 15 | #include "shader_recompiler/ir_opt/passes.h" | ||
| 16 | #include "shader_recompiler/shader_info.h" | ||
| 17 | |||
| 18 | namespace Shader::Optimization { | ||
| 19 | |||
| 20 | static IR::Attribute EmulatedLayerAttribute(VaryingState& stores) { | ||
| 21 | for (u32 i = 0; i < 32; i++) { | ||
| 22 | if (!stores.Generic(i)) { | ||
| 23 | return IR::Attribute::Generic0X + (i * 4); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | return IR::Attribute::Layer; | ||
| 27 | } | ||
| 28 | |||
| 29 | static bool PermittedProgramStage(Stage stage) { | ||
| 30 | switch (stage) { | ||
| 31 | case Stage::VertexA: | ||
| 32 | case Stage::VertexB: | ||
| 33 | case Stage::TessellationControl: | ||
| 34 | case Stage::TessellationEval: | ||
| 35 | return true; | ||
| 36 | default: | ||
| 37 | return false; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | void LayerPass(IR::Program& program, const HostTranslateInfo& host_info) { | ||
| 42 | if (host_info.support_viewport_index_layer || !PermittedProgramStage(program.stage)) { | ||
| 43 | return; | ||
| 44 | } | ||
| 45 | |||
| 46 | const auto end{program.post_order_blocks.end()}; | ||
| 47 | const auto layer_attribute = EmulatedLayerAttribute(program.info.stores); | ||
| 48 | bool requires_layer_emulation = false; | ||
| 49 | |||
| 50 | for (auto block = program.post_order_blocks.begin(); block != end; ++block) { | ||
| 51 | for (IR::Inst& inst : (*block)->Instructions()) { | ||
| 52 | if (inst.GetOpcode() == IR::Opcode::SetAttribute && | ||
| 53 | inst.Arg(0).Attribute() == IR::Attribute::Layer) { | ||
| 54 | requires_layer_emulation = true; | ||
| 55 | inst.SetArg(0, IR::Value{layer_attribute}); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | if (requires_layer_emulation) { | ||
| 61 | program.info.requires_layer_emulation = true; | ||
| 62 | program.info.emulated_layer = layer_attribute; | ||
| 63 | program.info.stores.Set(IR::Attribute::Layer, false); | ||
| 64 | program.info.stores.Set(layer_attribute, true); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | } // namespace Shader::Optimization | ||
diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h index 586a0668f..11bfe801a 100644 --- a/src/shader_recompiler/ir_opt/passes.h +++ b/src/shader_recompiler/ir_opt/passes.h | |||
| @@ -23,6 +23,7 @@ void RescalingPass(IR::Program& program); | |||
| 23 | void SsaRewritePass(IR::Program& program); | 23 | void SsaRewritePass(IR::Program& program); |
| 24 | void PositionPass(Environment& env, IR::Program& program); | 24 | void PositionPass(Environment& env, IR::Program& program); |
| 25 | void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info); | 25 | void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info); |
| 26 | void LayerPass(IR::Program& program, const HostTranslateInfo& host_info); | ||
| 26 | void VerificationPass(const IR::Program& program); | 27 | void VerificationPass(const IR::Program& program); |
| 27 | 28 | ||
| 28 | // Dual Vertex | 29 | // Dual Vertex |
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index ee6252bb5..d9c6e92db 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -204,6 +204,9 @@ struct Info { | |||
| 204 | u32 nvn_buffer_base{}; | 204 | u32 nvn_buffer_base{}; |
| 205 | std::bitset<16> nvn_buffer_used{}; | 205 | std::bitset<16> nvn_buffer_used{}; |
| 206 | 206 | ||
| 207 | bool requires_layer_emulation{}; | ||
| 208 | IR::Attribute emulated_layer{}; | ||
| 209 | |||
| 207 | boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS> | 210 | boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS> |
| 208 | constant_buffer_descriptors; | 211 | constant_buffer_descriptors; |
| 209 | boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors; | 212 | boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors; |