diff options
| author | 2021-04-23 17:47:54 -0400 | |
|---|---|---|
| committer | 2021-07-22 21:51:30 -0400 | |
| commit | 7ecc6de56ae01602b25408db8b6658d7a41a419a (patch) | |
| tree | 2bff17b5b55e9f37ac5e4031c77962216813d5d5 | |
| parent | shader: Initial OpenGL implementation (diff) | |
| download | yuzu-7ecc6de56ae01602b25408db8b6658d7a41a419a.tar.gz yuzu-7ecc6de56ae01602b25408db8b6658d7a41a419a.tar.xz yuzu-7ecc6de56ae01602b25408db8b6658d7a41a419a.zip | |
shader: Implement Int32 SUATOM/SURED
17 files changed, 733 insertions, 6 deletions
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index f20031d98..0bcd714d6 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -12,6 +12,7 @@ add_library(shader_recompiler STATIC | |||
| 12 | backend/spirv/emit_spirv_convert.cpp | 12 | backend/spirv/emit_spirv_convert.cpp |
| 13 | backend/spirv/emit_spirv_floating_point.cpp | 13 | backend/spirv/emit_spirv_floating_point.cpp |
| 14 | backend/spirv/emit_spirv_image.cpp | 14 | backend/spirv/emit_spirv_image.cpp |
| 15 | backend/spirv/emit_spirv_image_atomic.cpp | ||
| 15 | backend/spirv/emit_spirv_integer.cpp | 16 | backend/spirv/emit_spirv_integer.cpp |
| 16 | backend/spirv/emit_spirv_logical.cpp | 17 | backend/spirv/emit_spirv_logical.cpp |
| 17 | backend/spirv/emit_spirv_memory.cpp | 18 | backend/spirv/emit_spirv_memory.cpp |
| @@ -138,6 +139,7 @@ add_library(shader_recompiler STATIC | |||
| 138 | frontend/maxwell/translate/impl/predicate_set_predicate.cpp | 139 | frontend/maxwell/translate/impl/predicate_set_predicate.cpp |
| 139 | frontend/maxwell/translate/impl/predicate_set_register.cpp | 140 | frontend/maxwell/translate/impl/predicate_set_register.cpp |
| 140 | frontend/maxwell/translate/impl/select_source_with_predicate.cpp | 141 | frontend/maxwell/translate/impl/select_source_with_predicate.cpp |
| 142 | frontend/maxwell/translate/impl/surface_atomic_operations.cpp | ||
| 141 | frontend/maxwell/translate/impl/surface_load_store.cpp | 143 | frontend/maxwell/translate/impl/surface_load_store.cpp |
| 142 | frontend/maxwell/translate/impl/texture_fetch.cpp | 144 | frontend/maxwell/translate/impl/texture_fetch.cpp |
| 143 | frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp | 145 | frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp |
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index e9ffe4955..549df0d4b 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -1107,6 +1107,9 @@ void EmitContext::DefineTextures(const Info& info, u32& binding) { | |||
| 1107 | } | 1107 | } |
| 1108 | ++binding; | 1108 | ++binding; |
| 1109 | } | 1109 | } |
| 1110 | if (info.uses_atomic_image_u32) { | ||
| 1111 | image_u32 = TypePointer(spv::StorageClass::Image, U32[1]); | ||
| 1112 | } | ||
| 1110 | } | 1113 | } |
| 1111 | 1114 | ||
| 1112 | void EmitContext::DefineImages(const Info& info, u32& binding) { | 1115 | void EmitContext::DefineImages(const Info& info, u32& binding) { |
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h index 823ed8525..30b08104d 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.h +++ b/src/shader_recompiler/backend/spirv/emit_context.h | |||
| @@ -198,6 +198,7 @@ public: | |||
| 198 | 198 | ||
| 199 | Id image_buffer_type{}; | 199 | Id image_buffer_type{}; |
| 200 | Id sampled_texture_buffer_type{}; | 200 | Id sampled_texture_buffer_type{}; |
| 201 | Id image_u32{}; | ||
| 201 | 202 | ||
| 202 | std::array<UniformDefinitions, Info::MAX_CBUFS> cbufs{}; | 203 | std::array<UniformDefinitions, Info::MAX_CBUFS> cbufs{}; |
| 203 | std::array<StorageDefinitions, Info::MAX_SSBOS> ssbos{}; | 204 | std::array<StorageDefinitions, Info::MAX_SSBOS> ssbos{}; |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 745a834e3..3f9adc902 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp | |||
| @@ -335,6 +335,9 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct | |||
| 335 | if (info.uses_typeless_image_writes) { | 335 | if (info.uses_typeless_image_writes) { |
| 336 | ctx.AddCapability(spv::Capability::StorageImageWriteWithoutFormat); | 336 | ctx.AddCapability(spv::Capability::StorageImageWriteWithoutFormat); |
| 337 | } | 337 | } |
| 338 | if (info.uses_image_buffers) { | ||
| 339 | ctx.AddCapability(spv::Capability::ImageBuffer); | ||
| 340 | } | ||
| 338 | if (info.uses_sample_id) { | 341 | if (info.uses_sample_id) { |
| 339 | ctx.AddCapability(spv::Capability::SampleRateShading); | 342 | ctx.AddCapability(spv::Capability::SampleRateShading); |
| 340 | } | 343 | } |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index 8f6482b7b..47d62b190 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h | |||
| @@ -509,6 +509,50 @@ Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I | |||
| 509 | Id derivates, Id offset, Id lod_clamp); | 509 | Id derivates, Id offset, Id lod_clamp); |
| 510 | Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); | 510 | Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); |
| 511 | void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color); | 511 | void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color); |
| 512 | Id EmitBindlessImageAtomicIAdd32(EmitContext&); | ||
| 513 | Id EmitBindlessImageAtomicSMin32(EmitContext&); | ||
| 514 | Id EmitBindlessImageAtomicUMin32(EmitContext&); | ||
| 515 | Id EmitBindlessImageAtomicSMax32(EmitContext&); | ||
| 516 | Id EmitBindlessImageAtomicUMax32(EmitContext&); | ||
| 517 | Id EmitBindlessImageAtomicInc32(EmitContext&); | ||
| 518 | Id EmitBindlessImageAtomicDec32(EmitContext&); | ||
| 519 | Id EmitBindlessImageAtomicAnd32(EmitContext&); | ||
| 520 | Id EmitBindlessImageAtomicOr32(EmitContext&); | ||
| 521 | Id EmitBindlessImageAtomicXor32(EmitContext&); | ||
| 522 | Id EmitBindlessImageAtomicExchange32(EmitContext&); | ||
| 523 | Id EmitBoundImageAtomicIAdd32(EmitContext&); | ||
| 524 | Id EmitBoundImageAtomicSMin32(EmitContext&); | ||
| 525 | Id EmitBoundImageAtomicUMin32(EmitContext&); | ||
| 526 | Id EmitBoundImageAtomicSMax32(EmitContext&); | ||
| 527 | Id EmitBoundImageAtomicUMax32(EmitContext&); | ||
| 528 | Id EmitBoundImageAtomicInc32(EmitContext&); | ||
| 529 | Id EmitBoundImageAtomicDec32(EmitContext&); | ||
| 530 | Id EmitBoundImageAtomicAnd32(EmitContext&); | ||
| 531 | Id EmitBoundImageAtomicOr32(EmitContext&); | ||
| 532 | Id EmitBoundImageAtomicXor32(EmitContext&); | ||
| 533 | Id EmitBoundImageAtomicExchange32(EmitContext&); | ||
| 534 | Id EmitImageAtomicIAdd32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 535 | Id value); | ||
| 536 | Id EmitImageAtomicSMin32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 537 | Id value); | ||
| 538 | Id EmitImageAtomicUMin32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 539 | Id value); | ||
| 540 | Id EmitImageAtomicSMax32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 541 | Id value); | ||
| 542 | Id EmitImageAtomicUMax32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 543 | Id value); | ||
| 544 | Id EmitImageAtomicInc32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 545 | Id value); | ||
| 546 | Id EmitImageAtomicDec32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 547 | Id value); | ||
| 548 | Id EmitImageAtomicAnd32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 549 | Id value); | ||
| 550 | Id EmitImageAtomicOr32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 551 | Id value); | ||
| 552 | Id EmitImageAtomicXor32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 553 | Id value); | ||
| 554 | Id EmitImageAtomicExchange32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 555 | Id value); | ||
| 512 | Id EmitLaneId(EmitContext& ctx); | 556 | Id EmitLaneId(EmitContext& ctx); |
| 513 | Id EmitVoteAll(EmitContext& ctx, Id pred); | 557 | Id EmitVoteAll(EmitContext& ctx, Id pred); |
| 514 | Id EmitVoteAny(EmitContext& ctx, Id pred); | 558 | Id EmitVoteAny(EmitContext& ctx, Id pred); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image_atomic.cpp new file mode 100644 index 000000000..05bed22b9 --- /dev/null +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image_atomic.cpp | |||
| @@ -0,0 +1,182 @@ | |||
| 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/backend/spirv/emit_spirv.h" | ||
| 6 | #include "shader_recompiler/frontend/ir/modifiers.h" | ||
| 7 | |||
| 8 | namespace Shader::Backend::SPIRV { | ||
| 9 | namespace { | ||
| 10 | Id Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { | ||
| 11 | if (!index.IsImmediate()) { | ||
| 12 | throw NotImplementedException("Indirect image indexing"); | ||
| 13 | } | ||
| 14 | if (info.type == TextureType::Buffer) { | ||
| 15 | const ImageBufferDefinition def{ctx.image_buffers.at(index.U32())}; | ||
| 16 | return def.id; | ||
| 17 | } else { | ||
| 18 | const ImageDefinition def{ctx.images.at(index.U32())}; | ||
| 19 | return def.id; | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | std::pair<Id, Id> AtomicArgs(EmitContext& ctx) { | ||
| 24 | const Id scope{ctx.Const(static_cast<u32>(spv::Scope::Device))}; | ||
| 25 | const Id semantics{ctx.u32_zero_value}; | ||
| 26 | return {scope, semantics}; | ||
| 27 | } | ||
| 28 | |||
| 29 | Id ImageAtomicU32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id value, | ||
| 30 | Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id)) { | ||
| 31 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | ||
| 32 | const Id image{Image(ctx, index, info)}; | ||
| 33 | const Id pointer{ctx.OpImageTexelPointer(ctx.image_u32, image, coords, ctx.Const(0U))}; | ||
| 34 | const auto [scope, semantics]{AtomicArgs(ctx)}; | ||
| 35 | return (ctx.*atomic_func)(ctx.U32[1], pointer, scope, semantics, value); | ||
| 36 | } | ||
| 37 | } // Anonymous namespace | ||
| 38 | |||
| 39 | Id EmitImageAtomicIAdd32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 40 | Id value) { | ||
| 41 | return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicIAdd); | ||
| 42 | } | ||
| 43 | |||
| 44 | Id EmitImageAtomicSMin32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 45 | Id value) { | ||
| 46 | return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicSMin); | ||
| 47 | } | ||
| 48 | |||
| 49 | Id EmitImageAtomicUMin32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 50 | Id value) { | ||
| 51 | return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicUMin); | ||
| 52 | } | ||
| 53 | |||
| 54 | Id EmitImageAtomicSMax32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 55 | Id value) { | ||
| 56 | return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicSMax); | ||
| 57 | } | ||
| 58 | |||
| 59 | Id EmitImageAtomicUMax32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 60 | Id value) { | ||
| 61 | return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicUMax); | ||
| 62 | } | ||
| 63 | |||
| 64 | Id EmitImageAtomicInc32(EmitContext&, IR::Inst*, const IR::Value&, Id, Id) { | ||
| 65 | // TODO: This is not yet implemented | ||
| 66 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 67 | } | ||
| 68 | |||
| 69 | Id EmitImageAtomicDec32(EmitContext&, IR::Inst*, const IR::Value&, Id, Id) { | ||
| 70 | // TODO: This is not yet implemented | ||
| 71 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 72 | } | ||
| 73 | |||
| 74 | Id EmitImageAtomicAnd32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 75 | Id value) { | ||
| 76 | return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicAnd); | ||
| 77 | } | ||
| 78 | |||
| 79 | Id EmitImageAtomicOr32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 80 | Id value) { | ||
| 81 | return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicOr); | ||
| 82 | } | ||
| 83 | |||
| 84 | Id EmitImageAtomicXor32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 85 | Id value) { | ||
| 86 | return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicXor); | ||
| 87 | } | ||
| 88 | |||
| 89 | Id EmitImageAtomicExchange32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | ||
| 90 | Id value) { | ||
| 91 | return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicExchange); | ||
| 92 | } | ||
| 93 | |||
| 94 | Id EmitBindlessImageAtomicIAdd32(EmitContext&) { | ||
| 95 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 96 | } | ||
| 97 | |||
| 98 | Id EmitBindlessImageAtomicSMin32(EmitContext&) { | ||
| 99 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 100 | } | ||
| 101 | |||
| 102 | Id EmitBindlessImageAtomicUMin32(EmitContext&) { | ||
| 103 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 104 | } | ||
| 105 | |||
| 106 | Id EmitBindlessImageAtomicSMax32(EmitContext&) { | ||
| 107 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 108 | } | ||
| 109 | |||
| 110 | Id EmitBindlessImageAtomicUMax32(EmitContext&) { | ||
| 111 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 112 | } | ||
| 113 | |||
| 114 | Id EmitBindlessImageAtomicInc32(EmitContext&) { | ||
| 115 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 116 | } | ||
| 117 | |||
| 118 | Id EmitBindlessImageAtomicDec32(EmitContext&) { | ||
| 119 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 120 | } | ||
| 121 | |||
| 122 | Id EmitBindlessImageAtomicAnd32(EmitContext&) { | ||
| 123 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 124 | } | ||
| 125 | |||
| 126 | Id EmitBindlessImageAtomicOr32(EmitContext&) { | ||
| 127 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 128 | } | ||
| 129 | |||
| 130 | Id EmitBindlessImageAtomicXor32(EmitContext&) { | ||
| 131 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 132 | } | ||
| 133 | |||
| 134 | Id EmitBindlessImageAtomicExchange32(EmitContext&) { | ||
| 135 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 136 | } | ||
| 137 | |||
| 138 | Id EmitBoundImageAtomicIAdd32(EmitContext&) { | ||
| 139 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 140 | } | ||
| 141 | |||
| 142 | Id EmitBoundImageAtomicSMin32(EmitContext&) { | ||
| 143 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 144 | } | ||
| 145 | |||
| 146 | Id EmitBoundImageAtomicUMin32(EmitContext&) { | ||
| 147 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 148 | } | ||
| 149 | |||
| 150 | Id EmitBoundImageAtomicSMax32(EmitContext&) { | ||
| 151 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 152 | } | ||
| 153 | |||
| 154 | Id EmitBoundImageAtomicUMax32(EmitContext&) { | ||
| 155 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 156 | } | ||
| 157 | |||
| 158 | Id EmitBoundImageAtomicInc32(EmitContext&) { | ||
| 159 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 160 | } | ||
| 161 | |||
| 162 | Id EmitBoundImageAtomicDec32(EmitContext&) { | ||
| 163 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 164 | } | ||
| 165 | |||
| 166 | Id EmitBoundImageAtomicAnd32(EmitContext&) { | ||
| 167 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 168 | } | ||
| 169 | |||
| 170 | Id EmitBoundImageAtomicOr32(EmitContext&) { | ||
| 171 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 172 | } | ||
| 173 | |||
| 174 | Id EmitBoundImageAtomicXor32(EmitContext&) { | ||
| 175 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 176 | } | ||
| 177 | |||
| 178 | Id EmitBoundImageAtomicExchange32(EmitContext&) { | ||
| 179 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 180 | } | ||
| 181 | |||
| 182 | } // namespace Shader::Backend::SPIRV | ||
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 | ||
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index bb4aeb57c..7d8794a7e 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -565,6 +565,7 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 565 | case IR::Opcode::ImageWrite: { | 565 | case IR::Opcode::ImageWrite: { |
| 566 | const auto flags{inst.Flags<IR::TextureInstInfo>()}; | 566 | const auto flags{inst.Flags<IR::TextureInstInfo>()}; |
| 567 | info.uses_typeless_image_writes |= flags.image_format == ImageFormat::Typeless; | 567 | info.uses_typeless_image_writes |= flags.image_format == ImageFormat::Typeless; |
| 568 | info.uses_image_buffers |= flags.type == TextureType::Buffer; | ||
| 568 | break; | 569 | break; |
| 569 | } | 570 | } |
| 570 | case IR::Opcode::SubgroupEqMask: | 571 | case IR::Opcode::SubgroupEqMask: |
| @@ -696,6 +697,41 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 696 | info.used_storage_buffer_types |= IR::Type::U64; | 697 | info.used_storage_buffer_types |= IR::Type::U64; |
| 697 | info.uses_int64_bit_atomics = true; | 698 | info.uses_int64_bit_atomics = true; |
| 698 | break; | 699 | break; |
| 700 | case IR::Opcode::BindlessImageAtomicIAdd32: | ||
| 701 | case IR::Opcode::BindlessImageAtomicSMin32: | ||
| 702 | case IR::Opcode::BindlessImageAtomicUMin32: | ||
| 703 | case IR::Opcode::BindlessImageAtomicSMax32: | ||
| 704 | case IR::Opcode::BindlessImageAtomicUMax32: | ||
| 705 | case IR::Opcode::BindlessImageAtomicInc32: | ||
| 706 | case IR::Opcode::BindlessImageAtomicDec32: | ||
| 707 | case IR::Opcode::BindlessImageAtomicAnd32: | ||
| 708 | case IR::Opcode::BindlessImageAtomicOr32: | ||
| 709 | case IR::Opcode::BindlessImageAtomicXor32: | ||
| 710 | case IR::Opcode::BindlessImageAtomicExchange32: | ||
| 711 | case IR::Opcode::BoundImageAtomicIAdd32: | ||
| 712 | case IR::Opcode::BoundImageAtomicSMin32: | ||
| 713 | case IR::Opcode::BoundImageAtomicUMin32: | ||
| 714 | case IR::Opcode::BoundImageAtomicSMax32: | ||
| 715 | case IR::Opcode::BoundImageAtomicUMax32: | ||
| 716 | case IR::Opcode::BoundImageAtomicInc32: | ||
| 717 | case IR::Opcode::BoundImageAtomicDec32: | ||
| 718 | case IR::Opcode::BoundImageAtomicAnd32: | ||
| 719 | case IR::Opcode::BoundImageAtomicOr32: | ||
| 720 | case IR::Opcode::BoundImageAtomicXor32: | ||
| 721 | case IR::Opcode::BoundImageAtomicExchange32: | ||
| 722 | case IR::Opcode::ImageAtomicIAdd32: | ||
| 723 | case IR::Opcode::ImageAtomicSMin32: | ||
| 724 | case IR::Opcode::ImageAtomicUMin32: | ||
| 725 | case IR::Opcode::ImageAtomicSMax32: | ||
| 726 | case IR::Opcode::ImageAtomicUMax32: | ||
| 727 | case IR::Opcode::ImageAtomicInc32: | ||
| 728 | case IR::Opcode::ImageAtomicDec32: | ||
| 729 | case IR::Opcode::ImageAtomicAnd32: | ||
| 730 | case IR::Opcode::ImageAtomicOr32: | ||
| 731 | case IR::Opcode::ImageAtomicXor32: | ||
| 732 | case IR::Opcode::ImageAtomicExchange32: | ||
| 733 | info.uses_atomic_image_u32 = true; | ||
| 734 | break; | ||
| 699 | default: | 735 | default: |
| 700 | break; | 736 | break; |
| 701 | } | 737 | } |
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index 2b38bcf42..9e0a2fb09 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp | |||
| @@ -76,6 +76,39 @@ IR::Opcode IndexedInstruction(const IR::Inst& inst) { | |||
| 76 | case IR::Opcode::BoundImageWrite: | 76 | case IR::Opcode::BoundImageWrite: |
| 77 | case IR::Opcode::BindlessImageWrite: | 77 | case IR::Opcode::BindlessImageWrite: |
| 78 | return IR::Opcode::ImageWrite; | 78 | return IR::Opcode::ImageWrite; |
| 79 | case IR::Opcode::BoundImageAtomicIAdd32: | ||
| 80 | case IR::Opcode::BindlessImageAtomicIAdd32: | ||
| 81 | return IR::Opcode::ImageAtomicIAdd32; | ||
| 82 | case IR::Opcode::BoundImageAtomicSMin32: | ||
| 83 | case IR::Opcode::BindlessImageAtomicSMin32: | ||
| 84 | return IR::Opcode::ImageAtomicSMin32; | ||
| 85 | case IR::Opcode::BoundImageAtomicUMin32: | ||
| 86 | case IR::Opcode::BindlessImageAtomicUMin32: | ||
| 87 | return IR::Opcode::ImageAtomicUMin32; | ||
| 88 | case IR::Opcode::BoundImageAtomicSMax32: | ||
| 89 | case IR::Opcode::BindlessImageAtomicSMax32: | ||
| 90 | return IR::Opcode::ImageAtomicSMax32; | ||
| 91 | case IR::Opcode::BoundImageAtomicUMax32: | ||
| 92 | case IR::Opcode::BindlessImageAtomicUMax32: | ||
| 93 | return IR::Opcode::ImageAtomicUMax32; | ||
| 94 | case IR::Opcode::BoundImageAtomicInc32: | ||
| 95 | case IR::Opcode::BindlessImageAtomicInc32: | ||
| 96 | return IR::Opcode::ImageAtomicInc32; | ||
| 97 | case IR::Opcode::BoundImageAtomicDec32: | ||
| 98 | case IR::Opcode::BindlessImageAtomicDec32: | ||
| 99 | return IR::Opcode::ImageAtomicDec32; | ||
| 100 | case IR::Opcode::BoundImageAtomicAnd32: | ||
| 101 | case IR::Opcode::BindlessImageAtomicAnd32: | ||
| 102 | return IR::Opcode::ImageAtomicAnd32; | ||
| 103 | case IR::Opcode::BoundImageAtomicOr32: | ||
| 104 | case IR::Opcode::BindlessImageAtomicOr32: | ||
| 105 | return IR::Opcode::ImageAtomicOr32; | ||
| 106 | case IR::Opcode::BoundImageAtomicXor32: | ||
| 107 | case IR::Opcode::BindlessImageAtomicXor32: | ||
| 108 | return IR::Opcode::ImageAtomicXor32; | ||
| 109 | case IR::Opcode::BoundImageAtomicExchange32: | ||
| 110 | case IR::Opcode::BindlessImageAtomicExchange32: | ||
| 111 | return IR::Opcode::ImageAtomicExchange32; | ||
| 79 | default: | 112 | default: |
| 80 | return IR::Opcode::Void; | 113 | return IR::Opcode::Void; |
| 81 | } | 114 | } |
| @@ -95,6 +128,17 @@ bool IsBindless(const IR::Inst& inst) { | |||
| 95 | case IR::Opcode::BindlessImageGradient: | 128 | case IR::Opcode::BindlessImageGradient: |
| 96 | case IR::Opcode::BindlessImageRead: | 129 | case IR::Opcode::BindlessImageRead: |
| 97 | case IR::Opcode::BindlessImageWrite: | 130 | case IR::Opcode::BindlessImageWrite: |
| 131 | case IR::Opcode::BindlessImageAtomicIAdd32: | ||
| 132 | case IR::Opcode::BindlessImageAtomicSMin32: | ||
| 133 | case IR::Opcode::BindlessImageAtomicUMin32: | ||
| 134 | case IR::Opcode::BindlessImageAtomicSMax32: | ||
| 135 | case IR::Opcode::BindlessImageAtomicUMax32: | ||
| 136 | case IR::Opcode::BindlessImageAtomicInc32: | ||
| 137 | case IR::Opcode::BindlessImageAtomicDec32: | ||
| 138 | case IR::Opcode::BindlessImageAtomicAnd32: | ||
| 139 | case IR::Opcode::BindlessImageAtomicOr32: | ||
| 140 | case IR::Opcode::BindlessImageAtomicXor32: | ||
| 141 | case IR::Opcode::BindlessImageAtomicExchange32: | ||
| 98 | return true; | 142 | return true; |
| 99 | case IR::Opcode::BoundImageSampleImplicitLod: | 143 | case IR::Opcode::BoundImageSampleImplicitLod: |
| 100 | case IR::Opcode::BoundImageSampleExplicitLod: | 144 | case IR::Opcode::BoundImageSampleExplicitLod: |
| @@ -108,6 +152,17 @@ bool IsBindless(const IR::Inst& inst) { | |||
| 108 | case IR::Opcode::BoundImageGradient: | 152 | case IR::Opcode::BoundImageGradient: |
| 109 | case IR::Opcode::BoundImageRead: | 153 | case IR::Opcode::BoundImageRead: |
| 110 | case IR::Opcode::BoundImageWrite: | 154 | case IR::Opcode::BoundImageWrite: |
| 155 | case IR::Opcode::BoundImageAtomicIAdd32: | ||
| 156 | case IR::Opcode::BoundImageAtomicSMin32: | ||
| 157 | case IR::Opcode::BoundImageAtomicUMin32: | ||
| 158 | case IR::Opcode::BoundImageAtomicSMax32: | ||
| 159 | case IR::Opcode::BoundImageAtomicUMax32: | ||
| 160 | case IR::Opcode::BoundImageAtomicInc32: | ||
| 161 | case IR::Opcode::BoundImageAtomicDec32: | ||
| 162 | case IR::Opcode::BoundImageAtomicAnd32: | ||
| 163 | case IR::Opcode::BoundImageAtomicOr32: | ||
| 164 | case IR::Opcode::BoundImageAtomicXor32: | ||
| 165 | case IR::Opcode::BoundImageAtomicExchange32: | ||
| 111 | return false; | 166 | return false; |
| 112 | default: | 167 | default: |
| 113 | throw InvalidArgument("Invalid opcode {}", inst.GetOpcode()); | 168 | throw InvalidArgument("Invalid opcode {}", inst.GetOpcode()); |
| @@ -359,11 +414,22 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 359 | u32 index; | 414 | u32 index; |
| 360 | switch (inst->GetOpcode()) { | 415 | switch (inst->GetOpcode()) { |
| 361 | case IR::Opcode::ImageRead: | 416 | case IR::Opcode::ImageRead: |
| 417 | case IR::Opcode::ImageAtomicIAdd32: | ||
| 418 | case IR::Opcode::ImageAtomicSMin32: | ||
| 419 | case IR::Opcode::ImageAtomicUMin32: | ||
| 420 | case IR::Opcode::ImageAtomicSMax32: | ||
| 421 | case IR::Opcode::ImageAtomicUMax32: | ||
| 422 | case IR::Opcode::ImageAtomicInc32: | ||
| 423 | case IR::Opcode::ImageAtomicDec32: | ||
| 424 | case IR::Opcode::ImageAtomicAnd32: | ||
| 425 | case IR::Opcode::ImageAtomicOr32: | ||
| 426 | case IR::Opcode::ImageAtomicXor32: | ||
| 427 | case IR::Opcode::ImageAtomicExchange32: | ||
| 362 | case IR::Opcode::ImageWrite: { | 428 | case IR::Opcode::ImageWrite: { |
| 363 | if (cbuf.has_secondary) { | 429 | if (cbuf.has_secondary) { |
| 364 | throw NotImplementedException("Unexpected separate sampler"); | 430 | throw NotImplementedException("Unexpected separate sampler"); |
| 365 | } | 431 | } |
| 366 | const bool is_written{inst->GetOpcode() == IR::Opcode::ImageWrite}; | 432 | const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead}; |
| 367 | if (flags.type == TextureType::Buffer) { | 433 | if (flags.type == TextureType::Buffer) { |
| 368 | index = descriptors.Add(ImageBufferDescriptor{ | 434 | index = descriptors.Add(ImageBufferDescriptor{ |
| 369 | .format = flags.image_format, | 435 | .format = flags.image_format, |
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index cb1969b3a..2f6adf714 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -160,6 +160,7 @@ struct Info { | |||
| 160 | bool uses_derivatives{}; | 160 | bool uses_derivatives{}; |
| 161 | bool uses_typeless_image_reads{}; | 161 | bool uses_typeless_image_reads{}; |
| 162 | bool uses_typeless_image_writes{}; | 162 | bool uses_typeless_image_writes{}; |
| 163 | bool uses_image_buffers{}; | ||
| 163 | bool uses_shared_increment{}; | 164 | bool uses_shared_increment{}; |
| 164 | bool uses_shared_decrement{}; | 165 | bool uses_shared_decrement{}; |
| 165 | bool uses_global_increment{}; | 166 | bool uses_global_increment{}; |
| @@ -173,6 +174,7 @@ struct Info { | |||
| 173 | bool uses_atomic_f32x2_max{}; | 174 | bool uses_atomic_f32x2_max{}; |
| 174 | bool uses_int64_bit_atomics{}; | 175 | bool uses_int64_bit_atomics{}; |
| 175 | bool uses_global_memory{}; | 176 | bool uses_global_memory{}; |
| 177 | bool uses_atomic_image_u32{}; | ||
| 176 | 178 | ||
| 177 | IR::Type used_constant_buffer_types{}; | 179 | IR::Type used_constant_buffer_types{}; |
| 178 | IR::Type used_storage_buffer_types{}; | 180 | IR::Type used_storage_buffer_types{}; |