diff options
| author | Subv <subv2112@gmail.com> | 2018-04-20 09:09:50 -0500 | 
|---|---|---|
| committer | Subv <subv2112@gmail.com> | 2018-04-20 21:09:33 -0500 | 
| commit | 0a5e01b710b66b9264ceb469903e8b8f16faf516 (patch) | |
| tree | 27aafd787e4ab96dc9a4498016d94da9da03aa2e | |
| parent | d03fc774756306aa8fd89abd5522c928b46336c7 (diff) | |
ShaderGen: Implemented the fsetp instruction.
Predicate variables are now added to the generated shader code in the form of 'pX' where X is the predicate id.
These predicate variables are initialized to false on shader startup and are set via the fsetp instructions.
TODO:
* Not all the comparison types are implemented.
* Only the single-predicate version is implemented.
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 43 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 72 | 
2 files changed, 112 insertions, 3 deletions
| diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index b0da805db..fb639a417 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -109,6 +109,8 @@ union OpCode {          FSETP_R = 0x5BB,          FSETP_C = 0x4BB, +        FSETP_IMM = 0x36B, +        FSETP_NEG_IMM = 0x37B,          EXIT = 0xE30,          KIL = 0xE33, @@ -124,6 +126,7 @@ union OpCode {          Ffma,          Flow,          Memory, +        FloatPredicate,          Unknown,      }; @@ -164,6 +167,9 @@ union OpCode {          case Id::FSETP_C:          case Id::KIL:              return op4; +        case Id::FSETP_IMM: +        case Id::FSETP_NEG_IMM: +            return Id::FSETP_IMM;          }          switch (op5) { @@ -241,8 +247,9 @@ union OpCode {          info_table[Id::FMUL_C] = {Type::Arithmetic, "fmul_c"};          info_table[Id::FMUL_IMM] = {Type::Arithmetic, "fmul_imm"};          info_table[Id::FMUL32_IMM] = {Type::Arithmetic, "fmul32_imm"}; -        info_table[Id::FSETP_C] = {Type::Arithmetic, "fsetp_c"}; -        info_table[Id::FSETP_R] = {Type::Arithmetic, "fsetp_r"}; +        info_table[Id::FSETP_C] = {Type::FloatPredicate, "fsetp_c"}; +        info_table[Id::FSETP_R] = {Type::FloatPredicate, "fsetp_r"}; +        info_table[Id::FSETP_IMM] = {Type::FloatPredicate, "fsetp_imm"};          info_table[Id::EXIT] = {Type::Trivial, "exit"};          info_table[Id::IPA] = {Type::Trivial, "ipa"};          info_table[Id::KIL] = {Type::Flow, "kil"}; @@ -286,7 +293,23 @@ namespace Shader {  enum class Pred : u64 {      UnusedIndex = 0x7, -    NeverExecute = 0xf, +    NeverExecute = 0xF, +}; + +enum class PredCondition : u64 { +    LessThan = 1, +    Equal = 2, +    LessEqual = 3, +    GreaterThan = 4, +    NotEqual = 5, +    GreaterEqual = 6, +    // TODO(Subv): Other condition types +}; + +enum class PredOperation : u64 { +    And = 0, +    Or = 1, +    Xor = 2,  };  enum class SubOp : u64 { @@ -346,6 +369,20 @@ union Instruction {          BitField<49, 1, u64> negate_c;      } ffma; +    union { +        BitField<0, 3, u64> pred0; +        BitField<3, 3, u64> pred3; +        BitField<7, 1, u64> abs_a; +        BitField<39, 3, u64> pred39; +        BitField<42, 1, u64> neg_pred; +        BitField<43, 1, u64> neg_a; +        BitField<44, 1, u64> abs_b; +        BitField<45, 2, PredOperation> op; +        BitField<47, 1, u64> ftz; +        BitField<48, 4, PredCondition> cond; +        BitField<56, 1, u64> neg_b; +    } fsetp; +      BitField<61, 1, u64> is_b_imm;      BitField<60, 1, u64> is_b_gpr;      BitField<59, 1, u64> is_c_gpr; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 6db0b7d39..2e0203a68 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -279,6 +279,21 @@ private:      }      /* +     * Writes code that assigns a predicate boolean variable. +     * @param pred The id of the predicate to write to. +     * @param value The expression value to assign to the predicate. +     */ +    void SetPredicate(u64 pred, const std::string& value) { +        using Tegra::Shader::Pred; +        // Can't assign to the constant predicate. +        ASSERT(pred != static_cast<u64>(Pred::UnusedIndex)); + +        std::string variable = 'p' + std::to_string(pred); +        shader.AddLine(variable + " = " + value + ';'); +        declr_predicates.insert(std::move(variable)); +    } + +    /*       * Returns whether the instruction at the specified offset is a 'sched' instruction.       * Sched instructions always appear before a sequence of 3 instructions.       */ @@ -468,7 +483,57 @@ private:              }              break;          } +        case OpCode::Type::FloatPredicate: { +            std::string op_a = instr.fsetp.neg_a ? "-" : ""; +            op_a += GetRegister(instr.gpr8); + +            if (instr.fsetp.abs_a) { +                op_a = "abs(" + op_a + ')'; +            } + +            std::string op_b{}; + +            if (instr.is_b_imm) { +                if (instr.fsetp.neg_b) { +                    // Only the immediate version of fsetp has a neg_b bit. +                    op_b += '-'; +                } +                op_b += '(' + GetImmediate19(instr) + ')'; +            } else { +                if (instr.is_b_gpr) { +                    op_b += GetRegister(instr.gpr20); +                } else { +                    op_b += GetUniform(instr.uniform); +                } +            } + +            if (instr.fsetp.abs_b) { +                op_b = "abs(" + op_b + ')'; +            } +            using Tegra::Shader::Pred; +            ASSERT_MSG(instr.fsetp.pred0 == static_cast<u64>(Pred::UnusedIndex) && +                           instr.fsetp.pred39 == static_cast<u64>(Pred::UnusedIndex), +                       "Compound predicates are not implemented"); + +            // We can't use the constant predicate as destination. +            ASSERT(instr.fsetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); + +            using Tegra::Shader::PredCondition; +            switch (instr.fsetp.cond) { +            case PredCondition::LessThan: +                SetPredicate(instr.fsetp.pred3, '(' + op_a + ") < (" + op_b + ')'); +                break; +            case PredCondition::Equal: +                SetPredicate(instr.fsetp.pred3, '(' + op_a + ") == (" + op_b + ')'); +                break; +            default: +                NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})", +                               static_cast<unsigned>(instr.fsetp.cond.Value()), op_a, op_b); +                UNREACHABLE(); +            } +            break; +        }          default: {              switch (instr.opcode.EffectiveOpCode()) {              case OpCode::Id::EXIT: { @@ -623,6 +688,12 @@ private:              declarations.AddNewLine();              ++const_buffer_layout;          } + +        declarations.AddNewLine(); +        for (const auto& pred : declr_predicates) { +            declarations.AddLine("bool " + pred + " = false;"); +        } +        declarations.AddNewLine();      }  private: @@ -636,6 +707,7 @@ private:      // Declarations      std::set<std::string> declr_register; +    std::set<std::string> declr_predicates;      std::set<Attribute::Index> declr_input_attribute;      std::set<Attribute::Index> declr_output_attribute;      std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers; | 
