diff options
| author | 2021-04-04 03:04:48 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:26 -0400 | |
| commit | fc93bc2abde0b54a0a495f9b28a76fd34b47f320 (patch) | |
| tree | fc0b0c022604b3e4adfc28864b8c91b58a9b3c06 /src/shader_recompiler | |
| parent | shader: Abstract breadth searches and use the abstraction (diff) | |
| download | yuzu-fc93bc2abde0b54a0a495f9b28a76fd34b47f320.tar.gz yuzu-fc93bc2abde0b54a0a495f9b28a76fd34b47f320.tar.xz yuzu-fc93bc2abde0b54a0a495f9b28a76fd34b47f320.zip | |
shader: Implement BAR and fix memory barriers
Diffstat (limited to 'src/shader_recompiler')
7 files changed, 79 insertions, 5 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index e066ba87d..032b0b2f9 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h | |||
| @@ -28,6 +28,7 @@ void EmitSelectionMerge(EmitContext& ctx, Id merge_label); | |||
| 28 | void EmitReturn(EmitContext& ctx); | 28 | void EmitReturn(EmitContext& ctx); |
| 29 | void EmitUnreachable(EmitContext& ctx); | 29 | void EmitUnreachable(EmitContext& ctx); |
| 30 | void EmitDemoteToHelperInvocation(EmitContext& ctx, Id continue_label); | 30 | void EmitDemoteToHelperInvocation(EmitContext& ctx, Id continue_label); |
| 31 | void EmitBarrier(EmitContext& ctx); | ||
| 31 | void EmitMemoryBarrierWorkgroupLevel(EmitContext& ctx); | 32 | void EmitMemoryBarrierWorkgroupLevel(EmitContext& ctx); |
| 32 | void EmitMemoryBarrierDeviceLevel(EmitContext& ctx); | 33 | void EmitMemoryBarrierDeviceLevel(EmitContext& ctx); |
| 33 | void EmitMemoryBarrierSystemLevel(EmitContext& ctx); | 34 | void EmitMemoryBarrierSystemLevel(EmitContext& ctx); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp index 18f512319..74f523d0f 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp | |||
| @@ -8,16 +8,25 @@ | |||
| 8 | namespace Shader::Backend::SPIRV { | 8 | namespace Shader::Backend::SPIRV { |
| 9 | namespace { | 9 | namespace { |
| 10 | void EmitMemoryBarrierImpl(EmitContext& ctx, spv::Scope scope) { | 10 | void EmitMemoryBarrierImpl(EmitContext& ctx, spv::Scope scope) { |
| 11 | const auto semantics = | 11 | const auto semantics{ |
| 12 | spv::MemorySemanticsMask::AcquireRelease | spv::MemorySemanticsMask::UniformMemory | | 12 | spv::MemorySemanticsMask::AcquireRelease | spv::MemorySemanticsMask::UniformMemory | |
| 13 | spv::MemorySemanticsMask::WorkgroupMemory | spv::MemorySemanticsMask::AtomicCounterMemory | | 13 | spv::MemorySemanticsMask::WorkgroupMemory | spv::MemorySemanticsMask::AtomicCounterMemory | |
| 14 | spv::MemorySemanticsMask::ImageMemory; | 14 | spv::MemorySemanticsMask::ImageMemory}; |
| 15 | ctx.OpMemoryBarrier(ctx.Constant(ctx.U32[1], static_cast<u32>(scope)), | 15 | ctx.OpMemoryBarrier(ctx.Constant(ctx.U32[1], static_cast<u32>(scope)), |
| 16 | ctx.Constant(ctx.U32[1], static_cast<u32>(semantics))); | 16 | ctx.Constant(ctx.U32[1], static_cast<u32>(semantics))); |
| 17 | } | 17 | } |
| 18 | |||
| 19 | } // Anonymous namespace | 18 | } // Anonymous namespace |
| 20 | 19 | ||
| 20 | void EmitBarrier(EmitContext& ctx) { | ||
| 21 | const auto execution{spv::Scope::Workgroup}; | ||
| 22 | const auto memory{spv::Scope::Workgroup}; | ||
| 23 | const auto memory_semantics{spv::MemorySemanticsMask::AcquireRelease | | ||
| 24 | spv::MemorySemanticsMask::WorkgroupMemory}; | ||
| 25 | ctx.OpControlBarrier(ctx.Constant(ctx.U32[1], static_cast<u32>(execution)), | ||
| 26 | ctx.Constant(ctx.U32[1], static_cast<u32>(memory)), | ||
| 27 | ctx.Constant(ctx.U32[1], static_cast<u32>(memory_semantics))); | ||
| 28 | } | ||
| 29 | |||
| 21 | void EmitMemoryBarrierWorkgroupLevel(EmitContext& ctx) { | 30 | void EmitMemoryBarrierWorkgroupLevel(EmitContext& ctx) { |
| 22 | EmitMemoryBarrierImpl(ctx, spv::Scope::Workgroup); | 31 | EmitMemoryBarrierImpl(ctx, spv::Scope::Workgroup); |
| 23 | } | 32 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index dbd38a28b..246c3b9ef 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -82,6 +82,10 @@ void IREmitter::SelectionMerge(Block* merge_block) { | |||
| 82 | Inst(Opcode::SelectionMerge, merge_block); | 82 | Inst(Opcode::SelectionMerge, merge_block); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | void IREmitter::Barrier() { | ||
| 86 | Inst(Opcode::Barrier); | ||
| 87 | } | ||
| 88 | |||
| 85 | void IREmitter::MemoryBarrier(MemoryScope scope) { | 89 | void IREmitter::MemoryBarrier(MemoryScope scope) { |
| 86 | switch (scope) { | 90 | switch (scope) { |
| 87 | case MemoryScope::Workgroup: | 91 | case MemoryScope::Workgroup: |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 81a57fefe..1b00c548d 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -128,6 +128,7 @@ public: | |||
| 128 | [[nodiscard]] Value Select(const U1& condition, const Value& true_value, | 128 | [[nodiscard]] Value Select(const U1& condition, const Value& true_value, |
| 129 | const Value& false_value); | 129 | const Value& false_value); |
| 130 | 130 | ||
| 131 | [[nodiscard]] void Barrier(); | ||
| 131 | [[nodiscard]] void MemoryBarrier(MemoryScope scope); | 132 | [[nodiscard]] void MemoryBarrier(MemoryScope scope); |
| 132 | 133 | ||
| 133 | template <typename Dest, typename Source> | 134 | template <typename Dest, typename Source> |
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp index 074c71d53..481202d94 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.cpp +++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp | |||
| @@ -57,6 +57,10 @@ bool Inst::MayHaveSideEffects() const noexcept { | |||
| 57 | case Opcode::Return: | 57 | case Opcode::Return: |
| 58 | case Opcode::Unreachable: | 58 | case Opcode::Unreachable: |
| 59 | case Opcode::DemoteToHelperInvocation: | 59 | case Opcode::DemoteToHelperInvocation: |
| 60 | case Opcode::Barrier: | ||
| 61 | case Opcode::MemoryBarrierWorkgroupLevel: | ||
| 62 | case Opcode::MemoryBarrierDeviceLevel: | ||
| 63 | case Opcode::MemoryBarrierSystemLevel: | ||
| 60 | case Opcode::Prologue: | 64 | case Opcode::Prologue: |
| 61 | case Opcode::Epilogue: | 65 | case Opcode::Epilogue: |
| 62 | case Opcode::SetAttribute: | 66 | case Opcode::SetAttribute: |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 734f5328b..dcd54bcf7 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -17,6 +17,7 @@ OPCODE(Unreachable, Void, | |||
| 17 | OPCODE(DemoteToHelperInvocation, Void, Label, ) | 17 | OPCODE(DemoteToHelperInvocation, Void, Label, ) |
| 18 | 18 | ||
| 19 | // Barriers | 19 | // Barriers |
| 20 | OPCODE(Barrier, Void, ) | ||
| 20 | OPCODE(MemoryBarrierWorkgroupLevel, Void, ) | 21 | OPCODE(MemoryBarrierWorkgroupLevel, Void, ) |
| 21 | OPCODE(MemoryBarrierDeviceLevel, Void, ) | 22 | OPCODE(MemoryBarrierDeviceLevel, Void, ) |
| 22 | OPCODE(MemoryBarrierSystemLevel, Void, ) | 23 | OPCODE(MemoryBarrierSystemLevel, Void, ) |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/barrier_operations.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/barrier_operations.cpp index 26d5e276b..2a2a294df 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/barrier_operations.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/barrier_operations.cpp | |||
| @@ -38,6 +38,7 @@ void TranslatorVisitor::MEMBAR(u64 inst) { | |||
| 38 | u64 raw; | 38 | u64 raw; |
| 39 | BitField<8, 2, LocalScope> scope; | 39 | BitField<8, 2, LocalScope> scope; |
| 40 | } membar{inst}; | 40 | } membar{inst}; |
| 41 | |||
| 41 | ir.MemoryBarrier(LocalScopeToMemoryScope(membar.scope)); | 42 | ir.MemoryBarrier(LocalScopeToMemoryScope(membar.scope)); |
| 42 | } | 43 | } |
| 43 | 44 | ||
| @@ -45,8 +46,61 @@ void TranslatorVisitor::DEPBAR() { | |||
| 45 | // DEPBAR is a no-op | 46 | // DEPBAR is a no-op |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | void TranslatorVisitor::BAR(u64) { | 49 | void TranslatorVisitor::BAR(u64 insn) { |
| 49 | throw NotImplementedException("Instruction {} is not implemented", Opcode::BAR); | 50 | enum class Mode { |
| 51 | RedPopc, | ||
| 52 | Scan, | ||
| 53 | RedAnd, | ||
| 54 | RedOr, | ||
| 55 | Sync, | ||
| 56 | Arrive, | ||
| 57 | }; | ||
| 58 | union { | ||
| 59 | u64 raw; | ||
| 60 | BitField<43, 1, u64> is_a_imm; | ||
| 61 | BitField<44, 1, u64> is_b_imm; | ||
| 62 | BitField<8, 8, u64> imm_a; | ||
| 63 | BitField<20, 12, u64> imm_b; | ||
| 64 | BitField<42, 1, u64> neg_pred; | ||
| 65 | BitField<39, 3, IR::Pred> pred; | ||
| 66 | } const bar{insn}; | ||
| 67 | |||
| 68 | const Mode mode{[insn] { | ||
| 69 | switch (insn & 0x0000009B00000000ULL) { | ||
| 70 | case 0x0000000200000000ULL: | ||
| 71 | return Mode::RedPopc; | ||
| 72 | case 0x0000000300000000ULL: | ||
| 73 | return Mode::Scan; | ||
| 74 | case 0x0000000A00000000ULL: | ||
| 75 | return Mode::RedAnd; | ||
| 76 | case 0x0000001200000000ULL: | ||
| 77 | return Mode::RedOr; | ||
| 78 | case 0x0000008000000000ULL: | ||
| 79 | return Mode::Sync; | ||
| 80 | case 0x0000008100000000ULL: | ||
| 81 | return Mode::Arrive; | ||
| 82 | } | ||
| 83 | throw NotImplementedException("Invalid encoding"); | ||
| 84 | }()}; | ||
| 85 | if (mode != Mode::Sync) { | ||
| 86 | throw NotImplementedException("BAR mode {}", mode); | ||
| 87 | } | ||
| 88 | if (bar.is_a_imm == 0) { | ||
| 89 | throw NotImplementedException("Non-immediate input A"); | ||
| 90 | } | ||
| 91 | if (bar.imm_a != 0) { | ||
| 92 | throw NotImplementedException("Non-zero input A"); | ||
| 93 | } | ||
| 94 | if (bar.is_b_imm == 0) { | ||
| 95 | throw NotImplementedException("Non-immediate input B"); | ||
| 96 | } | ||
| 97 | if (bar.imm_b != 0) { | ||
| 98 | throw NotImplementedException("Non-zero input B"); | ||
| 99 | } | ||
| 100 | if (bar.pred != IR::Pred::PT && bar.neg_pred != 0) { | ||
| 101 | throw NotImplementedException("Non-true input predicate"); | ||
| 102 | } | ||
| 103 | ir.Barrier(); | ||
| 50 | } | 104 | } |
| 51 | 105 | ||
| 52 | } // namespace Shader::Maxwell | 106 | } // namespace Shader::Maxwell |