diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 15 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 31 |
2 files changed, 45 insertions, 1 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index da64430e9..a57b90632 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -288,6 +288,19 @@ union Instruction { | |||
| 288 | } | 288 | } |
| 289 | } texs; | 289 | } texs; |
| 290 | 290 | ||
| 291 | union { | ||
| 292 | BitField<20, 5, u64> target; | ||
| 293 | BitField<5, 1, u64> constant_buffer; | ||
| 294 | |||
| 295 | s32 GetBranchTarget() const { | ||
| 296 | // Sign extend the branch target offset | ||
| 297 | u32 mask = 1U << (5 - 1); | ||
| 298 | u32 value = static_cast<u32>(target); | ||
| 299 | // The branch offset is relative to the next instruction, so add 1 to it. | ||
| 300 | return static_cast<s32>((value ^ mask) - mask) + 1; | ||
| 301 | } | ||
| 302 | } bra; | ||
| 303 | |||
| 291 | BitField<61, 1, u64> is_b_imm; | 304 | BitField<61, 1, u64> is_b_imm; |
| 292 | BitField<60, 1, u64> is_b_gpr; | 305 | BitField<60, 1, u64> is_b_gpr; |
| 293 | BitField<59, 1, u64> is_c_gpr; | 306 | BitField<59, 1, u64> is_c_gpr; |
| @@ -306,6 +319,7 @@ class OpCode { | |||
| 306 | public: | 319 | public: |
| 307 | enum class Id { | 320 | enum class Id { |
| 308 | KIL, | 321 | KIL, |
| 322 | BRA, | ||
| 309 | LD_A, | 323 | LD_A, |
| 310 | ST_A, | 324 | ST_A, |
| 311 | TEX, | 325 | TEX, |
| @@ -470,6 +484,7 @@ private: | |||
| 470 | std::vector<Matcher> table = { | 484 | std::vector<Matcher> table = { |
| 471 | #define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name) | 485 | #define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name) |
| 472 | INST("111000110011----", Id::KIL, Type::Flow, "KIL"), | 486 | INST("111000110011----", Id::KIL, Type::Flow, "KIL"), |
| 487 | INST("111000100100----", Id::BRA, Type::Flow, "BRA"), | ||
| 473 | INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), | 488 | INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), |
| 474 | INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"), | 489 | INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"), |
| 475 | INST("1100000000111---", Id::TEX, Type::Memory, "TEX"), | 490 | INST("1100000000111---", Id::TEX, Type::Memory, "TEX"), |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index bb5209a7e..4cfd6f042 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -88,6 +88,20 @@ private: | |||
| 88 | return *subroutines.insert(std::move(subroutine)).first; | 88 | return *subroutines.insert(std::move(subroutine)).first; |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | /// Merges exit method of two parallel branches. | ||
| 92 | static ExitMethod ParallelExit(ExitMethod a, ExitMethod b) { | ||
| 93 | if (a == ExitMethod::Undetermined) { | ||
| 94 | return b; | ||
| 95 | } | ||
| 96 | if (b == ExitMethod::Undetermined) { | ||
| 97 | return a; | ||
| 98 | } | ||
| 99 | if (a == b) { | ||
| 100 | return a; | ||
| 101 | } | ||
| 102 | return ExitMethod::Conditional; | ||
| 103 | } | ||
| 104 | |||
| 91 | /// Scans a range of code for labels and determines the exit method. | 105 | /// Scans a range of code for labels and determines the exit method. |
| 92 | ExitMethod Scan(u32 begin, u32 end, std::set<u32>& labels) { | 106 | ExitMethod Scan(u32 begin, u32 end, std::set<u32>& labels) { |
| 93 | auto [iter, inserted] = | 107 | auto [iter, inserted] = |
| @@ -97,11 +111,19 @@ private: | |||
| 97 | return exit_method; | 111 | return exit_method; |
| 98 | 112 | ||
| 99 | for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) { | 113 | for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) { |
| 100 | if (const auto opcode = OpCode::Decode({program_code[offset]})) { | 114 | const Instruction instr = {program_code[offset]}; |
| 115 | if (const auto opcode = OpCode::Decode(instr)) { | ||
| 101 | switch (opcode->GetId()) { | 116 | switch (opcode->GetId()) { |
| 102 | case OpCode::Id::EXIT: { | 117 | case OpCode::Id::EXIT: { |
| 103 | return exit_method = ExitMethod::AlwaysEnd; | 118 | return exit_method = ExitMethod::AlwaysEnd; |
| 104 | } | 119 | } |
| 120 | case OpCode::Id::BRA: { | ||
| 121 | u32 target = offset + instr.bra.GetBranchTarget(); | ||
| 122 | labels.insert(target); | ||
| 123 | ExitMethod no_jmp = Scan(offset + 1, end, labels); | ||
| 124 | ExitMethod jmp = Scan(target, end, labels); | ||
| 125 | return exit_method = ParallelExit(no_jmp, jmp); | ||
| 126 | } | ||
| 105 | } | 127 | } |
| 106 | } | 128 | } |
| 107 | } | 129 | } |
| @@ -1081,6 +1103,13 @@ private: | |||
| 1081 | shader.AddLine("discard;"); | 1103 | shader.AddLine("discard;"); |
| 1082 | break; | 1104 | break; |
| 1083 | } | 1105 | } |
| 1106 | case OpCode::Id::BRA: { | ||
| 1107 | ASSERT_MSG(instr.bra.constant_buffer == 0, | ||
| 1108 | "BRA with constant buffers are not implemented"); | ||
| 1109 | u32 target = offset + instr.bra.GetBranchTarget(); | ||
| 1110 | shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); | ||
| 1111 | break; | ||
| 1112 | } | ||
| 1084 | case OpCode::Id::IPA: { | 1113 | case OpCode::Id::IPA: { |
| 1085 | const auto& attribute = instr.attribute.fmt28; | 1114 | const auto& attribute = instr.attribute.fmt28; |
| 1086 | regs.SetRegisterToInputAttibute(instr.gpr0, attribute.element, attribute.index); | 1115 | regs.SetRegisterToInputAttibute(instr.gpr0, attribute.element, attribute.index); |