diff options
Diffstat (limited to 'src/shader_recompiler/frontend')
8 files changed, 393 insertions, 5 deletions
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index 5913fdeff..354d72c9b 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -1869,6 +1869,95 @@ void IREmitter::ImageWrite(const Value& handle, const Value& coords, const Value | |||
| 1869 | Inst(op, Flags{info}, handle, coords, color); | 1869 | Inst(op, Flags{info}, handle, coords, color); |
| 1870 | } | 1870 | } |
| 1871 | 1871 | ||
| 1872 | Value IREmitter::ImageAtomicIAdd(const Value& handle, const Value& coords, const Value& value, | ||
| 1873 | TextureInstInfo info) { | ||
| 1874 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicIAdd32 | ||
| 1875 | : Opcode::BindlessImageAtomicIAdd32}; | ||
| 1876 | return Inst(op, Flags{info}, handle, coords, value); | ||
| 1877 | } | ||
| 1878 | |||
| 1879 | Value IREmitter::ImageAtomicSMin(const Value& handle, const Value& coords, const Value& value, | ||
| 1880 | TextureInstInfo info) { | ||
| 1881 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicSMin32 | ||
| 1882 | : Opcode::BindlessImageAtomicSMin32}; | ||
| 1883 | return Inst(op, Flags{info}, handle, coords, value); | ||
| 1884 | } | ||
| 1885 | |||
| 1886 | Value IREmitter::ImageAtomicUMin(const Value& handle, const Value& coords, const Value& value, | ||
| 1887 | TextureInstInfo info) { | ||
| 1888 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicUMin32 | ||
| 1889 | : Opcode::BindlessImageAtomicUMin32}; | ||
| 1890 | return Inst(op, Flags{info}, handle, coords, value); | ||
| 1891 | } | ||
| 1892 | |||
| 1893 | Value IREmitter::ImageAtomicIMin(const Value& handle, const Value& coords, const Value& value, | ||
| 1894 | bool is_signed, TextureInstInfo info) { | ||
| 1895 | return is_signed ? ImageAtomicSMin(handle, coords, value, info) | ||
| 1896 | : ImageAtomicUMin(handle, coords, value, info); | ||
| 1897 | } | ||
| 1898 | |||
| 1899 | Value IREmitter::ImageAtomicSMax(const Value& handle, const Value& coords, const Value& value, | ||
| 1900 | TextureInstInfo info) { | ||
| 1901 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicSMax32 | ||
| 1902 | : Opcode::BindlessImageAtomicSMax32}; | ||
| 1903 | return Inst(op, Flags{info}, handle, coords, value); | ||
| 1904 | } | ||
| 1905 | |||
| 1906 | Value IREmitter::ImageAtomicUMax(const Value& handle, const Value& coords, const Value& value, | ||
| 1907 | TextureInstInfo info) { | ||
| 1908 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicUMax32 | ||
| 1909 | : Opcode::BindlessImageAtomicUMax32}; | ||
| 1910 | return Inst(op, Flags{info}, handle, coords, value); | ||
| 1911 | } | ||
| 1912 | |||
| 1913 | Value IREmitter::ImageAtomicIMax(const Value& handle, const Value& coords, const Value& value, | ||
| 1914 | bool is_signed, TextureInstInfo info) { | ||
| 1915 | return is_signed ? ImageAtomicSMax(handle, coords, value, info) | ||
| 1916 | : ImageAtomicUMax(handle, coords, value, info); | ||
| 1917 | } | ||
| 1918 | |||
| 1919 | Value IREmitter::ImageAtomicInc(const Value& handle, const Value& coords, const Value& value, | ||
| 1920 | TextureInstInfo info) { | ||
| 1921 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicInc32 | ||
| 1922 | : Opcode::BindlessImageAtomicInc32}; | ||
| 1923 | return Inst(op, Flags{info}, handle, coords, value); | ||
| 1924 | } | ||
| 1925 | |||
| 1926 | Value IREmitter::ImageAtomicDec(const Value& handle, const Value& coords, const Value& value, | ||
| 1927 | TextureInstInfo info) { | ||
| 1928 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicDec32 | ||
| 1929 | : Opcode::BindlessImageAtomicDec32}; | ||
| 1930 | return Inst(op, Flags{info}, handle, coords, value); | ||
| 1931 | } | ||
| 1932 | |||
| 1933 | Value IREmitter::ImageAtomicAnd(const Value& handle, const Value& coords, const Value& value, | ||
| 1934 | TextureInstInfo info) { | ||
| 1935 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicAnd32 | ||
| 1936 | : Opcode::BindlessImageAtomicAnd32}; | ||
| 1937 | return Inst(op, Flags{info}, handle, coords, value); | ||
| 1938 | } | ||
| 1939 | |||
| 1940 | Value IREmitter::ImageAtomicOr(const Value& handle, const Value& coords, const Value& value, | ||
| 1941 | TextureInstInfo info) { | ||
| 1942 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicOr32 | ||
| 1943 | : Opcode::BindlessImageAtomicOr32}; | ||
| 1944 | return Inst(op, Flags{info}, handle, coords, value); | ||
| 1945 | } | ||
| 1946 | |||
| 1947 | Value IREmitter::ImageAtomicXor(const Value& handle, const Value& coords, const Value& value, | ||
| 1948 | TextureInstInfo info) { | ||
| 1949 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicXor32 | ||
| 1950 | : Opcode::BindlessImageAtomicXor32}; | ||
| 1951 | return Inst(op, Flags{info}, handle, coords, value); | ||
| 1952 | } | ||
| 1953 | |||
| 1954 | Value IREmitter::ImageAtomicExchange(const Value& handle, const Value& coords, const Value& value, | ||
| 1955 | TextureInstInfo info) { | ||
| 1956 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicExchange32 | ||
| 1957 | : Opcode::BindlessImageAtomicExchange32}; | ||
| 1958 | return Inst(op, Flags{info}, handle, coords, value); | ||
| 1959 | } | ||
| 1960 | |||
| 1872 | U1 IREmitter::VoteAll(const U1& value) { | 1961 | U1 IREmitter::VoteAll(const U1& value) { |
| 1873 | return Inst<U1>(Opcode::VoteAll, value); | 1962 | return Inst<U1>(Opcode::VoteAll, value); |
| 1874 | } | 1963 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index a12919283..4e614d424 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -334,6 +334,32 @@ public: | |||
| 334 | [[nodiscard]] void ImageWrite(const Value& handle, const Value& coords, const Value& color, | 334 | [[nodiscard]] void ImageWrite(const Value& handle, const Value& coords, const Value& color, |
| 335 | TextureInstInfo info); | 335 | TextureInstInfo info); |
| 336 | 336 | ||
| 337 | [[nodiscard]] Value ImageAtomicIAdd(const Value& handle, const Value& coords, | ||
| 338 | const Value& value, TextureInstInfo info); | ||
| 339 | [[nodiscard]] Value ImageAtomicSMin(const Value& handle, const Value& coords, | ||
| 340 | const Value& value, TextureInstInfo info); | ||
| 341 | [[nodiscard]] Value ImageAtomicUMin(const Value& handle, const Value& coords, | ||
| 342 | const Value& value, TextureInstInfo info); | ||
| 343 | [[nodiscard]] Value ImageAtomicIMin(const Value& handle, const Value& coords, | ||
| 344 | const Value& value, bool is_signed, TextureInstInfo info); | ||
| 345 | [[nodiscard]] Value ImageAtomicSMax(const Value& handle, const Value& coords, | ||
| 346 | const Value& value, TextureInstInfo info); | ||
| 347 | [[nodiscard]] Value ImageAtomicUMax(const Value& handle, const Value& coords, | ||
| 348 | const Value& value, TextureInstInfo info); | ||
| 349 | [[nodiscard]] Value ImageAtomicIMax(const Value& handle, const Value& coords, | ||
| 350 | const Value& value, bool is_signed, TextureInstInfo info); | ||
| 351 | [[nodiscard]] Value ImageAtomicInc(const Value& handle, const Value& coords, const Value& value, | ||
| 352 | TextureInstInfo info); | ||
| 353 | [[nodiscard]] Value ImageAtomicDec(const Value& handle, const Value& coords, const Value& value, | ||
| 354 | TextureInstInfo info); | ||
| 355 | [[nodiscard]] Value ImageAtomicAnd(const Value& handle, const Value& coords, const Value& value, | ||
| 356 | TextureInstInfo info); | ||
| 357 | [[nodiscard]] Value ImageAtomicOr(const Value& handle, const Value& coords, const Value& value, | ||
| 358 | TextureInstInfo info); | ||
| 359 | [[nodiscard]] Value ImageAtomicXor(const Value& handle, const Value& coords, const Value& value, | ||
| 360 | TextureInstInfo info); | ||
| 361 | [[nodiscard]] Value ImageAtomicExchange(const Value& handle, const Value& coords, | ||
| 362 | const Value& value, TextureInstInfo info); | ||
| 337 | [[nodiscard]] U1 VoteAll(const U1& value); | 363 | [[nodiscard]] U1 VoteAll(const U1& value); |
| 338 | [[nodiscard]] U1 VoteAny(const U1& value); | 364 | [[nodiscard]] U1 VoteAny(const U1& value); |
| 339 | [[nodiscard]] U1 VoteEqual(const U1& value); | 365 | [[nodiscard]] U1 VoteEqual(const U1& value); |
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp index dba902186..616ef17d4 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.cpp +++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp | |||
| @@ -166,6 +166,39 @@ bool Inst::MayHaveSideEffects() const noexcept { | |||
| 166 | case Opcode::BindlessImageWrite: | 166 | case Opcode::BindlessImageWrite: |
| 167 | case Opcode::BoundImageWrite: | 167 | case Opcode::BoundImageWrite: |
| 168 | case Opcode::ImageWrite: | 168 | case Opcode::ImageWrite: |
| 169 | case IR::Opcode::BindlessImageAtomicIAdd32: | ||
| 170 | case IR::Opcode::BindlessImageAtomicSMin32: | ||
| 171 | case IR::Opcode::BindlessImageAtomicUMin32: | ||
| 172 | case IR::Opcode::BindlessImageAtomicSMax32: | ||
| 173 | case IR::Opcode::BindlessImageAtomicUMax32: | ||
| 174 | case IR::Opcode::BindlessImageAtomicInc32: | ||
| 175 | case IR::Opcode::BindlessImageAtomicDec32: | ||
| 176 | case IR::Opcode::BindlessImageAtomicAnd32: | ||
| 177 | case IR::Opcode::BindlessImageAtomicOr32: | ||
| 178 | case IR::Opcode::BindlessImageAtomicXor32: | ||
| 179 | case IR::Opcode::BindlessImageAtomicExchange32: | ||
| 180 | case IR::Opcode::BoundImageAtomicIAdd32: | ||
| 181 | case IR::Opcode::BoundImageAtomicSMin32: | ||
| 182 | case IR::Opcode::BoundImageAtomicUMin32: | ||
| 183 | case IR::Opcode::BoundImageAtomicSMax32: | ||
| 184 | case IR::Opcode::BoundImageAtomicUMax32: | ||
| 185 | case IR::Opcode::BoundImageAtomicInc32: | ||
| 186 | case IR::Opcode::BoundImageAtomicDec32: | ||
| 187 | case IR::Opcode::BoundImageAtomicAnd32: | ||
| 188 | case IR::Opcode::BoundImageAtomicOr32: | ||
| 189 | case IR::Opcode::BoundImageAtomicXor32: | ||
| 190 | case IR::Opcode::BoundImageAtomicExchange32: | ||
| 191 | case IR::Opcode::ImageAtomicIAdd32: | ||
| 192 | case IR::Opcode::ImageAtomicSMin32: | ||
| 193 | case IR::Opcode::ImageAtomicUMin32: | ||
| 194 | case IR::Opcode::ImageAtomicSMax32: | ||
| 195 | case IR::Opcode::ImageAtomicUMax32: | ||
| 196 | case IR::Opcode::ImageAtomicInc32: | ||
| 197 | case IR::Opcode::ImageAtomicDec32: | ||
| 198 | case IR::Opcode::ImageAtomicAnd32: | ||
| 199 | case IR::Opcode::ImageAtomicOr32: | ||
| 200 | case IR::Opcode::ImageAtomicXor32: | ||
| 201 | case IR::Opcode::ImageAtomicExchange32: | ||
| 169 | return true; | 202 | return true; |
| 170 | default: | 203 | default: |
| 171 | return false; | 204 | return false; |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index b14719c51..9165421f8 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -496,6 +496,44 @@ OPCODE(ImageGradient, F32x4, Opaq | |||
| 496 | OPCODE(ImageRead, U32x4, Opaque, Opaque, ) | 496 | OPCODE(ImageRead, U32x4, Opaque, Opaque, ) |
| 497 | OPCODE(ImageWrite, Void, Opaque, Opaque, U32x4, ) | 497 | OPCODE(ImageWrite, Void, Opaque, Opaque, U32x4, ) |
| 498 | 498 | ||
| 499 | // Atomic Image operations | ||
| 500 | |||
| 501 | OPCODE(BindlessImageAtomicIAdd32, U32, U32, Opaque, U32, ) | ||
| 502 | OPCODE(BindlessImageAtomicSMin32, U32, U32, Opaque, U32, ) | ||
| 503 | OPCODE(BindlessImageAtomicUMin32, U32, U32, Opaque, U32, ) | ||
| 504 | OPCODE(BindlessImageAtomicSMax32, U32, U32, Opaque, U32, ) | ||
| 505 | OPCODE(BindlessImageAtomicUMax32, U32, U32, Opaque, U32, ) | ||
| 506 | OPCODE(BindlessImageAtomicInc32, U32, U32, Opaque, U32, ) | ||
| 507 | OPCODE(BindlessImageAtomicDec32, U32, U32, Opaque, U32, ) | ||
| 508 | OPCODE(BindlessImageAtomicAnd32, U32, U32, Opaque, U32, ) | ||
| 509 | OPCODE(BindlessImageAtomicOr32, U32, U32, Opaque, U32, ) | ||
| 510 | OPCODE(BindlessImageAtomicXor32, U32, U32, Opaque, U32, ) | ||
| 511 | OPCODE(BindlessImageAtomicExchange32, U32, U32, Opaque, U32, ) | ||
| 512 | |||
| 513 | OPCODE(BoundImageAtomicIAdd32, U32, U32, Opaque, U32, ) | ||
| 514 | OPCODE(BoundImageAtomicSMin32, U32, U32, Opaque, U32, ) | ||
| 515 | OPCODE(BoundImageAtomicUMin32, U32, U32, Opaque, U32, ) | ||
| 516 | OPCODE(BoundImageAtomicSMax32, U32, U32, Opaque, U32, ) | ||
| 517 | OPCODE(BoundImageAtomicUMax32, U32, U32, Opaque, U32, ) | ||
| 518 | OPCODE(BoundImageAtomicInc32, U32, U32, Opaque, U32, ) | ||
| 519 | OPCODE(BoundImageAtomicDec32, U32, U32, Opaque, U32, ) | ||
| 520 | OPCODE(BoundImageAtomicAnd32, U32, U32, Opaque, U32, ) | ||
| 521 | OPCODE(BoundImageAtomicOr32, U32, U32, Opaque, U32, ) | ||
| 522 | OPCODE(BoundImageAtomicXor32, U32, U32, Opaque, U32, ) | ||
| 523 | OPCODE(BoundImageAtomicExchange32, U32, U32, Opaque, U32, ) | ||
| 524 | |||
| 525 | OPCODE(ImageAtomicIAdd32, U32, Opaque, Opaque, U32, ) | ||
| 526 | OPCODE(ImageAtomicSMin32, U32, Opaque, Opaque, U32, ) | ||
| 527 | OPCODE(ImageAtomicUMin32, U32, Opaque, Opaque, U32, ) | ||
| 528 | OPCODE(ImageAtomicSMax32, U32, Opaque, Opaque, U32, ) | ||
| 529 | OPCODE(ImageAtomicUMax32, U32, Opaque, Opaque, U32, ) | ||
| 530 | OPCODE(ImageAtomicInc32, U32, Opaque, Opaque, U32, ) | ||
| 531 | OPCODE(ImageAtomicDec32, U32, Opaque, Opaque, U32, ) | ||
| 532 | OPCODE(ImageAtomicAnd32, U32, Opaque, Opaque, U32, ) | ||
| 533 | OPCODE(ImageAtomicOr32, U32, Opaque, Opaque, U32, ) | ||
| 534 | OPCODE(ImageAtomicXor32, U32, Opaque, Opaque, U32, ) | ||
| 535 | OPCODE(ImageAtomicExchange32, U32, Opaque, Opaque, U32, ) | ||
| 536 | |||
| 499 | // Warp operations | 537 | // Warp operations |
| 500 | OPCODE(LaneId, U32, ) | 538 | OPCODE(LaneId, U32, ) |
| 501 | OPCODE(VoteAll, U1, U1, ) | 539 | OPCODE(VoteAll, U1, U1, ) |
diff --git a/src/shader_recompiler/frontend/maxwell/maxwell.inc b/src/shader_recompiler/frontend/maxwell/maxwell.inc index c759bd4d4..2fee591bb 100644 --- a/src/shader_recompiler/frontend/maxwell/maxwell.inc +++ b/src/shader_recompiler/frontend/maxwell/maxwell.inc | |||
| @@ -244,7 +244,8 @@ INST(STG, "STG", "1110 1110 1101 1---") | |||
| 244 | INST(STL, "STL", "1110 1111 0101 0---") | 244 | INST(STL, "STL", "1110 1111 0101 0---") |
| 245 | INST(STP, "STP", "1110 1110 1010 0---") | 245 | INST(STP, "STP", "1110 1110 1010 0---") |
| 246 | INST(STS, "STS", "1110 1111 0101 1---") | 246 | INST(STS, "STS", "1110 1111 0101 1---") |
| 247 | INST(SUATOM_cas, "SUATOM", "1110 1010 ---- ----") | 247 | INST(SUATOM, "SUATOM", "1110 1010 0--- ----") |
| 248 | INST(SUATOM_cas, "SUATOM_cas", "1110 1010 1--- ----") | ||
| 248 | INST(SULD, "SULD", "1110 1011 000- ----") | 249 | INST(SULD, "SULD", "1110 1011 000- ----") |
| 249 | INST(SURED, "SURED", "1110 1011 010- ----") | 250 | INST(SURED, "SURED", "1110 1011 010- ----") |
| 250 | INST(SUST, "SUST", "1110 1011 001- ----") | 251 | INST(SUST, "SUST", "1110 1011 001- ----") |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h index bf7d1bae8..335e4f24f 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h | |||
| @@ -303,6 +303,7 @@ public: | |||
| 303 | void STL(u64 insn); | 303 | void STL(u64 insn); |
| 304 | void STP(u64 insn); | 304 | void STP(u64 insn); |
| 305 | void STS(u64 insn); | 305 | void STS(u64 insn); |
| 306 | void SUATOM(u64 insn); | ||
| 306 | void SUATOM_cas(u64 insn); | 307 | void SUATOM_cas(u64 insn); |
| 307 | void SULD(u64 insn); | 308 | void SULD(u64 insn); |
| 308 | void SURED(u64 insn); | 309 | void SURED(u64 insn); |
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 a4f99bbbe..7e26ab359 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp | |||
| @@ -249,10 +249,6 @@ void TranslatorVisitor::SUATOM_cas(u64) { | |||
| 249 | ThrowNotImplemented(Opcode::SUATOM_cas); | 249 | ThrowNotImplemented(Opcode::SUATOM_cas); |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | void TranslatorVisitor::SURED(u64) { | ||
| 253 | ThrowNotImplemented(Opcode::SURED); | ||
| 254 | } | ||
| 255 | |||
| 256 | void TranslatorVisitor::SYNC(u64) { | 252 | void TranslatorVisitor::SYNC(u64) { |
| 257 | ThrowNotImplemented(Opcode::SYNC); | 253 | ThrowNotImplemented(Opcode::SYNC); |
| 258 | } | 254 | } |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/surface_atomic_operations.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/surface_atomic_operations.cpp new file mode 100644 index 000000000..994bdc3eb --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/surface_atomic_operations.cpp | |||
| @@ -0,0 +1,204 @@ | |||
| 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 <array> | ||
| 6 | #include <bit> | ||
| 7 | |||
| 8 | #include "common/bit_field.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "shader_recompiler/frontend/ir/modifiers.h" | ||
| 11 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 12 | |||
| 13 | namespace Shader::Maxwell { | ||
| 14 | namespace { | ||
| 15 | enum class Type : u64 { | ||
| 16 | _1D, | ||
| 17 | BUFFER_1D, | ||
| 18 | ARRAY_1D, | ||
| 19 | _2D, | ||
| 20 | ARRAY_2D, | ||
| 21 | _3D, | ||
| 22 | }; | ||
| 23 | |||
| 24 | enum class Size : u64 { | ||
| 25 | U32, | ||
| 26 | S32, | ||
| 27 | U64, | ||
| 28 | S64, | ||
| 29 | F32FTZRN, | ||
| 30 | F16x2FTZRN, | ||
| 31 | SD32, | ||
| 32 | SD64, | ||
| 33 | }; | ||
| 34 | |||
| 35 | enum class AtomicOp : u64 { | ||
| 36 | ADD, | ||
| 37 | MIN, | ||
| 38 | MAX, | ||
| 39 | INC, | ||
| 40 | DEC, | ||
| 41 | AND, | ||
| 42 | OR, | ||
| 43 | XOR, | ||
| 44 | EXCH, | ||
| 45 | }; | ||
| 46 | |||
| 47 | enum class Clamp : u64 { | ||
| 48 | IGN, | ||
| 49 | Default, | ||
| 50 | TRAP, | ||
| 51 | }; | ||
| 52 | |||
| 53 | TextureType GetType(Type type) { | ||
| 54 | switch (type) { | ||
| 55 | case Type::_1D: | ||
| 56 | return TextureType::Color1D; | ||
| 57 | case Type::BUFFER_1D: | ||
| 58 | return TextureType::Buffer; | ||
| 59 | case Type::ARRAY_1D: | ||
| 60 | return TextureType::ColorArray1D; | ||
| 61 | case Type::_2D: | ||
| 62 | return TextureType::Color2D; | ||
| 63 | case Type::ARRAY_2D: | ||
| 64 | return TextureType::ColorArray2D; | ||
| 65 | case Type::_3D: | ||
| 66 | return TextureType::Color3D; | ||
| 67 | } | ||
| 68 | throw NotImplementedException("Invalid type {}", type); | ||
| 69 | } | ||
| 70 | |||
| 71 | IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, Type type) { | ||
| 72 | const auto array{[&](int index) { | ||
| 73 | return v.ir.BitFieldExtract(v.X(reg + index), v.ir.Imm32(0), v.ir.Imm32(16)); | ||
| 74 | }}; | ||
| 75 | switch (type) { | ||
| 76 | case Type::_1D: | ||
| 77 | case Type::BUFFER_1D: | ||
| 78 | return v.X(reg); | ||
| 79 | default: | ||
| 80 | break; | ||
| 81 | } | ||
| 82 | throw NotImplementedException("Invalid type {}", type); | ||
| 83 | } | ||
| 84 | |||
| 85 | IR::Value ApplyAtomicOp(IR::IREmitter& ir, const IR::U32& handle, const IR::Value& coords, | ||
| 86 | const IR::Value& op_b, IR::TextureInstInfo info, AtomicOp op, | ||
| 87 | bool is_signed) { | ||
| 88 | switch (op) { | ||
| 89 | case AtomicOp::ADD: | ||
| 90 | return ir.ImageAtomicIAdd(handle, coords, op_b, info); | ||
| 91 | case AtomicOp::MIN: | ||
| 92 | return ir.ImageAtomicIMin(handle, coords, op_b, is_signed, info); | ||
| 93 | case AtomicOp::MAX: | ||
| 94 | return ir.ImageAtomicIMax(handle, coords, op_b, is_signed, info); | ||
| 95 | case AtomicOp::INC: | ||
| 96 | return ir.ImageAtomicInc(handle, coords, op_b, info); | ||
| 97 | case AtomicOp::DEC: | ||
| 98 | return ir.ImageAtomicDec(handle, coords, op_b, info); | ||
| 99 | case AtomicOp::AND: | ||
| 100 | return ir.ImageAtomicAnd(handle, coords, op_b, info); | ||
| 101 | case AtomicOp::OR: | ||
| 102 | return ir.ImageAtomicOr(handle, coords, op_b, info); | ||
| 103 | case AtomicOp::XOR: | ||
| 104 | return ir.ImageAtomicXor(handle, coords, op_b, info); | ||
| 105 | case AtomicOp::EXCH: | ||
| 106 | return ir.ImageAtomicExchange(handle, coords, op_b, info); | ||
| 107 | default: | ||
| 108 | throw NotImplementedException("Atomic Operation {}", op); | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | ImageFormat Format(Size size) { | ||
| 113 | switch (size) { | ||
| 114 | case Size::U32: | ||
| 115 | case Size::S32: | ||
| 116 | case Size::SD32: | ||
| 117 | return ImageFormat::R32_UINT; | ||
| 118 | default: | ||
| 119 | break; | ||
| 120 | } | ||
| 121 | throw NotImplementedException("Invalid size {}", size); | ||
| 122 | } | ||
| 123 | |||
| 124 | bool IsSizeInt32(Size size) { | ||
| 125 | switch (size) { | ||
| 126 | case Size::U32: | ||
| 127 | case Size::S32: | ||
| 128 | case Size::SD32: | ||
| 129 | return true; | ||
| 130 | default: | ||
| 131 | return false; | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | void ImageAtomOp(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg, IR::Reg coord_reg, | ||
| 136 | IR::Reg bindless_reg, AtomicOp op, Clamp clamp, Size size, Type type, | ||
| 137 | u64 bound_offset, bool is_bindless, bool write_result) { | ||
| 138 | if (clamp != Clamp::IGN) { | ||
| 139 | throw NotImplementedException("Clamp {}", clamp); | ||
| 140 | } | ||
| 141 | if (!IsSizeInt32(size)) { | ||
| 142 | throw NotImplementedException("Size {}", size); | ||
| 143 | } | ||
| 144 | const bool is_signed{size == Size::S32}; | ||
| 145 | const ImageFormat format{Format(size)}; | ||
| 146 | const TextureType tex_type{GetType(type)}; | ||
| 147 | const IR::Value coords{MakeCoords(v, coord_reg, type)}; | ||
| 148 | |||
| 149 | const IR::U32 handle{is_bindless != 0 ? v.X(bindless_reg) | ||
| 150 | : v.ir.Imm32(static_cast<u32>(bound_offset * 4))}; | ||
| 151 | IR::TextureInstInfo info{}; | ||
| 152 | info.type.Assign(tex_type); | ||
| 153 | info.image_format.Assign(format); | ||
| 154 | |||
| 155 | // TODO: float/64-bit operand | ||
| 156 | const IR::Value op_b{v.X(operand_reg)}; | ||
| 157 | const IR::Value color{ApplyAtomicOp(v.ir, handle, coords, op_b, info, op, is_signed)}; | ||
| 158 | |||
| 159 | if (write_result) { | ||
| 160 | v.X(dest_reg, IR::U32{color}); | ||
| 161 | } | ||
| 162 | } | ||
| 163 | } // Anonymous namespace | ||
| 164 | |||
| 165 | void TranslatorVisitor::SUATOM(u64 insn) { | ||
| 166 | union { | ||
| 167 | u64 raw; | ||
| 168 | BitField<54, 1, u64> is_bindless; | ||
| 169 | BitField<29, 4, AtomicOp> op; | ||
| 170 | BitField<33, 3, Type> type; | ||
| 171 | BitField<51, 3, Size> size; | ||
| 172 | BitField<49, 2, Clamp> clamp; | ||
| 173 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 174 | BitField<8, 8, IR::Reg> coord_reg; | ||
| 175 | BitField<20, 8, IR::Reg> operand_reg; | ||
| 176 | BitField<36, 13, u64> bound_offset; // !is_bindless | ||
| 177 | BitField<39, 8, IR::Reg> bindless_reg; // is_bindless | ||
| 178 | } const suatom{insn}; | ||
| 179 | |||
| 180 | ImageAtomOp(*this, suatom.dest_reg, suatom.operand_reg, suatom.coord_reg, suatom.bindless_reg, | ||
| 181 | suatom.op, suatom.clamp, suatom.size, suatom.type, suatom.bound_offset, | ||
| 182 | suatom.is_bindless != 0, true); | ||
| 183 | } | ||
| 184 | |||
| 185 | void TranslatorVisitor::SURED(u64 insn) { | ||
| 186 | // TODO: confirm offsets | ||
| 187 | union { | ||
| 188 | u64 raw; | ||
| 189 | BitField<51, 1, u64> is_bound; | ||
| 190 | BitField<21, 3, AtomicOp> op; | ||
| 191 | BitField<33, 3, Type> type; | ||
| 192 | BitField<20, 3, Size> size; | ||
| 193 | BitField<49, 2, Clamp> clamp; | ||
| 194 | BitField<0, 8, IR::Reg> operand_reg; | ||
| 195 | BitField<8, 8, IR::Reg> coord_reg; | ||
| 196 | BitField<36, 13, u64> bound_offset; // is_bound | ||
| 197 | BitField<39, 8, IR::Reg> bindless_reg; // !is_bound | ||
| 198 | } const sured{insn}; | ||
| 199 | ImageAtomOp(*this, IR::Reg::RZ, sured.operand_reg, sured.coord_reg, sured.bindless_reg, | ||
| 200 | sured.op, sured.clamp, sured.size, sured.type, sured.bound_offset, | ||
| 201 | sured.is_bound == 0, false); | ||
| 202 | } | ||
| 203 | |||
| 204 | } // namespace Shader::Maxwell | ||