diff options
| author | 2018-12-17 18:09:40 -0300 | |
|---|---|---|
| committer | 2019-01-15 17:54:51 -0300 | |
| commit | b0e79208385ca3183fd1abdd4c6628268840e9ef (patch) | |
| tree | b7bc86e90a0c5fd356c8e435f7911c0fc228e242 | |
| parent | shader_decode: Implement PBK and BRK (diff) | |
| download | yuzu-b0e79208385ca3183fd1abdd4c6628268840e9ef.tar.gz yuzu-b0e79208385ca3183fd1abdd4c6628268840e9ef.tar.xz yuzu-b0e79208385ca3183fd1abdd4c6628268840e9ef.zip | |
shader_decode: Implement XMAD
| -rw-r--r-- | src/video_core/shader/decode/xmad.cpp | 86 |
1 files changed, 85 insertions, 1 deletions
diff --git a/src/video_core/shader/decode/xmad.cpp b/src/video_core/shader/decode/xmad.cpp index 27a2fc05d..fcab1fb80 100644 --- a/src/video_core/shader/decode/xmad.cpp +++ b/src/video_core/shader/decode/xmad.cpp | |||
| @@ -16,7 +16,91 @@ u32 ShaderIR::DecodeXmad(BasicBlock& bb, u32 pc) { | |||
| 16 | const Instruction instr = {program_code[pc]}; | 16 | const Instruction instr = {program_code[pc]}; |
| 17 | const auto opcode = OpCode::Decode(instr); | 17 | const auto opcode = OpCode::Decode(instr); |
| 18 | 18 | ||
| 19 | UNIMPLEMENTED(); | 19 | UNIMPLEMENTED_IF(instr.xmad.sign_a); |
| 20 | UNIMPLEMENTED_IF(instr.xmad.sign_b); | ||
| 21 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | ||
| 22 | "Condition codes generation in XMAD is not implemented"); | ||
| 23 | |||
| 24 | Node op_a = GetRegister(instr.gpr8); // instr.xmad.sign_a | ||
| 25 | |||
| 26 | // TODO(bunnei): Needs to be fixed once op_a or op_b is signed | ||
| 27 | UNIMPLEMENTED_IF(instr.xmad.sign_a != instr.xmad.sign_b); | ||
| 28 | const bool is_signed_a = instr.xmad.sign_a == 1; | ||
| 29 | const bool is_signed_b = instr.xmad.sign_b == 1; | ||
| 30 | const bool is_signed_c = is_signed_a; | ||
| 31 | |||
| 32 | auto [is_merge, op_b, op_c] = [&]() -> std::tuple<bool, Node, Node> { | ||
| 33 | switch (opcode->get().GetId()) { | ||
| 34 | case OpCode::Id::XMAD_CR: | ||
| 35 | return {instr.xmad.merge_56, GetConstBuffer(instr.cbuf34.index, instr.cbuf34.offset), | ||
| 36 | GetRegister(instr.gpr39)}; | ||
| 37 | case OpCode::Id::XMAD_RR: | ||
| 38 | return {instr.xmad.merge_37, GetRegister(instr.gpr20), GetRegister(instr.gpr39)}; | ||
| 39 | case OpCode::Id::XMAD_RC: | ||
| 40 | return {false, GetRegister(instr.gpr39), | ||
| 41 | GetConstBuffer(instr.cbuf34.index, instr.cbuf34.offset)}; | ||
| 42 | case OpCode::Id::XMAD_IMM: | ||
| 43 | return {instr.xmad.merge_37, Immediate(static_cast<u32>(instr.xmad.imm20_16)), | ||
| 44 | GetRegister(instr.gpr39)}; | ||
| 45 | default: | ||
| 46 | UNIMPLEMENTED_MSG("Unhandled XMAD instruction: {}", opcode->get().GetName()); | ||
| 47 | } | ||
| 48 | }(); | ||
| 49 | |||
| 50 | if (instr.xmad.high_a) { | ||
| 51 | op_a = SignedOperation(OperationCode::ILogicalShiftRight, is_signed_a, NO_PRECISE, op_a, | ||
| 52 | Immediate(16)); | ||
| 53 | } else { | ||
| 54 | op_a = SignedOperation(OperationCode::IBitwiseAnd, is_signed_a, NO_PRECISE, op_a, | ||
| 55 | Immediate(0xffff)); | ||
| 56 | } | ||
| 57 | |||
| 58 | const Node original_b = op_b; | ||
| 59 | if (instr.xmad.high_b) { | ||
| 60 | op_b = SignedOperation(OperationCode::ILogicalShiftRight, is_signed_b, NO_PRECISE, op_a, | ||
| 61 | Immediate(16)); | ||
| 62 | } else { | ||
| 63 | op_b = SignedOperation(OperationCode::IBitwiseAnd, is_signed_b, NO_PRECISE, op_b, | ||
| 64 | Immediate(0xffff)); | ||
| 65 | } | ||
| 66 | |||
| 67 | // TODO(Rodrigo): Use an appropiate sign for this operation | ||
| 68 | Node product = Operation(OperationCode::IMul, NO_PRECISE, op_a, op_b); | ||
| 69 | if (instr.xmad.product_shift_left) { | ||
| 70 | product = Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, op_a, Immediate(16)); | ||
| 71 | } | ||
| 72 | |||
| 73 | op_c = [&]() { | ||
| 74 | switch (instr.xmad.mode) { | ||
| 75 | case Tegra::Shader::XmadMode::None: | ||
| 76 | return op_c; | ||
| 77 | case Tegra::Shader::XmadMode::CLo: | ||
| 78 | return SignedOperation(OperationCode::IBitwiseAnd, is_signed_c, NO_PRECISE, op_c, | ||
| 79 | Immediate(0xffff)); | ||
| 80 | case Tegra::Shader::XmadMode::CHi: | ||
| 81 | return SignedOperation(OperationCode::ILogicalShiftRight, is_signed_c, NO_PRECISE, op_c, | ||
| 82 | Immediate(16)); | ||
| 83 | case Tegra::Shader::XmadMode::CBcc: { | ||
| 84 | const Node shifted_b = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_b, | ||
| 85 | NO_PRECISE, original_b, Immediate(16)); | ||
| 86 | return SignedOperation(OperationCode::IAdd, is_signed_c, NO_PRECISE, op_c, shifted_b); | ||
| 87 | } | ||
| 88 | default: { | ||
| 89 | UNIMPLEMENTED_MSG("Unhandled XMAD mode: {}", static_cast<u32>(instr.xmad.mode.Value())); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | }(); | ||
| 93 | |||
| 94 | // TODO(Rodrigo): Use an appropiate sign for this operation | ||
| 95 | Node sum = Operation(OperationCode::IAdd, product, op_c); | ||
| 96 | if (is_merge) { | ||
| 97 | const Node a = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, sum, Immediate(0xffff)); | ||
| 98 | const Node b = | ||
| 99 | Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, original_b, Immediate(0xffff)); | ||
| 100 | sum = Operation(OperationCode::IBitwiseOr, NO_PRECISE, a, b); | ||
| 101 | } | ||
| 102 | |||
| 103 | SetRegister(bb, instr.gpr0, sum); | ||
| 20 | 104 | ||
| 21 | return pc; | 105 | return pc; |
| 22 | } | 106 | } |