diff options
| -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 {          }      } texs; +    union { +        BitField<20, 5, u64> target; +        BitField<5, 1, u64> constant_buffer; + +        s32 GetBranchTarget() const { +            // Sign extend the branch target offset +            u32 mask = 1U << (5 - 1); +            u32 value = static_cast<u32>(target); +            // The branch offset is relative to the next instruction, so add 1 to it. +            return static_cast<s32>((value ^ mask) - mask) + 1; +        } +    } bra; +      BitField<61, 1, u64> is_b_imm;      BitField<60, 1, u64> is_b_gpr;      BitField<59, 1, u64> is_c_gpr; @@ -306,6 +319,7 @@ class OpCode {  public:      enum class Id {          KIL, +        BRA,          LD_A,          ST_A,          TEX, @@ -470,6 +484,7 @@ private:          std::vector<Matcher> table = {  #define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name)              INST("111000110011----", Id::KIL, Type::Flow, "KIL"), +            INST("111000100100----", Id::BRA, Type::Flow, "BRA"),              INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),              INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"),              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:          return *subroutines.insert(std::move(subroutine)).first;      } +    /// Merges exit method of two parallel branches. +    static ExitMethod ParallelExit(ExitMethod a, ExitMethod b) { +        if (a == ExitMethod::Undetermined) { +            return b; +        } +        if (b == ExitMethod::Undetermined) { +            return a; +        } +        if (a == b) { +            return a; +        } +        return ExitMethod::Conditional; +    } +      /// Scans a range of code for labels and determines the exit method.      ExitMethod Scan(u32 begin, u32 end, std::set<u32>& labels) {          auto [iter, inserted] = @@ -97,11 +111,19 @@ private:              return exit_method;          for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) { -            if (const auto opcode = OpCode::Decode({program_code[offset]})) { +            const Instruction instr = {program_code[offset]}; +            if (const auto opcode = OpCode::Decode(instr)) {                  switch (opcode->GetId()) {                  case OpCode::Id::EXIT: {                      return exit_method = ExitMethod::AlwaysEnd;                  } +                case OpCode::Id::BRA: { +                    u32 target = offset + instr.bra.GetBranchTarget(); +                    labels.insert(target); +                    ExitMethod no_jmp = Scan(offset + 1, end, labels); +                    ExitMethod jmp = Scan(target, end, labels); +                    return exit_method = ParallelExit(no_jmp, jmp); +                }                  }              }          } @@ -1081,6 +1103,13 @@ private:                  shader.AddLine("discard;");                  break;              } +            case OpCode::Id::BRA: { +                ASSERT_MSG(instr.bra.constant_buffer == 0, +                           "BRA with constant buffers are not implemented"); +                u32 target = offset + instr.bra.GetBranchTarget(); +                shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); +                break; +            }              case OpCode::Id::IPA: {                  const auto& attribute = instr.attribute.fmt28;                  regs.SetRegisterToInputAttibute(instr.gpr0, attribute.element, attribute.index); | 
