diff options
Diffstat (limited to 'src/shader_recompiler/frontend')
| -rw-r--r-- | src/shader_recompiler/frontend/ir/ir_emitter.cpp | 8 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/ir_emitter.h | 3 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/modifiers.h | 3 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp | 4 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp (renamed from src/shader_recompiler/frontend/maxwell/translate/impl/texture_sample.cpp) | 0 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp | 262 |
6 files changed, 275 insertions, 5 deletions
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index 556961fa4..d94596ee9 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -512,6 +512,14 @@ Value IREmitter::UnpackFloat2x16(const U32& value) { | |||
| 512 | return Inst(Opcode::UnpackFloat2x16, value); | 512 | return Inst(Opcode::UnpackFloat2x16, value); |
| 513 | } | 513 | } |
| 514 | 514 | ||
| 515 | U32 IREmitter::PackHalf2x16(const Value& vector) { | ||
| 516 | return Inst<U32>(Opcode::PackHalf2x16, vector); | ||
| 517 | } | ||
| 518 | |||
| 519 | Value IREmitter::UnpackHalf2x16(const U32& value) { | ||
| 520 | return Inst(Opcode::UnpackHalf2x16, value); | ||
| 521 | } | ||
| 522 | |||
| 515 | F64 IREmitter::PackDouble2x32(const Value& vector) { | 523 | F64 IREmitter::PackDouble2x32(const Value& vector) { |
| 516 | return Inst<F64>(Opcode::PackDouble2x32, vector); | 524 | return Inst<F64>(Opcode::PackDouble2x32, vector); |
| 517 | } | 525 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 74fb3dbcb..27ff5a29d 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -115,6 +115,9 @@ public: | |||
| 115 | [[nodiscard]] U32 PackFloat2x16(const Value& vector); | 115 | [[nodiscard]] U32 PackFloat2x16(const Value& vector); |
| 116 | [[nodiscard]] Value UnpackFloat2x16(const U32& value); | 116 | [[nodiscard]] Value UnpackFloat2x16(const U32& value); |
| 117 | 117 | ||
| 118 | [[nodiscard]] U32 PackHalf2x16(const Value& vector); | ||
| 119 | [[nodiscard]] Value UnpackHalf2x16(const U32& value); | ||
| 120 | |||
| 118 | [[nodiscard]] F64 PackDouble2x32(const Value& vector); | 121 | [[nodiscard]] F64 PackDouble2x32(const Value& vector); |
| 119 | [[nodiscard]] Value UnpackDouble2x32(const F64& value); | 122 | [[nodiscard]] Value UnpackDouble2x32(const F64& value); |
| 120 | 123 | ||
diff --git a/src/shader_recompiler/frontend/ir/modifiers.h b/src/shader_recompiler/frontend/ir/modifiers.h index ad07700ae..308c00153 100644 --- a/src/shader_recompiler/frontend/ir/modifiers.h +++ b/src/shader_recompiler/frontend/ir/modifiers.h | |||
| @@ -36,7 +36,8 @@ union TextureInstInfo { | |||
| 36 | u32 raw; | 36 | u32 raw; |
| 37 | BitField<0, 8, TextureType> type; | 37 | BitField<0, 8, TextureType> type; |
| 38 | BitField<8, 1, u32> has_bias; | 38 | BitField<8, 1, u32> has_bias; |
| 39 | BitField<16, 1, u32> has_lod_clamp; | 39 | BitField<9, 1, u32> has_lod_clamp; |
| 40 | BitField<10, 1, u32> relaxed_precision; | ||
| 40 | }; | 41 | }; |
| 41 | static_assert(sizeof(TextureInstInfo) <= sizeof(u32)); | 42 | static_assert(sizeof(TextureInstInfo) <= sizeof(u32)); |
| 42 | 43 | ||
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 92da5c7e8..9aa7b836c 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp | |||
| @@ -553,10 +553,6 @@ void TranslatorVisitor::SYNC(u64) { | |||
| 553 | ThrowNotImplemented(Opcode::SYNC); | 553 | ThrowNotImplemented(Opcode::SYNC); |
| 554 | } | 554 | } |
| 555 | 555 | ||
| 556 | void TranslatorVisitor::TEXS(u64) { | ||
| 557 | ThrowNotImplemented(Opcode::TEXS); | ||
| 558 | } | ||
| 559 | |||
| 560 | void TranslatorVisitor::TLD(u64) { | 556 | void TranslatorVisitor::TLD(u64) { |
| 561 | ThrowNotImplemented(Opcode::TLD); | 557 | ThrowNotImplemented(Opcode::TLD); |
| 562 | } | 558 | } |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_sample.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp index 98d9f4c64..98d9f4c64 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_sample.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp | |||
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 new file mode 100644 index 000000000..ac1615b00 --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp | |||
| @@ -0,0 +1,262 @@ | |||
| 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 <utility> | ||
| 6 | |||
| 7 | #include "common/bit_field.h" | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "shader_recompiler/frontend/ir/modifiers.h" | ||
| 10 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 11 | |||
| 12 | namespace Shader::Maxwell { | ||
| 13 | namespace { | ||
| 14 | enum class Precision : u64 { | ||
| 15 | F16, | ||
| 16 | F32, | ||
| 17 | }; | ||
| 18 | |||
| 19 | union Encoding { | ||
| 20 | u64 raw; | ||
| 21 | BitField<59, 1, Precision> precision; | ||
| 22 | BitField<53, 4, u64> encoding; | ||
| 23 | BitField<49, 1, u64> nodep; | ||
| 24 | BitField<28, 8, IR::Reg> dest_reg_b; | ||
| 25 | BitField<0, 8, IR::Reg> dest_reg_a; | ||
| 26 | BitField<8, 8, IR::Reg> src_reg_a; | ||
| 27 | BitField<20, 8, IR::Reg> src_reg_b; | ||
| 28 | BitField<36, 13, u64> cbuf_offset; | ||
| 29 | BitField<50, 3, u64> swizzle; | ||
| 30 | }; | ||
| 31 | |||
| 32 | constexpr unsigned R = 1; | ||
| 33 | constexpr unsigned G = 2; | ||
| 34 | constexpr unsigned B = 4; | ||
| 35 | constexpr unsigned A = 8; | ||
| 36 | |||
| 37 | constexpr std::array RG_LUT{ | ||
| 38 | R, // | ||
| 39 | G, // | ||
| 40 | B, // | ||
| 41 | A, // | ||
| 42 | R | G, // | ||
| 43 | R | A, // | ||
| 44 | G | A, // | ||
| 45 | B | A, // | ||
| 46 | }; | ||
| 47 | |||
| 48 | constexpr std::array RGBA_LUT{ | ||
| 49 | R | G | B, // | ||
| 50 | R | G | A, // | ||
| 51 | R | B | A, // | ||
| 52 | G | B | A, // | ||
| 53 | R | G | B | A, // | ||
| 54 | }; | ||
| 55 | |||
| 56 | void CheckAlignment(IR::Reg reg, int alignment) { | ||
| 57 | if (!IR::IsAligned(reg, alignment)) { | ||
| 58 | throw NotImplementedException("Unaligned source register {}", reg); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | template <typename... Args> | ||
| 63 | IR::Value Composite(TranslatorVisitor& v, Args... regs) { | ||
| 64 | return v.ir.CompositeConstruct(v.F(regs)...); | ||
| 65 | } | ||
| 66 | |||
| 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))); | ||
| 69 | } | ||
| 70 | |||
| 71 | IR::Value Sample(TranslatorVisitor& v, u64 insn) { | ||
| 72 | const Encoding texs{insn}; | ||
| 73 | const IR::U32 handle{v.ir.Imm32(static_cast<u32>(texs.cbuf_offset))}; | ||
| 74 | const IR::F32 zero{v.ir.Imm32(0.0f)}; | ||
| 75 | const IR::Reg reg_a{texs.src_reg_a}; | ||
| 76 | const IR::Reg reg_b{texs.src_reg_b}; | ||
| 77 | IR::TextureInstInfo info{}; | ||
| 78 | if (texs.precision == Precision::F16) { | ||
| 79 | info.relaxed_precision.Assign(1); | ||
| 80 | } | ||
| 81 | switch (texs.encoding) { | ||
| 82 | case 0: // 1D.LZ | ||
| 83 | info.type.Assign(TextureType::Color1D); | ||
| 84 | return v.ir.ImageSampleExplicitLod(handle, v.F(reg_a), zero, {}, {}, info); | ||
| 85 | case 1: // 2D | ||
| 86 | info.type.Assign(TextureType::Color2D); | ||
| 87 | return v.ir.ImageSampleImplicitLod(handle, Composite(v, reg_a, reg_b), {}, {}, {}, info); | ||
| 88 | case 2: // 2D.LZ | ||
| 89 | info.type.Assign(TextureType::Color2D); | ||
| 90 | return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_b), zero, {}, {}, info); | ||
| 91 | case 3: // 2D.LL | ||
| 92 | CheckAlignment(reg_a, 2); | ||
| 93 | info.type.Assign(TextureType::Color2D); | ||
| 94 | return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b), {}, | ||
| 95 | {}, info); | ||
| 96 | case 4: // 2D.DC | ||
| 97 | CheckAlignment(reg_a, 2); | ||
| 98 | info.type.Assign(TextureType::Shadow2D); | ||
| 99 | return v.ir.ImageSampleDrefImplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b), | ||
| 100 | {}, {}, {}, info); | ||
| 101 | case 5: // 2D.LL.DC | ||
| 102 | CheckAlignment(reg_a, 2); | ||
| 103 | CheckAlignment(reg_b, 2); | ||
| 104 | info.type.Assign(TextureType::Shadow2D); | ||
| 105 | return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1), | ||
| 106 | v.F(reg_b + 1), v.F(reg_b), {}, {}, info); | ||
| 107 | case 6: // 2D.LZ.DC | ||
| 108 | CheckAlignment(reg_a, 2); | ||
| 109 | info.type.Assign(TextureType::Shadow2D); | ||
| 110 | return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b), | ||
| 111 | zero, {}, {}, info); | ||
| 112 | case 7: // ARRAY_2D | ||
| 113 | CheckAlignment(reg_a, 2); | ||
| 114 | info.type.Assign(TextureType::ColorArray2D); | ||
| 115 | return v.ir.ImageSampleImplicitLod( | ||
| 116 | handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))), | ||
| 117 | {}, {}, {}, info); | ||
| 118 | case 8: // ARRAY_2D.LZ | ||
| 119 | CheckAlignment(reg_a, 2); | ||
| 120 | info.type.Assign(TextureType::ColorArray2D); | ||
| 121 | return v.ir.ImageSampleExplicitLod( | ||
| 122 | handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))), | ||
| 123 | zero, {}, {}, info); | ||
| 124 | case 9: // ARRAY_2D.LZ.DC | ||
| 125 | CheckAlignment(reg_a, 2); | ||
| 126 | CheckAlignment(reg_b, 2); | ||
| 127 | info.type.Assign(TextureType::ShadowArray2D); | ||
| 128 | return v.ir.ImageSampleDrefExplicitLod( | ||
| 129 | handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))), | ||
| 130 | v.F(reg_b + 1), zero, {}, {}, info); | ||
| 131 | case 10: // 3D | ||
| 132 | CheckAlignment(reg_a, 2); | ||
| 133 | info.type.Assign(TextureType::Color3D); | ||
| 134 | return v.ir.ImageSampleImplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), {}, {}, | ||
| 135 | {}, info); | ||
| 136 | case 11: // 3D.LZ | ||
| 137 | CheckAlignment(reg_a, 2); | ||
| 138 | info.type.Assign(TextureType::Color3D); | ||
| 139 | return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), zero, {}, | ||
| 140 | {}, info); | ||
| 141 | case 12: // CUBE | ||
| 142 | CheckAlignment(reg_a, 2); | ||
| 143 | info.type.Assign(TextureType::ColorCube); | ||
| 144 | return v.ir.ImageSampleImplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), {}, {}, | ||
| 145 | {}, info); | ||
| 146 | case 13: // CUBE.LL | ||
| 147 | CheckAlignment(reg_a, 2); | ||
| 148 | CheckAlignment(reg_b, 2); | ||
| 149 | info.type.Assign(TextureType::ColorCube); | ||
| 150 | return v.ir.ImageSampleExplicitLod(handle, Composite(v, reg_a, reg_a + 1, reg_b), | ||
| 151 | v.F(reg_b + 1), {}, {}, info); | ||
| 152 | default: | ||
| 153 | throw NotImplementedException("Illegal encoding {}", texs.encoding.Value()); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | unsigned Swizzle(u64 insn) { | ||
| 158 | const Encoding texs{insn}; | ||
| 159 | const size_t encoding{texs.swizzle}; | ||
| 160 | if (texs.dest_reg_b == IR::Reg::RZ) { | ||
| 161 | if (encoding >= RG_LUT.size()) { | ||
| 162 | throw NotImplementedException("Illegal RG encoding {}", encoding); | ||
| 163 | } | ||
| 164 | return RG_LUT[encoding]; | ||
| 165 | } else { | ||
| 166 | if (encoding >= RGBA_LUT.size()) { | ||
| 167 | throw NotImplementedException("Illegal RGBA encoding {}", encoding); | ||
| 168 | } | ||
| 169 | return RGBA_LUT[encoding]; | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | IR::F32 Extract(TranslatorVisitor& v, const IR::Value& sample, unsigned component) { | ||
| 174 | const bool is_shadow{sample.Type() == IR::Type::F32}; | ||
| 175 | if (is_shadow) { | ||
| 176 | const bool is_alpha{component == 3}; | ||
| 177 | return is_alpha ? v.ir.Imm32(1.0f) : IR::F32{sample}; | ||
| 178 | } else { | ||
| 179 | return IR::F32{v.ir.CompositeExtract(sample, component)}; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | IR::Reg RegStoreComponent32(u64 insn, unsigned index) { | ||
| 184 | const Encoding texs{insn}; | ||
| 185 | switch (index) { | ||
| 186 | case 0: | ||
| 187 | return texs.dest_reg_a; | ||
| 188 | case 1: | ||
| 189 | CheckAlignment(texs.dest_reg_a, 2); | ||
| 190 | return texs.dest_reg_a + 1; | ||
| 191 | case 2: | ||
| 192 | return texs.dest_reg_b; | ||
| 193 | case 3: | ||
| 194 | CheckAlignment(texs.dest_reg_b, 2); | ||
| 195 | return texs.dest_reg_b + 1; | ||
| 196 | } | ||
| 197 | throw LogicError("Invalid store index {}", index); | ||
| 198 | } | ||
| 199 | |||
| 200 | void Store32(TranslatorVisitor& v, u64 insn, const IR::Value& sample) { | ||
| 201 | const unsigned swizzle{Swizzle(insn)}; | ||
| 202 | unsigned store_index{0}; | ||
| 203 | for (unsigned component = 0; component < 4; ++component) { | ||
| 204 | if (((swizzle >> component) & 1) == 0) { | ||
| 205 | continue; | ||
| 206 | } | ||
| 207 | const IR::Reg dest{RegStoreComponent32(insn, store_index)}; | ||
| 208 | v.F(dest, Extract(v, sample, component)); | ||
| 209 | ++store_index; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | IR::U32 Pack(TranslatorVisitor& v, const IR::F32& lhs, const IR::F32& rhs) { | ||
| 214 | return v.ir.PackHalf2x16(v.ir.CompositeConstruct(lhs, rhs)); | ||
| 215 | } | ||
| 216 | |||
| 217 | void Store16(TranslatorVisitor& v, u64 insn, const IR::Value& sample) { | ||
| 218 | const unsigned swizzle{Swizzle(insn)}; | ||
| 219 | unsigned store_index{0}; | ||
| 220 | std::array<IR::F32, 4> swizzled; | ||
| 221 | for (unsigned component = 0; component < 4; ++component) { | ||
| 222 | if (((swizzle >> component) & 1) == 0) { | ||
| 223 | continue; | ||
| 224 | } | ||
| 225 | swizzled[store_index] = Extract(v, sample, component); | ||
| 226 | ++store_index; | ||
| 227 | } | ||
| 228 | const IR::F32 zero{v.ir.Imm32(0.0f)}; | ||
| 229 | const Encoding texs{insn}; | ||
| 230 | switch (store_index) { | ||
| 231 | case 1: | ||
| 232 | v.X(texs.dest_reg_a, Pack(v, swizzled[0], zero)); | ||
| 233 | break; | ||
| 234 | case 2: | ||
| 235 | case 3: | ||
| 236 | case 4: | ||
| 237 | v.X(texs.dest_reg_a, Pack(v, swizzled[0], swizzled[1])); | ||
| 238 | switch (store_index) { | ||
| 239 | case 2: | ||
| 240 | break; | ||
| 241 | case 3: | ||
| 242 | v.X(texs.dest_reg_b, Pack(v, swizzled[2], zero)); | ||
| 243 | break; | ||
| 244 | case 4: | ||
| 245 | v.X(texs.dest_reg_b, Pack(v, swizzled[2], swizzled[3])); | ||
| 246 | break; | ||
| 247 | } | ||
| 248 | break; | ||
| 249 | } | ||
| 250 | } | ||
| 251 | } // Anonymous namespace | ||
| 252 | |||
| 253 | void TranslatorVisitor::TEXS(u64 insn) { | ||
| 254 | const IR::Value sample{Sample(*this, insn)}; | ||
| 255 | if (Encoding{insn}.precision == Precision::F32) { | ||
| 256 | Store32(*this, insn, sample); | ||
| 257 | } else { | ||
| 258 | Store16(*this, insn, sample); | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | } // namespace Shader::Maxwell | ||