diff options
| author | 2018-12-18 22:18:44 -0300 | |
|---|---|---|
| committer | 2019-01-15 17:54:52 -0300 | |
| commit | a40fd075164a5f86367dfa7bea4d7815148e63b7 (patch) | |
| tree | bd3af6b5cf15e7588f5620027052a700bbd1b5b9 /src | |
| parent | shader_decode: Implement ST_L (diff) | |
| download | yuzu-a40fd075164a5f86367dfa7bea4d7815148e63b7.tar.gz yuzu-a40fd075164a5f86367dfa7bea4d7815148e63b7.tar.xz yuzu-a40fd075164a5f86367dfa7bea4d7815148e63b7.zip | |
shader_decode: Implement LOP3
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/shader/decode/arithmetic_integer.cpp | 60 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 2 |
2 files changed, 62 insertions, 0 deletions
diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp index dbdcebbb4..145bbcfc8 100644 --- a/src/video_core/shader/decode/arithmetic_integer.cpp +++ b/src/video_core/shader/decode/arithmetic_integer.cpp | |||
| @@ -11,6 +11,7 @@ namespace VideoCommon::Shader { | |||
| 11 | 11 | ||
| 12 | using Tegra::Shader::Instruction; | 12 | using Tegra::Shader::Instruction; |
| 13 | using Tegra::Shader::OpCode; | 13 | using Tegra::Shader::OpCode; |
| 14 | using Tegra::Shader::Register; | ||
| 14 | 15 | ||
| 15 | u32 ShaderIR::DecodeArithmeticInteger(BasicBlock& bb, u32 pc) { | 16 | u32 ShaderIR::DecodeArithmeticInteger(BasicBlock& bb, u32 pc) { |
| 16 | const Instruction instr = {program_code[pc]}; | 17 | const Instruction instr = {program_code[pc]}; |
| @@ -79,6 +80,24 @@ u32 ShaderIR::DecodeArithmeticInteger(BasicBlock& bb, u32 pc) { | |||
| 79 | instr.alu.lop.pred_result_mode, instr.alu.lop.pred48); | 80 | instr.alu.lop.pred_result_mode, instr.alu.lop.pred48); |
| 80 | break; | 81 | break; |
| 81 | } | 82 | } |
| 83 | case OpCode::Id::LOP3_C: | ||
| 84 | case OpCode::Id::LOP3_R: | ||
| 85 | case OpCode::Id::LOP3_IMM: { | ||
| 86 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | ||
| 87 | "Condition codes generation in LOP3 is not implemented"); | ||
| 88 | |||
| 89 | const Node op_c = GetRegister(instr.gpr39); | ||
| 90 | const Node lut = [&]() { | ||
| 91 | if (opcode->get().GetId() == OpCode::Id::LOP3_R) { | ||
| 92 | return Immediate(instr.alu.lop3.GetImmLut28()); | ||
| 93 | } else { | ||
| 94 | return Immediate(instr.alu.lop3.GetImmLut48()); | ||
| 95 | } | ||
| 96 | }(); | ||
| 97 | |||
| 98 | WriteLop3Instruction(bb, instr.gpr0, op_a, op_b, op_c, lut); | ||
| 99 | break; | ||
| 100 | } | ||
| 82 | case OpCode::Id::IMNMX_C: | 101 | case OpCode::Id::IMNMX_C: |
| 83 | case OpCode::Id::IMNMX_R: | 102 | case OpCode::Id::IMNMX_R: |
| 84 | case OpCode::Id::IMNMX_IMM: { | 103 | case OpCode::Id::IMNMX_IMM: { |
| @@ -102,4 +121,45 @@ u32 ShaderIR::DecodeArithmeticInteger(BasicBlock& bb, u32 pc) { | |||
| 102 | return pc; | 121 | return pc; |
| 103 | } | 122 | } |
| 104 | 123 | ||
| 124 | void ShaderIR::WriteLop3Instruction(BasicBlock& bb, Register dest, Node op_a, Node op_b, Node op_c, | ||
| 125 | Node imm_lut) { | ||
| 126 | constexpr u32 lop_iterations = 32; | ||
| 127 | const Node one = Immediate(1); | ||
| 128 | const Node two = Immediate(2); | ||
| 129 | |||
| 130 | Node value{}; | ||
| 131 | for (u32 i = 0; i < lop_iterations; ++i) { | ||
| 132 | const Node shift_amount = Immediate(i); | ||
| 133 | |||
| 134 | const Node a = Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, op_c, shift_amount); | ||
| 135 | const Node pack_0 = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, a, one); | ||
| 136 | |||
| 137 | const Node b = Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, op_b, shift_amount); | ||
| 138 | const Node c = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, b, one); | ||
| 139 | const Node pack_1 = Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, c, one); | ||
| 140 | |||
| 141 | const Node d = Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, op_a, shift_amount); | ||
| 142 | const Node e = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, d, one); | ||
| 143 | const Node pack_2 = Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, e, two); | ||
| 144 | |||
| 145 | const Node pack_01 = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, pack_0, pack_1); | ||
| 146 | const Node pack_012 = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, pack_01, pack_2); | ||
| 147 | |||
| 148 | const Node shifted_bit = | ||
| 149 | Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, imm_lut, pack_012); | ||
| 150 | const Node bit = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, shifted_bit, one); | ||
| 151 | |||
| 152 | const Node right = | ||
| 153 | Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, bit, shift_amount); | ||
| 154 | |||
| 155 | if (i > 0) { | ||
| 156 | value = Operation(OperationCode::IBitwiseOr, NO_PRECISE, value, right); | ||
| 157 | } else { | ||
| 158 | value = right; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | SetRegister(bb, dest, value); | ||
| 163 | } | ||
| 164 | |||
| 105 | } // namespace VideoCommon::Shader \ No newline at end of file | 165 | } // namespace VideoCommon::Shader \ No newline at end of file |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index b67fd6531..b91ef246f 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -701,6 +701,8 @@ private: | |||
| 701 | Tegra::Shader::LogicOperation logic_op, Node op_a, Node op_b, | 701 | Tegra::Shader::LogicOperation logic_op, Node op_a, Node op_b, |
| 702 | Tegra::Shader::PredicateResultMode predicate_mode, | 702 | Tegra::Shader::PredicateResultMode predicate_mode, |
| 703 | Tegra::Shader::Pred predicate); | 703 | Tegra::Shader::Pred predicate); |
| 704 | void WriteLop3Instruction(BasicBlock& bb, Tegra::Shader::Register dest, Node op_a, Node op_b, | ||
| 705 | Node op_c, Node imm_lut); | ||
| 704 | 706 | ||
| 705 | template <typename... T> | 707 | template <typename... T> |
| 706 | inline Node Operation(OperationCode code, const T*... operands) { | 708 | inline Node Operation(OperationCode code, const T*... operands) { |