summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/engines/shader_bytecode.h15
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp31
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 {
306public: 319public:
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);