diff options
Diffstat (limited to 'src/video_core')
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 47 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 107 | 
2 files changed, 133 insertions, 21 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 88b4d0bac..7e1de0fa1 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -240,6 +240,41 @@ enum class FlowCondition : u64 {      Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?  }; +enum class ControlCode : u64 { +    F = 0, +    LT = 1, +    EQ = 2, +    LE = 3, +    GT = 4, +    NE = 5, +    GE = 6, +    Num = 7, +    Nan = 8, +    LTU = 9, +    EQU = 10, +    LEU = 11, +    GTU = 12, +    NEU = 13, +    GEU = 14, +    // +    OFF = 16, +    LO = 17, +    SFF = 18, +    LS = 19, +    HI = 20, +    SFT = 21, +    HS = 22, +    OFT = 23, +    CSM_TA = 24, +    CSM_TR = 25, +    CSM_MX = 26, +    FCSM_TA = 27, +    FCSM_TR = 28, +    FCSM_MX = 29, +    RLE = 30, +    RGT = 31, +}; +  enum class PredicateResultMode : u64 {      None = 0x0,      NotZero = 0x3, @@ -555,6 +590,15 @@ union Instruction {      } pset;      union { +        BitField<0, 3, u64> pred0; +        BitField<3, 3, u64> pred3; +        BitField<8, 5, ControlCode> cc; // flag in cc +        BitField<39, 3, u64> pred39; +        BitField<42, 1, u64> neg_pred39; +        BitField<45, 4, PredOperation> op; // op with pred39 +    } csetp; + +    union {          BitField<39, 3, u64> pred39;          BitField<42, 1, u64> neg_pred;          BitField<43, 1, u64> neg_a; @@ -881,6 +925,7 @@ union Instruction {          BitField<36, 5, u64> index;      } cbuf36; +    BitField<47, 1, u64> generates_cc;      BitField<61, 1, u64> is_b_imm;      BitField<60, 1, u64> is_b_gpr;      BitField<59, 1, u64> is_c_gpr; @@ -1005,6 +1050,7 @@ public:          ISET_IMM,          PSETP,          PSET, +        CSETP,          XMAD_IMM,          XMAD_CR,          XMAD_RC, @@ -1241,6 +1287,7 @@ private:              INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"),              INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"),              INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), +            INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"),              INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),              INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),              INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"), diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index cca6cc6ff..393ab5eab 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -236,6 +236,14 @@ private:      const std::string& suffix;  }; +enum class InternalFlag : u64 { +    ZeroFlag = 0, +    CarryFlag = 1, +    OverflowFlag = 2, +    NaNFlag = 3, +    Amount +}; +  /**   * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state   * of all registers (e.g. whether they are currently being used as Floats or Integers), and @@ -329,13 +337,19 @@ public:      void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem,                                const std::string& value, u64 dest_num_components,                                u64 value_num_components, bool is_saturated = false, -                              u64 dest_elem = 0, Register::Size size = Register::Size::Word) { +                              u64 dest_elem = 0, Register::Size size = Register::Size::Word, +                              bool sets_cc = false) {          ASSERT_MSG(!is_saturated, "Unimplemented");          const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"};          SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')',                      dest_num_components, value_num_components, dest_elem); + +        if (sets_cc) { +            const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; +            SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); +        }      }      /** @@ -352,6 +366,26 @@ public:          shader.AddLine(dest + " = " + src + ';');      } +    std::string GetControlCode(const Tegra::Shader::ControlCode cc) const { +        switch (cc) { +        case Tegra::Shader::ControlCode::NEU: +            return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')'; +        default: +            LOG_CRITICAL(HW_GPU, "Unimplemented Control Code {}", static_cast<u32>(cc)); +            UNREACHABLE(); +            return "false"; +        } +    } + +    std::string GetInternalFlag(const InternalFlag ii) const { +        const u32 code = static_cast<u32>(ii); +        return "internalFlag_" + std::to_string(code) + suffix; +    } + +    void SetInternalFlag(const InternalFlag ii, const std::string& value) const { +        shader.AddLine(GetInternalFlag(ii) + " = " + value + ';'); +    } +      /**       * Writes code that does a output attribute assignment to register operation. Output attributes       * are stored as floats, so this may require conversion. @@ -415,6 +449,12 @@ public:          }          declarations.AddNewLine(); +        for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) { +            const InternalFlag code = static_cast<InternalFlag>(ii); +            declarations.AddLine("bool " + GetInternalFlag(code) + " = false;"); +        } +        declarations.AddNewLine(); +          for (const auto element : declr_input_attribute) {              // TODO(bunnei): Use proper number of elements for these              u32 idx = @@ -1620,7 +1660,8 @@ private:                  }                  regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, -                                          1, instr.alu.saturate_d, 0, instr.conversion.dest_size); +                                          1, instr.alu.saturate_d, 0, instr.conversion.dest_size, +                                          instr.generates_cc.Value() != 0);                  break;              }              case OpCode::Id::I2F_R: @@ -2277,31 +2318,55 @@ private:              break;          }          case OpCode::Type::PredicateSetPredicate: { -            const std::string op_a = -                GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); -            const std::string op_b = -                GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0); +            switch (opcode->GetId()) { +            case OpCode::Id::PSETP: { +                const std::string op_a = +                    GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); +                const std::string op_b = +                    GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0); -            // We can't use the constant predicate as destination. -            ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); +                // We can't use the constant predicate as destination. +                ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); -            const std::string second_pred = -                GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0); +                const std::string second_pred = +                    GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0); -            const std::string combiner = GetPredicateCombiner(instr.psetp.op); +                const std::string combiner = GetPredicateCombiner(instr.psetp.op); -            const std::string predicate = -                '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')'; +                const std::string predicate = +                    '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')'; -            // Set the primary predicate to the result of Predicate OP SecondPredicate -            SetPredicate(instr.psetp.pred3, -                         '(' + predicate + ") " + combiner + " (" + second_pred + ')'); +                // Set the primary predicate to the result of Predicate OP SecondPredicate +                SetPredicate(instr.psetp.pred3, +                             '(' + predicate + ") " + combiner + " (" + second_pred + ')'); -            if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { -                // Set the secondary predicate to the result of !Predicate OP SecondPredicate, -                // if enabled -                SetPredicate(instr.psetp.pred0, -                             "!(" + predicate + ") " + combiner + " (" + second_pred + ')'); +                if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { +                    // Set the secondary predicate to the result of !Predicate OP SecondPredicate, +                    // if enabled +                    SetPredicate(instr.psetp.pred0, +                                 "!(" + predicate + ") " + combiner + " (" + second_pred + ')'); +                } +                break; +            } +            case OpCode::Id::CSETP: { +                const std::string pred = +                    GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0); +                const std::string combiner = GetPredicateCombiner(instr.csetp.op); +                const std::string controlCode = regs.GetControlCode(instr.csetp.cc); +                if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) { +                    SetPredicate(instr.csetp.pred3, +                                 '(' + controlCode + ") " + combiner + " (" + pred + ')'); +                } +                if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { +                    SetPredicate(instr.csetp.pred0, +                                 "!(" + controlCode + ") " + combiner + " (" + pred + ')'); +                } +                break; +            } +            default: { +                LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}", opcode->GetName()); +                UNREACHABLE(); +            }              }              break;          }  | 
