diff options
| author | 2021-03-27 19:47:00 -0400 | |
|---|---|---|
| committer | 2021-07-22 21:51:24 -0400 | |
| commit | 51475e21ba5e9a17730a2b5a868dc73d53db9bc1 (patch) | |
| tree | 75b91429b808db9640a248e886fcb6cea1cef8e8 /src | |
| parent | shader: Add missing I2I exception when CC is used (diff) | |
| download | yuzu-51475e21ba5e9a17730a2b5a868dc73d53db9bc1.tar.gz yuzu-51475e21ba5e9a17730a2b5a868dc73d53db9bc1.tar.xz yuzu-51475e21ba5e9a17730a2b5a868dc73d53db9bc1.zip | |
shader: Implement VMAD, VMNMX, VSETP
Diffstat (limited to '')
9 files changed, 319 insertions, 23 deletions
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 7f8dc8eed..55b846c84 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -127,6 +127,11 @@ add_library(shader_recompiler STATIC | |||
| 127 | frontend/maxwell/translate/impl/texture_gather_swizzled.cpp | 127 | frontend/maxwell/translate/impl/texture_gather_swizzled.cpp |
| 128 | frontend/maxwell/translate/impl/texture_gather.cpp | 128 | frontend/maxwell/translate/impl/texture_gather.cpp |
| 129 | frontend/maxwell/translate/impl/texture_query.cpp | 129 | frontend/maxwell/translate/impl/texture_query.cpp |
| 130 | frontend/maxwell/translate/impl/video_helper.cpp | ||
| 131 | frontend/maxwell/translate/impl/video_helper.h | ||
| 132 | frontend/maxwell/translate/impl/video_minimum_maximum.cpp | ||
| 133 | frontend/maxwell/translate/impl/video_multiply_add.cpp | ||
| 134 | frontend/maxwell/translate/impl/video_set_predicate.cpp | ||
| 130 | frontend/maxwell/translate/impl/vote.cpp | 135 | frontend/maxwell/translate/impl/vote.cpp |
| 131 | frontend/maxwell/translate/impl/warp_shuffle.cpp | 136 | frontend/maxwell/translate/impl/warp_shuffle.cpp |
| 132 | frontend/maxwell/translate/translate.cpp | 137 | frontend/maxwell/translate/translate.cpp |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index 82613f607..6d41442ee 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -1121,6 +1121,10 @@ U32 IREmitter::UMin(const U32& a, const U32& b) { | |||
| 1121 | return Inst<U32>(Opcode::UMin32, a, b); | 1121 | return Inst<U32>(Opcode::UMin32, a, b); |
| 1122 | } | 1122 | } |
| 1123 | 1123 | ||
| 1124 | U32 IREmitter::IMin(const U32& a, const U32& b, bool is_signed) { | ||
| 1125 | return is_signed ? SMin(a, b) : UMin(a, b); | ||
| 1126 | } | ||
| 1127 | |||
| 1124 | U32 IREmitter::SMax(const U32& a, const U32& b) { | 1128 | U32 IREmitter::SMax(const U32& a, const U32& b) { |
| 1125 | return Inst<U32>(Opcode::SMax32, a, b); | 1129 | return Inst<U32>(Opcode::SMax32, a, b); |
| 1126 | } | 1130 | } |
| @@ -1129,6 +1133,10 @@ U32 IREmitter::UMax(const U32& a, const U32& b) { | |||
| 1129 | return Inst<U32>(Opcode::UMax32, a, b); | 1133 | return Inst<U32>(Opcode::UMax32, a, b); |
| 1130 | } | 1134 | } |
| 1131 | 1135 | ||
| 1136 | U32 IREmitter::IMax(const U32& a, const U32& b, bool is_signed) { | ||
| 1137 | return is_signed ? SMax(a, b) : UMax(a, b); | ||
| 1138 | } | ||
| 1139 | |||
| 1132 | U1 IREmitter::ILessThan(const U32& lhs, const U32& rhs, bool is_signed) { | 1140 | U1 IREmitter::ILessThan(const U32& lhs, const U32& rhs, bool is_signed) { |
| 1133 | return Inst<U1>(is_signed ? Opcode::SLessThan : Opcode::ULessThan, lhs, rhs); | 1141 | return Inst<U1>(is_signed ? Opcode::SLessThan : Opcode::ULessThan, lhs, rhs); |
| 1134 | } | 1142 | } |
| @@ -1267,11 +1275,7 @@ U32U64 IREmitter::ConvertFToU(size_t bitsize, const F16F32F64& value) { | |||
| 1267 | } | 1275 | } |
| 1268 | 1276 | ||
| 1269 | U32U64 IREmitter::ConvertFToI(size_t bitsize, bool is_signed, const F16F32F64& value) { | 1277 | U32U64 IREmitter::ConvertFToI(size_t bitsize, bool is_signed, const F16F32F64& value) { |
| 1270 | if (is_signed) { | 1278 | return is_signed ? ConvertFToS(bitsize, value) : ConvertFToU(bitsize, value); |
| 1271 | return ConvertFToS(bitsize, value); | ||
| 1272 | } else { | ||
| 1273 | return ConvertFToU(bitsize, value); | ||
| 1274 | } | ||
| 1275 | } | 1279 | } |
| 1276 | 1280 | ||
| 1277 | F16F32F64 IREmitter::ConvertSToF(size_t dest_bitsize, size_t src_bitsize, const Value& value) { | 1281 | F16F32F64 IREmitter::ConvertSToF(size_t dest_bitsize, size_t src_bitsize, const Value& value) { |
| @@ -1360,11 +1364,8 @@ F16F32F64 IREmitter::ConvertUToF(size_t dest_bitsize, size_t src_bitsize, const | |||
| 1360 | 1364 | ||
| 1361 | F16F32F64 IREmitter::ConvertIToF(size_t dest_bitsize, size_t src_bitsize, bool is_signed, | 1365 | F16F32F64 IREmitter::ConvertIToF(size_t dest_bitsize, size_t src_bitsize, bool is_signed, |
| 1362 | const Value& value) { | 1366 | const Value& value) { |
| 1363 | if (is_signed) { | 1367 | return is_signed ? ConvertSToF(dest_bitsize, src_bitsize, value) |
| 1364 | return ConvertSToF(dest_bitsize, src_bitsize, value); | 1368 | : ConvertUToF(dest_bitsize, src_bitsize, value); |
| 1365 | } else { | ||
| 1366 | return ConvertUToF(dest_bitsize, src_bitsize, value); | ||
| 1367 | } | ||
| 1368 | } | 1369 | } |
| 1369 | 1370 | ||
| 1370 | U32U64 IREmitter::UConvert(size_t result_bitsize, const U32U64& value) { | 1371 | U32U64 IREmitter::UConvert(size_t result_bitsize, const U32U64& value) { |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 771c186d4..8d50aa607 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -196,8 +196,10 @@ public: | |||
| 196 | [[nodiscard]] U32 FindUMsb(const U32& value); | 196 | [[nodiscard]] U32 FindUMsb(const U32& value); |
| 197 | [[nodiscard]] U32 SMin(const U32& a, const U32& b); | 197 | [[nodiscard]] U32 SMin(const U32& a, const U32& b); |
| 198 | [[nodiscard]] U32 UMin(const U32& a, const U32& b); | 198 | [[nodiscard]] U32 UMin(const U32& a, const U32& b); |
| 199 | [[nodiscard]] U32 IMin(const U32& a, const U32& b, bool is_signed); | ||
| 199 | [[nodiscard]] U32 SMax(const U32& a, const U32& b); | 200 | [[nodiscard]] U32 SMax(const U32& a, const U32& b); |
| 200 | [[nodiscard]] U32 UMax(const U32& a, const U32& b); | 201 | [[nodiscard]] U32 UMax(const U32& a, const U32& b); |
| 202 | [[nodiscard]] U32 IMax(const U32& a, const U32& b, bool is_signed); | ||
| 201 | 203 | ||
| 202 | [[nodiscard]] U1 ILessThan(const U32& lhs, const U32& rhs, bool is_signed); | 204 | [[nodiscard]] U1 ILessThan(const U32& lhs, const U32& rhs, bool is_signed); |
| 203 | [[nodiscard]] U1 IEqual(const U32U64& lhs, const U32U64& rhs); | 205 | [[nodiscard]] U1 IEqual(const U32U64& lhs, const U32U64& rhs); |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp index 96ee2e741..409216640 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp | |||
| @@ -385,14 +385,6 @@ void TranslatorVisitor::VADD(u64) { | |||
| 385 | ThrowNotImplemented(Opcode::VADD); | 385 | ThrowNotImplemented(Opcode::VADD); |
| 386 | } | 386 | } |
| 387 | 387 | ||
| 388 | void TranslatorVisitor::VMAD(u64) { | ||
| 389 | ThrowNotImplemented(Opcode::VMAD); | ||
| 390 | } | ||
| 391 | |||
| 392 | void TranslatorVisitor::VMNMX(u64) { | ||
| 393 | ThrowNotImplemented(Opcode::VMNMX); | ||
| 394 | } | ||
| 395 | |||
| 396 | void TranslatorVisitor::VOTE_vtg(u64) { | 388 | void TranslatorVisitor::VOTE_vtg(u64) { |
| 397 | ThrowNotImplemented(Opcode::VOTE_vtg); | 389 | ThrowNotImplemented(Opcode::VOTE_vtg); |
| 398 | } | 390 | } |
| @@ -400,11 +392,6 @@ void TranslatorVisitor::VOTE_vtg(u64) { | |||
| 400 | void TranslatorVisitor::VSET(u64) { | 392 | void TranslatorVisitor::VSET(u64) { |
| 401 | ThrowNotImplemented(Opcode::VSET); | 393 | ThrowNotImplemented(Opcode::VSET); |
| 402 | } | 394 | } |
| 403 | |||
| 404 | void TranslatorVisitor::VSETP(u64) { | ||
| 405 | ThrowNotImplemented(Opcode::VSETP); | ||
| 406 | } | ||
| 407 | |||
| 408 | void TranslatorVisitor::VSHL(u64) { | 395 | void TranslatorVisitor::VSHL(u64) { |
| 409 | ThrowNotImplemented(Opcode::VSHL); | 396 | ThrowNotImplemented(Opcode::VSHL); |
| 410 | } | 397 | } |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/video_helper.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/video_helper.cpp new file mode 100644 index 000000000..e1f4174cf --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/video_helper.cpp | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "shader_recompiler/exception.h" | ||
| 6 | #include "shader_recompiler/frontend/maxwell/translate/impl/video_helper.h" | ||
| 7 | |||
| 8 | namespace Shader::Maxwell { | ||
| 9 | |||
| 10 | IR::U32 ExtractVideoOperandValue(IR::IREmitter& ir, const IR::U32& value, VideoWidth width, | ||
| 11 | u32 selector, bool is_signed) { | ||
| 12 | switch (width) { | ||
| 13 | case VideoWidth::Byte: | ||
| 14 | case VideoWidth::Unknown: | ||
| 15 | return ir.BitFieldExtract(value, ir.Imm32(selector * 8), ir.Imm32(8), is_signed); | ||
| 16 | case VideoWidth::Short: | ||
| 17 | return ir.BitFieldExtract(value, ir.Imm32(selector * 16), ir.Imm32(16), is_signed); | ||
| 18 | case VideoWidth::Word: | ||
| 19 | return value; | ||
| 20 | default: | ||
| 21 | throw NotImplementedException("Unknown VideoWidth {}", width); | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | VideoWidth GetVideoSourceWidth(VideoWidth width, bool is_immediate) { | ||
| 26 | // immediates must be 16-bit format. | ||
| 27 | return is_immediate ? VideoWidth::Short : width; | ||
| 28 | } | ||
| 29 | |||
| 30 | } // namespace Shader::Maxwell | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/video_helper.h b/src/shader_recompiler/frontend/maxwell/translate/impl/video_helper.h new file mode 100644 index 000000000..40c0b907c --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/video_helper.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 9 | |||
| 10 | namespace Shader::Maxwell { | ||
| 11 | enum class VideoWidth : u64 { | ||
| 12 | Byte, | ||
| 13 | Unknown, | ||
| 14 | Short, | ||
| 15 | Word, | ||
| 16 | }; | ||
| 17 | |||
| 18 | [[nodiscard]] IR::U32 ExtractVideoOperandValue(IR::IREmitter& ir, const IR::U32& value, | ||
| 19 | VideoWidth width, u32 selector, bool is_signed); | ||
| 20 | |||
| 21 | [[nodiscard]] VideoWidth GetVideoSourceWidth(VideoWidth width, bool is_immediate); | ||
| 22 | |||
| 23 | } // namespace Shader::Maxwell | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/video_minimum_maximum.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/video_minimum_maximum.cpp new file mode 100644 index 000000000..78869601f --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/video_minimum_maximum.cpp | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/common_types.h" | ||
| 6 | #include "shader_recompiler/exception.h" | ||
| 7 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 8 | #include "shader_recompiler/frontend/maxwell/translate/impl/video_helper.h" | ||
| 9 | |||
| 10 | namespace Shader::Maxwell { | ||
| 11 | namespace { | ||
| 12 | enum class VideoMinMaxOps : u64 { | ||
| 13 | MRG_16H, | ||
| 14 | MRG_16L, | ||
| 15 | MRG_8B0, | ||
| 16 | MRG_8B2, | ||
| 17 | ACC, | ||
| 18 | MIN, | ||
| 19 | MAX, | ||
| 20 | }; | ||
| 21 | |||
| 22 | [[nodiscard]] IR::U32 ApplyVideoMinMaxOp(IR::IREmitter& ir, const IR::U32& lhs, const IR::U32& rhs, | ||
| 23 | VideoMinMaxOps op, bool is_signed) { | ||
| 24 | switch (op) { | ||
| 25 | case VideoMinMaxOps::MIN: | ||
| 26 | return ir.IMin(lhs, rhs, is_signed); | ||
| 27 | case VideoMinMaxOps::MAX: | ||
| 28 | return ir.IMax(lhs, rhs, is_signed); | ||
| 29 | default: | ||
| 30 | throw NotImplementedException("VMNMX op {}", op); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | } // Anonymous namespace | ||
| 34 | |||
| 35 | void TranslatorVisitor::VMNMX(u64 insn) { | ||
| 36 | union { | ||
| 37 | u64 raw; | ||
| 38 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 39 | BitField<20, 16, u64> src_b_imm; | ||
| 40 | BitField<28, 2, u64> src_b_selector; | ||
| 41 | BitField<29, 2, VideoWidth> src_b_width; | ||
| 42 | BitField<36, 2, u64> src_a_selector; | ||
| 43 | BitField<37, 2, VideoWidth> src_a_width; | ||
| 44 | BitField<47, 1, u64> cc; | ||
| 45 | BitField<48, 1, u64> src_a_sign; | ||
| 46 | BitField<49, 1, u64> src_b_sign; | ||
| 47 | BitField<50, 1, u64> is_src_b_reg; | ||
| 48 | BitField<51, 3, VideoMinMaxOps> op; | ||
| 49 | BitField<54, 1, u64> dest_sign; | ||
| 50 | BitField<55, 1, u64> sat; | ||
| 51 | BitField<56, 1, u64> mx; | ||
| 52 | } const vmnmx{insn}; | ||
| 53 | |||
| 54 | if (vmnmx.cc != 0) { | ||
| 55 | throw NotImplementedException("VMNMX CC"); | ||
| 56 | } | ||
| 57 | if (vmnmx.sat != 0) { | ||
| 58 | throw NotImplementedException("VMNMX SAT"); | ||
| 59 | } | ||
| 60 | // Selectors were shown to default to 2 in unit tests | ||
| 61 | if (vmnmx.src_a_selector != 2) { | ||
| 62 | throw NotImplementedException("VMNMX Selector {}", vmnmx.src_a_selector.Value()); | ||
| 63 | } | ||
| 64 | if (vmnmx.src_b_selector != 2) { | ||
| 65 | throw NotImplementedException("VMNMX Selector {}", vmnmx.src_b_selector.Value()); | ||
| 66 | } | ||
| 67 | if (vmnmx.src_a_width != VideoWidth::Word) { | ||
| 68 | throw NotImplementedException("VMNMX Source Width {}", vmnmx.src_a_width.Value()); | ||
| 69 | } | ||
| 70 | |||
| 71 | const bool is_b_imm{vmnmx.is_src_b_reg == 0}; | ||
| 72 | const IR::U32 src_a{GetReg8(insn)}; | ||
| 73 | const IR::U32 src_b{is_b_imm ? ir.Imm32(static_cast<u32>(vmnmx.src_b_imm)) : GetReg20(insn)}; | ||
| 74 | const IR::U32 src_c{GetReg39(insn)}; | ||
| 75 | |||
| 76 | const VideoWidth a_width{vmnmx.src_a_width}; | ||
| 77 | const VideoWidth b_width{GetVideoSourceWidth(vmnmx.src_b_width, is_b_imm)}; | ||
| 78 | |||
| 79 | const bool src_a_signed{vmnmx.src_a_sign != 0}; | ||
| 80 | const bool src_b_signed{vmnmx.src_b_sign != 0}; | ||
| 81 | const IR::U32 op_a{ExtractVideoOperandValue(ir, src_a, a_width, 0, src_a_signed)}; | ||
| 82 | const IR::U32 op_b{ExtractVideoOperandValue(ir, src_b, b_width, 0, src_b_signed)}; | ||
| 83 | |||
| 84 | // First operation's sign is only dependent on operand b's sign | ||
| 85 | const bool op_1_signed{src_b_signed}; | ||
| 86 | |||
| 87 | const IR::U32 lhs{vmnmx.mx != 0 ? ir.IMax(op_a, op_b, op_1_signed) | ||
| 88 | : ir.IMin(op_a, op_b, op_1_signed)}; | ||
| 89 | X(vmnmx.dest_reg, ApplyVideoMinMaxOp(ir, lhs, src_c, vmnmx.op, vmnmx.dest_sign != 0)); | ||
| 90 | } | ||
| 91 | |||
| 92 | } // namespace Shader::Maxwell | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/video_multiply_add.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/video_multiply_add.cpp new file mode 100644 index 000000000..cc2e6d6e6 --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/video_multiply_add.cpp | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/common_types.h" | ||
| 6 | #include "shader_recompiler/exception.h" | ||
| 7 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 8 | #include "shader_recompiler/frontend/maxwell/translate/impl/video_helper.h" | ||
| 9 | |||
| 10 | namespace Shader::Maxwell { | ||
| 11 | void TranslatorVisitor::VMAD(u64 insn) { | ||
| 12 | union { | ||
| 13 | u64 raw; | ||
| 14 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 15 | BitField<20, 16, u64> src_b_imm; | ||
| 16 | BitField<28, 2, u64> src_b_selector; | ||
| 17 | BitField<29, 2, VideoWidth> src_b_width; | ||
| 18 | BitField<36, 2, u64> src_a_selector; | ||
| 19 | BitField<37, 2, VideoWidth> src_a_width; | ||
| 20 | BitField<47, 1, u64> cc; | ||
| 21 | BitField<48, 1, u64> src_a_sign; | ||
| 22 | BitField<49, 1, u64> src_b_sign; | ||
| 23 | BitField<50, 1, u64> is_src_b_reg; | ||
| 24 | BitField<51, 2, u64> scale; | ||
| 25 | BitField<53, 1, u64> src_c_neg; | ||
| 26 | BitField<54, 1, u64> src_a_neg; | ||
| 27 | BitField<55, 1, u64> sat; | ||
| 28 | } const vmad{insn}; | ||
| 29 | |||
| 30 | if (vmad.cc != 0) { | ||
| 31 | throw NotImplementedException("VMAD CC"); | ||
| 32 | } | ||
| 33 | if (vmad.sat != 0) { | ||
| 34 | throw NotImplementedException("VMAD SAT"); | ||
| 35 | } | ||
| 36 | if (vmad.scale != 0) { | ||
| 37 | throw NotImplementedException("VMAD SCALE"); | ||
| 38 | } | ||
| 39 | if (vmad.src_a_neg != 0 && vmad.src_c_neg != 0) { | ||
| 40 | throw NotImplementedException("VMAD PO"); | ||
| 41 | } | ||
| 42 | if (vmad.src_a_neg != 0 || vmad.src_c_neg != 0) { | ||
| 43 | throw NotImplementedException("VMAD NEG"); | ||
| 44 | } | ||
| 45 | const bool is_b_imm{vmad.is_src_b_reg == 0}; | ||
| 46 | const IR::U32 src_a{GetReg8(insn)}; | ||
| 47 | const IR::U32 src_b{is_b_imm ? ir.Imm32(static_cast<u32>(vmad.src_b_imm)) : GetReg20(insn)}; | ||
| 48 | const IR::U32 src_c{GetReg39(insn)}; | ||
| 49 | |||
| 50 | const u32 a_selector{static_cast<u32>(vmad.src_a_selector)}; | ||
| 51 | // Immediate values can't have a selector | ||
| 52 | const u32 b_selector{is_b_imm ? 0U : static_cast<u32>(vmad.src_b_selector)}; | ||
| 53 | const VideoWidth a_width{vmad.src_a_width}; | ||
| 54 | const VideoWidth b_width{GetVideoSourceWidth(vmad.src_b_width, is_b_imm)}; | ||
| 55 | |||
| 56 | const bool src_a_signed{vmad.src_a_sign != 0}; | ||
| 57 | const bool src_b_signed{vmad.src_b_sign != 0}; | ||
| 58 | const IR::U32 op_a{ExtractVideoOperandValue(ir, src_a, a_width, a_selector, src_a_signed)}; | ||
| 59 | const IR::U32 op_b{ExtractVideoOperandValue(ir, src_b, b_width, b_selector, src_b_signed)}; | ||
| 60 | |||
| 61 | X(vmad.dest_reg, ir.IAdd(ir.IMul(op_a, op_b), src_c)); | ||
| 62 | } | ||
| 63 | |||
| 64 | } // namespace Shader::Maxwell | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/video_set_predicate.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/video_set_predicate.cpp new file mode 100644 index 000000000..af13b3fcc --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/video_set_predicate.cpp | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/common_types.h" | ||
| 6 | #include "shader_recompiler/exception.h" | ||
| 7 | #include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h" | ||
| 8 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 9 | #include "shader_recompiler/frontend/maxwell/translate/impl/video_helper.h" | ||
| 10 | |||
| 11 | namespace Shader::Maxwell { | ||
| 12 | namespace { | ||
| 13 | enum class VsetpCompareOp : u64 { | ||
| 14 | False = 0, | ||
| 15 | LessThan, | ||
| 16 | Equal, | ||
| 17 | LessThanEqual, | ||
| 18 | GreaterThan = 16, | ||
| 19 | NotEqual, | ||
| 20 | GreaterThanEqual, | ||
| 21 | True, | ||
| 22 | }; | ||
| 23 | |||
| 24 | CompareOp VsetpToShaderCompareOp(VsetpCompareOp op) { | ||
| 25 | switch (op) { | ||
| 26 | case VsetpCompareOp::False: | ||
| 27 | return CompareOp::False; | ||
| 28 | case VsetpCompareOp::LessThan: | ||
| 29 | return CompareOp::LessThan; | ||
| 30 | case VsetpCompareOp::Equal: | ||
| 31 | return CompareOp::Equal; | ||
| 32 | case VsetpCompareOp::LessThanEqual: | ||
| 33 | return CompareOp::LessThanEqual; | ||
| 34 | case VsetpCompareOp::GreaterThan: | ||
| 35 | return CompareOp::GreaterThan; | ||
| 36 | case VsetpCompareOp::NotEqual: | ||
| 37 | return CompareOp::NotEqual; | ||
| 38 | case VsetpCompareOp::GreaterThanEqual: | ||
| 39 | return CompareOp::GreaterThanEqual; | ||
| 40 | case VsetpCompareOp::True: | ||
| 41 | return CompareOp::True; | ||
| 42 | default: | ||
| 43 | throw NotImplementedException("Invalid compare op {}", op); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | } // Anonymous namespace | ||
| 47 | |||
| 48 | void TranslatorVisitor::VSETP(u64 insn) { | ||
| 49 | union { | ||
| 50 | u64 raw; | ||
| 51 | BitField<0, 3, IR::Pred> dest_pred_b; | ||
| 52 | BitField<3, 3, IR::Pred> dest_pred_a; | ||
| 53 | BitField<20, 16, u64> src_b_imm; | ||
| 54 | BitField<28, 2, u64> src_b_selector; | ||
| 55 | BitField<29, 2, VideoWidth> src_b_width; | ||
| 56 | BitField<36, 2, u64> src_a_selector; | ||
| 57 | BitField<37, 2, VideoWidth> src_a_width; | ||
| 58 | BitField<39, 3, IR::Pred> bop_pred; | ||
| 59 | BitField<42, 1, u64> neg_bop_pred; | ||
| 60 | BitField<43, 5, VsetpCompareOp> compare_op; | ||
| 61 | BitField<45, 2, BooleanOp> bop; | ||
| 62 | BitField<48, 1, u64> src_a_sign; | ||
| 63 | BitField<49, 1, u64> src_b_sign; | ||
| 64 | BitField<50, 1, u64> is_src_b_reg; | ||
| 65 | } const vsetp{insn}; | ||
| 66 | |||
| 67 | const bool is_b_imm{vsetp.is_src_b_reg == 0}; | ||
| 68 | const IR::U32 src_a{GetReg8(insn)}; | ||
| 69 | const IR::U32 src_b{is_b_imm ? ir.Imm32(static_cast<u32>(vsetp.src_b_imm)) : GetReg20(insn)}; | ||
| 70 | |||
| 71 | const u32 a_selector{static_cast<u32>(vsetp.src_a_selector)}; | ||
| 72 | const u32 b_selector{is_b_imm ? 0U : static_cast<u32>(vsetp.src_b_selector)}; | ||
| 73 | const VideoWidth a_width{vsetp.src_a_width}; | ||
| 74 | const VideoWidth b_width{GetVideoSourceWidth(vsetp.src_b_width, is_b_imm)}; | ||
| 75 | |||
| 76 | const bool src_a_signed{vsetp.src_a_sign != 0}; | ||
| 77 | const bool src_b_signed{vsetp.src_b_sign != 0}; | ||
| 78 | const IR::U32 op_a{ExtractVideoOperandValue(ir, src_a, a_width, a_selector, src_a_signed)}; | ||
| 79 | const IR::U32 op_b{ExtractVideoOperandValue(ir, src_b, b_width, a_selector, src_b_signed)}; | ||
| 80 | |||
| 81 | // Compare operation's sign is only dependent on operand b's sign | ||
| 82 | const bool compare_signed{src_b_signed}; | ||
| 83 | const CompareOp compare_op{VsetpToShaderCompareOp(vsetp.compare_op)}; | ||
| 84 | const IR::U1 comparison{IntegerCompare(ir, op_a, op_b, compare_op, compare_signed)}; | ||
| 85 | const IR::U1 bop_pred{ir.GetPred(vsetp.bop_pred, vsetp.neg_bop_pred != 0)}; | ||
| 86 | const IR::U1 result_a{PredicateCombine(ir, comparison, bop_pred, vsetp.bop)}; | ||
| 87 | const IR::U1 result_b{PredicateCombine(ir, ir.LogicalNot(comparison), bop_pred, vsetp.bop)}; | ||
| 88 | ir.SetPred(vsetp.dest_pred_a, result_a); | ||
| 89 | ir.SetPred(vsetp.dest_pred_b, result_b); | ||
| 90 | } | ||
| 91 | |||
| 92 | } // namespace Shader::Maxwell | ||