diff options
| author | 2021-03-20 05:04:12 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:23 -0400 | |
| commit | f91859efd259995806c2944f7941b105b58300d3 (patch) | |
| tree | 489e587bcac6c0833c02378a106222c4db107c14 /src/shader_recompiler/frontend/maxwell | |
| parent | shader: Implement ISCADD (imm) (diff) | |
| download | yuzu-f91859efd259995806c2944f7941b105b58300d3.tar.gz yuzu-f91859efd259995806c2944f7941b105b58300d3.tar.xz yuzu-f91859efd259995806c2944f7941b105b58300d3.zip | |
shader: Implement I2F
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell')
6 files changed, 198 insertions, 14 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp index e444dcd4f..c9af83010 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp | |||
| @@ -121,6 +121,22 @@ IR::F64 TranslatorVisitor::GetDoubleCbuf(u64 insn) { | |||
| 121 | return ir.PackDouble2x32(ir.CompositeConstruct(lower_bits, value)); | 121 | return ir.PackDouble2x32(ir.CompositeConstruct(lower_bits, value)); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | IR::U64 TranslatorVisitor::GetPackedCbuf(u64 insn) { | ||
| 125 | union { | ||
| 126 | u64 raw; | ||
| 127 | BitField<20, 1, u64> unaligned; | ||
| 128 | } const cbuf{insn}; | ||
| 129 | |||
| 130 | if (cbuf.unaligned != 0) { | ||
| 131 | throw NotImplementedException("Unaligned packed constant buffer read"); | ||
| 132 | } | ||
| 133 | const auto [binding, lower_offset]{CbufAddr(insn)}; | ||
| 134 | const IR::U32 upper_offset{ir.Imm32(lower_offset.U32() + 4)}; | ||
| 135 | const IR::U32 lower_value{ir.GetCbuf(binding, lower_offset)}; | ||
| 136 | const IR::U32 upper_value{ir.GetCbuf(binding, upper_offset)}; | ||
| 137 | return ir.PackUint2x32(ir.CompositeConstruct(lower_value, upper_value)); | ||
| 138 | } | ||
| 139 | |||
| 124 | IR::U32 TranslatorVisitor::GetImm20(u64 insn) { | 140 | IR::U32 TranslatorVisitor::GetImm20(u64 insn) { |
| 125 | union { | 141 | union { |
| 126 | u64 raw; | 142 | u64 raw; |
| @@ -158,6 +174,11 @@ IR::F64 TranslatorVisitor::GetDoubleImm20(u64 insn) { | |||
| 158 | return ir.Imm64(Common::BitCast<f64>(value | sign_bit)); | 174 | return ir.Imm64(Common::BitCast<f64>(value | sign_bit)); |
| 159 | } | 175 | } |
| 160 | 176 | ||
| 177 | IR::U64 TranslatorVisitor::GetPackedImm20(u64 insn) { | ||
| 178 | const s64 value{GetImm20(insn).U32()}; | ||
| 179 | return ir.Imm64(static_cast<u64>(static_cast<s64>(value) << 32)); | ||
| 180 | } | ||
| 181 | |||
| 161 | IR::U32 TranslatorVisitor::GetImm32(u64 insn) { | 182 | IR::U32 TranslatorVisitor::GetImm32(u64 insn) { |
| 162 | union { | 183 | union { |
| 163 | u64 raw; | 184 | u64 raw; |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h index ed81d9c36..cb66cca25 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h | |||
| @@ -356,10 +356,12 @@ public: | |||
| 356 | [[nodiscard]] IR::U32 GetCbuf(u64 insn); | 356 | [[nodiscard]] IR::U32 GetCbuf(u64 insn); |
| 357 | [[nodiscard]] IR::F32 GetFloatCbuf(u64 insn); | 357 | [[nodiscard]] IR::F32 GetFloatCbuf(u64 insn); |
| 358 | [[nodiscard]] IR::F64 GetDoubleCbuf(u64 insn); | 358 | [[nodiscard]] IR::F64 GetDoubleCbuf(u64 insn); |
| 359 | [[nodiscard]] IR::U64 GetPackedCbuf(u64 insn); | ||
| 359 | 360 | ||
| 360 | [[nodiscard]] IR::U32 GetImm20(u64 insn); | 361 | [[nodiscard]] IR::U32 GetImm20(u64 insn); |
| 361 | [[nodiscard]] IR::F32 GetFloatImm20(u64 insn); | 362 | [[nodiscard]] IR::F32 GetFloatImm20(u64 insn); |
| 362 | [[nodiscard]] IR::F64 GetDoubleImm20(u64 insn); | 363 | [[nodiscard]] IR::F64 GetDoubleImm20(u64 insn); |
| 364 | [[nodiscard]] IR::U64 GetPackedImm20(u64 insn); | ||
| 363 | 365 | ||
| 364 | [[nodiscard]] IR::U32 GetImm32(u64 insn); | 366 | [[nodiscard]] IR::U32 GetImm32(u64 insn); |
| 365 | [[nodiscard]] IR::F32 GetFloatImm32(u64 insn); | 367 | [[nodiscard]] IR::F32 GetFloatImm32(u64 insn); |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/integer_floating_point_conversion.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_floating_point_conversion.cpp new file mode 100644 index 000000000..e8b5ae1d2 --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_floating_point_conversion.cpp | |||
| @@ -0,0 +1,173 @@ | |||
| 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/bit_field.h" | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h" | ||
| 8 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 9 | |||
| 10 | namespace Shader::Maxwell { | ||
| 11 | namespace { | ||
| 12 | enum class FloatFormat : u64 { | ||
| 13 | F16 = 1, | ||
| 14 | F32 = 2, | ||
| 15 | F64 = 3, | ||
| 16 | }; | ||
| 17 | |||
| 18 | enum class IntFormat : u64 { | ||
| 19 | U8 = 0, | ||
| 20 | U16 = 1, | ||
| 21 | U32 = 2, | ||
| 22 | U64 = 3, | ||
| 23 | }; | ||
| 24 | |||
| 25 | union Encoding { | ||
| 26 | u64 raw; | ||
| 27 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 28 | BitField<8, 2, FloatFormat> float_format; | ||
| 29 | BitField<10, 2, IntFormat> int_format; | ||
| 30 | BitField<13, 1, u64> is_signed; | ||
| 31 | BitField<39, 2, FpRounding> fp_rounding; | ||
| 32 | BitField<41, 2, u64> selector; | ||
| 33 | BitField<47, 1, u64> cc; | ||
| 34 | BitField<45, 1, u64> neg; | ||
| 35 | BitField<49, 1, u64> abs; | ||
| 36 | }; | ||
| 37 | |||
| 38 | bool Is64(u64 insn) { | ||
| 39 | return Encoding{insn}.int_format == IntFormat::U64; | ||
| 40 | } | ||
| 41 | |||
| 42 | int BitSize(FloatFormat format) { | ||
| 43 | switch (format) { | ||
| 44 | case FloatFormat::F16: | ||
| 45 | return 16; | ||
| 46 | case FloatFormat::F32: | ||
| 47 | return 32; | ||
| 48 | case FloatFormat::F64: | ||
| 49 | return 64; | ||
| 50 | } | ||
| 51 | throw NotImplementedException("Invalid float format {}", format); | ||
| 52 | } | ||
| 53 | |||
| 54 | IR::U32 SmallAbs(TranslatorVisitor& v, const IR::U32& value, int bitsize) { | ||
| 55 | const IR::U32 least_value{v.ir.Imm32(-(1 << (bitsize - 1)))}; | ||
| 56 | const IR::U32 mask{v.ir.ShiftRightArithmetic(value, v.ir.Imm32(bitsize - 1))}; | ||
| 57 | const IR::U32 absolute{v.ir.BitwiseXor(v.ir.IAdd(value, mask), mask)}; | ||
| 58 | const IR::U1 is_least{v.ir.IEqual(value, least_value)}; | ||
| 59 | return IR::U32{v.ir.Select(is_least, value, absolute)}; | ||
| 60 | } | ||
| 61 | |||
| 62 | void I2F(TranslatorVisitor& v, u64 insn, IR::U32U64 src) { | ||
| 63 | const Encoding i2f{insn}; | ||
| 64 | if (i2f.cc != 0) { | ||
| 65 | throw NotImplementedException("CC"); | ||
| 66 | } | ||
| 67 | const bool is_signed{i2f.is_signed != 0}; | ||
| 68 | int src_bitsize{}; | ||
| 69 | switch (i2f.int_format) { | ||
| 70 | case IntFormat::U8: | ||
| 71 | src = v.ir.BitFieldExtract(src, v.ir.Imm32(static_cast<u32>(i2f.selector) * 8), | ||
| 72 | v.ir.Imm32(8), is_signed); | ||
| 73 | if (i2f.abs != 0) { | ||
| 74 | src = SmallAbs(v, src, 8); | ||
| 75 | } | ||
| 76 | src_bitsize = 8; | ||
| 77 | break; | ||
| 78 | case IntFormat::U16: | ||
| 79 | if (i2f.selector == 1 || i2f.selector == 3) { | ||
| 80 | throw NotImplementedException("Invalid U16 selector {}", i2f.selector.Value()); | ||
| 81 | } | ||
| 82 | src = v.ir.BitFieldExtract(src, v.ir.Imm32(static_cast<u32>(i2f.selector) * 8), | ||
| 83 | v.ir.Imm32(16), is_signed); | ||
| 84 | if (i2f.abs != 0) { | ||
| 85 | src = SmallAbs(v, src, 16); | ||
| 86 | } | ||
| 87 | src_bitsize = 16; | ||
| 88 | break; | ||
| 89 | case IntFormat::U32: | ||
| 90 | case IntFormat::U64: | ||
| 91 | if (i2f.selector != 0) { | ||
| 92 | throw NotImplementedException("Unexpected selector {}", i2f.selector.Value()); | ||
| 93 | } | ||
| 94 | if (i2f.abs != 0 && is_signed) { | ||
| 95 | src = v.ir.IAbs(src); | ||
| 96 | } | ||
| 97 | src_bitsize = i2f.int_format == IntFormat::U64 ? 64 : 32; | ||
| 98 | break; | ||
| 99 | } | ||
| 100 | const int conversion_src_bitsize{i2f.int_format == IntFormat::U64 ? 64 : 32}; | ||
| 101 | const int dst_bitsize{BitSize(i2f.float_format)}; | ||
| 102 | IR::F16F32F64 value{v.ir.ConvertIToF(dst_bitsize, conversion_src_bitsize, is_signed, src)}; | ||
| 103 | if (i2f.neg != 0) { | ||
| 104 | if (i2f.abs != 0 || !is_signed) { | ||
| 105 | // We know the value is positive | ||
| 106 | value = v.ir.FPNeg(value); | ||
| 107 | } else { | ||
| 108 | // Only negate if the input isn't the lowest value | ||
| 109 | IR::U1 is_least; | ||
| 110 | if (src_bitsize == 64) { | ||
| 111 | is_least = v.ir.IEqual(src, v.ir.Imm64(std::numeric_limits<s64>::min())); | ||
| 112 | } else { | ||
| 113 | const IR::U32 least_value{v.ir.Imm32(-(1 << (src_bitsize - 1)))}; | ||
| 114 | is_least = v.ir.IEqual(src, least_value); | ||
| 115 | } | ||
| 116 | value = IR::F16F32F64{v.ir.Select(is_least, value, v.ir.FPNeg(value))}; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | switch (i2f.float_format) { | ||
| 120 | case FloatFormat::F16: { | ||
| 121 | const IR::F16 zero{v.ir.FPConvert(16, v.ir.Imm32(0.0f))}; | ||
| 122 | v.X(i2f.dest_reg, v.ir.PackFloat2x16(v.ir.CompositeConstruct(value, zero))); | ||
| 123 | break; | ||
| 124 | } | ||
| 125 | case FloatFormat::F32: | ||
| 126 | v.F(i2f.dest_reg, value); | ||
| 127 | break; | ||
| 128 | case FloatFormat::F64: { | ||
| 129 | if (!IR::IsAligned(i2f.dest_reg, 2)) { | ||
| 130 | throw NotImplementedException("Unaligned destination {}", i2f.dest_reg.Value()); | ||
| 131 | } | ||
| 132 | const IR::Value vector{v.ir.UnpackDouble2x32(value)}; | ||
| 133 | for (int i = 0; i < 2; ++i) { | ||
| 134 | v.X(i2f.dest_reg + i, IR::U32{v.ir.CompositeExtract(vector, i)}); | ||
| 135 | } | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | default: | ||
| 139 | throw NotImplementedException("Invalid float format {}", i2f.float_format.Value()); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } // Anonymous namespace | ||
| 143 | |||
| 144 | void TranslatorVisitor::I2F_reg(u64 insn) { | ||
| 145 | if (Is64(insn)) { | ||
| 146 | union { | ||
| 147 | u64 raw; | ||
| 148 | BitField<20, 8, IR::Reg> reg; | ||
| 149 | } const value{insn}; | ||
| 150 | const IR::Value regs{ir.CompositeConstruct(ir.GetReg(value.reg), ir.GetReg(value.reg + 1))}; | ||
| 151 | I2F(*this, insn, ir.PackUint2x32(regs)); | ||
| 152 | } else { | ||
| 153 | I2F(*this, insn, GetReg20(insn)); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | void TranslatorVisitor::I2F_cbuf(u64 insn) { | ||
| 158 | if (Is64(insn)) { | ||
| 159 | I2F(*this, insn, GetPackedCbuf(insn)); | ||
| 160 | } else { | ||
| 161 | I2F(*this, insn, GetCbuf(insn)); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | void TranslatorVisitor::I2F_imm(u64 insn) { | ||
| 166 | if (Is64(insn)) { | ||
| 167 | I2F(*this, insn, GetPackedImm20(insn)); | ||
| 168 | } else { | ||
| 169 | I2F(*this, insn, GetImm20(insn)); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | } // namespace Shader::Maxwell \ No newline at end of file | ||
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 a4367fc5a..4078feafa 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp | |||
| @@ -241,18 +241,6 @@ void TranslatorVisitor::HSETP2_imm(u64) { | |||
| 241 | ThrowNotImplemented(Opcode::HSETP2_imm); | 241 | ThrowNotImplemented(Opcode::HSETP2_imm); |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | void TranslatorVisitor::I2F_reg(u64) { | ||
| 245 | ThrowNotImplemented(Opcode::I2F_reg); | ||
| 246 | } | ||
| 247 | |||
| 248 | void TranslatorVisitor::I2F_cbuf(u64) { | ||
| 249 | ThrowNotImplemented(Opcode::I2F_cbuf); | ||
| 250 | } | ||
| 251 | |||
| 252 | void TranslatorVisitor::I2F_imm(u64) { | ||
| 253 | ThrowNotImplemented(Opcode::I2F_imm); | ||
| 254 | } | ||
| 255 | |||
| 256 | void TranslatorVisitor::IDE(u64) { | 244 | void TranslatorVisitor::IDE(u64) { |
| 257 | ThrowNotImplemented(Opcode::IDE); | 245 | ThrowNotImplemented(Opcode::IDE); |
| 258 | } | 246 | } |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp index 0fbb87ec4..b691b4d1f 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp | |||
| @@ -56,7 +56,7 @@ Shader::TextureType GetType(TextureType type, bool dc) { | |||
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureType type) { | 58 | IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, TextureType type) { |
| 59 | const auto read_array{[&]() -> IR::F32 { return v.ir.ConvertUToF(32, v.X(reg)); }}; | 59 | const auto read_array{[&]() -> IR::F32 { return v.ir.ConvertUToF(32, 16, v.X(reg)); }}; |
| 60 | switch (type) { | 60 | switch (type) { |
| 61 | case TextureType::_1D: | 61 | case TextureType::_1D: |
| 62 | return v.F(reg); | 62 | return v.F(reg); |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp index 54f0df754..d5fda20f4 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp | |||
| @@ -65,7 +65,7 @@ IR::Value Composite(TranslatorVisitor& v, Args... regs) { | |||
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | IR::F32 ReadArray(TranslatorVisitor& v, const IR::U32& value) { | 67 | IR::F32 ReadArray(TranslatorVisitor& v, const IR::U32& value) { |
| 68 | return v.ir.ConvertUToF(32, v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(16))); | 68 | return v.ir.ConvertUToF(32, 16, v.ir.BitFieldExtract(value, v.ir.Imm32(0), v.ir.Imm32(16))); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | IR::Value Sample(TranslatorVisitor& v, u64 insn) { | 71 | IR::Value Sample(TranslatorVisitor& v, u64 insn) { |