summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/shader_recompiler/CMakeLists.txt2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.cpp3
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.h1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp3
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.h44
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image_atomic.cpp182
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp89
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h26
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.cpp33
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc38
-rw-r--r--src/shader_recompiler/frontend/maxwell/maxwell.inc3
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/impl.h1
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp4
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/surface_atomic_operations.cpp204
-rw-r--r--src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp36
-rw-r--r--src/shader_recompiler/ir_opt/texture_pass.cpp68
-rw-r--r--src/shader_recompiler/shader_info.h2
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
1112void EmitContext::DefineImages(const Info& info, u32& binding) { 1115void 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);
510Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); 510Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
511void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color); 511void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color);
512Id EmitBindlessImageAtomicIAdd32(EmitContext&);
513Id EmitBindlessImageAtomicSMin32(EmitContext&);
514Id EmitBindlessImageAtomicUMin32(EmitContext&);
515Id EmitBindlessImageAtomicSMax32(EmitContext&);
516Id EmitBindlessImageAtomicUMax32(EmitContext&);
517Id EmitBindlessImageAtomicInc32(EmitContext&);
518Id EmitBindlessImageAtomicDec32(EmitContext&);
519Id EmitBindlessImageAtomicAnd32(EmitContext&);
520Id EmitBindlessImageAtomicOr32(EmitContext&);
521Id EmitBindlessImageAtomicXor32(EmitContext&);
522Id EmitBindlessImageAtomicExchange32(EmitContext&);
523Id EmitBoundImageAtomicIAdd32(EmitContext&);
524Id EmitBoundImageAtomicSMin32(EmitContext&);
525Id EmitBoundImageAtomicUMin32(EmitContext&);
526Id EmitBoundImageAtomicSMax32(EmitContext&);
527Id EmitBoundImageAtomicUMax32(EmitContext&);
528Id EmitBoundImageAtomicInc32(EmitContext&);
529Id EmitBoundImageAtomicDec32(EmitContext&);
530Id EmitBoundImageAtomicAnd32(EmitContext&);
531Id EmitBoundImageAtomicOr32(EmitContext&);
532Id EmitBoundImageAtomicXor32(EmitContext&);
533Id EmitBoundImageAtomicExchange32(EmitContext&);
534Id EmitImageAtomicIAdd32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
535 Id value);
536Id EmitImageAtomicSMin32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
537 Id value);
538Id EmitImageAtomicUMin32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
539 Id value);
540Id EmitImageAtomicSMax32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
541 Id value);
542Id EmitImageAtomicUMax32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
543 Id value);
544Id EmitImageAtomicInc32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
545 Id value);
546Id EmitImageAtomicDec32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
547 Id value);
548Id EmitImageAtomicAnd32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
549 Id value);
550Id EmitImageAtomicOr32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
551 Id value);
552Id EmitImageAtomicXor32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
553 Id value);
554Id EmitImageAtomicExchange32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
555 Id value);
512Id EmitLaneId(EmitContext& ctx); 556Id EmitLaneId(EmitContext& ctx);
513Id EmitVoteAll(EmitContext& ctx, Id pred); 557Id EmitVoteAll(EmitContext& ctx, Id pred);
514Id EmitVoteAny(EmitContext& ctx, Id pred); 558Id 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
8namespace Shader::Backend::SPIRV {
9namespace {
10Id 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
23std::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
29Id 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
39Id 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
44Id 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
49Id 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
54Id 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
59Id 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
64Id EmitImageAtomicInc32(EmitContext&, IR::Inst*, const IR::Value&, Id, Id) {
65 // TODO: This is not yet implemented
66 throw NotImplementedException("SPIR-V Instruction");
67}
68
69Id EmitImageAtomicDec32(EmitContext&, IR::Inst*, const IR::Value&, Id, Id) {
70 // TODO: This is not yet implemented
71 throw NotImplementedException("SPIR-V Instruction");
72}
73
74Id 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
79Id 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
84Id 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
89Id 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
94Id EmitBindlessImageAtomicIAdd32(EmitContext&) {
95 throw NotImplementedException("SPIR-V Instruction");
96}
97
98Id EmitBindlessImageAtomicSMin32(EmitContext&) {
99 throw NotImplementedException("SPIR-V Instruction");
100}
101
102Id EmitBindlessImageAtomicUMin32(EmitContext&) {
103 throw NotImplementedException("SPIR-V Instruction");
104}
105
106Id EmitBindlessImageAtomicSMax32(EmitContext&) {
107 throw NotImplementedException("SPIR-V Instruction");
108}
109
110Id EmitBindlessImageAtomicUMax32(EmitContext&) {
111 throw NotImplementedException("SPIR-V Instruction");
112}
113
114Id EmitBindlessImageAtomicInc32(EmitContext&) {
115 throw NotImplementedException("SPIR-V Instruction");
116}
117
118Id EmitBindlessImageAtomicDec32(EmitContext&) {
119 throw NotImplementedException("SPIR-V Instruction");
120}
121
122Id EmitBindlessImageAtomicAnd32(EmitContext&) {
123 throw NotImplementedException("SPIR-V Instruction");
124}
125
126Id EmitBindlessImageAtomicOr32(EmitContext&) {
127 throw NotImplementedException("SPIR-V Instruction");
128}
129
130Id EmitBindlessImageAtomicXor32(EmitContext&) {
131 throw NotImplementedException("SPIR-V Instruction");
132}
133
134Id EmitBindlessImageAtomicExchange32(EmitContext&) {
135 throw NotImplementedException("SPIR-V Instruction");
136}
137
138Id EmitBoundImageAtomicIAdd32(EmitContext&) {
139 throw NotImplementedException("SPIR-V Instruction");
140}
141
142Id EmitBoundImageAtomicSMin32(EmitContext&) {
143 throw NotImplementedException("SPIR-V Instruction");
144}
145
146Id EmitBoundImageAtomicUMin32(EmitContext&) {
147 throw NotImplementedException("SPIR-V Instruction");
148}
149
150Id EmitBoundImageAtomicSMax32(EmitContext&) {
151 throw NotImplementedException("SPIR-V Instruction");
152}
153
154Id EmitBoundImageAtomicUMax32(EmitContext&) {
155 throw NotImplementedException("SPIR-V Instruction");
156}
157
158Id EmitBoundImageAtomicInc32(EmitContext&) {
159 throw NotImplementedException("SPIR-V Instruction");
160}
161
162Id EmitBoundImageAtomicDec32(EmitContext&) {
163 throw NotImplementedException("SPIR-V Instruction");
164}
165
166Id EmitBoundImageAtomicAnd32(EmitContext&) {
167 throw NotImplementedException("SPIR-V Instruction");
168}
169
170Id EmitBoundImageAtomicOr32(EmitContext&) {
171 throw NotImplementedException("SPIR-V Instruction");
172}
173
174Id EmitBoundImageAtomicXor32(EmitContext&) {
175 throw NotImplementedException("SPIR-V Instruction");
176}
177
178Id 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
1872Value 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
1879Value 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
1886Value 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
1893Value 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
1899Value 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
1906Value 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
1913Value 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
1919Value 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
1926Value 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
1933Value 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
1940Value 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
1947Value 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
1954Value 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
1872U1 IREmitter::VoteAll(const U1& value) { 1961U1 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
496OPCODE(ImageRead, U32x4, Opaque, Opaque, ) 496OPCODE(ImageRead, U32x4, Opaque, Opaque, )
497OPCODE(ImageWrite, Void, Opaque, Opaque, U32x4, ) 497OPCODE(ImageWrite, Void, Opaque, Opaque, U32x4, )
498 498
499// Atomic Image operations
500
501OPCODE(BindlessImageAtomicIAdd32, U32, U32, Opaque, U32, )
502OPCODE(BindlessImageAtomicSMin32, U32, U32, Opaque, U32, )
503OPCODE(BindlessImageAtomicUMin32, U32, U32, Opaque, U32, )
504OPCODE(BindlessImageAtomicSMax32, U32, U32, Opaque, U32, )
505OPCODE(BindlessImageAtomicUMax32, U32, U32, Opaque, U32, )
506OPCODE(BindlessImageAtomicInc32, U32, U32, Opaque, U32, )
507OPCODE(BindlessImageAtomicDec32, U32, U32, Opaque, U32, )
508OPCODE(BindlessImageAtomicAnd32, U32, U32, Opaque, U32, )
509OPCODE(BindlessImageAtomicOr32, U32, U32, Opaque, U32, )
510OPCODE(BindlessImageAtomicXor32, U32, U32, Opaque, U32, )
511OPCODE(BindlessImageAtomicExchange32, U32, U32, Opaque, U32, )
512
513OPCODE(BoundImageAtomicIAdd32, U32, U32, Opaque, U32, )
514OPCODE(BoundImageAtomicSMin32, U32, U32, Opaque, U32, )
515OPCODE(BoundImageAtomicUMin32, U32, U32, Opaque, U32, )
516OPCODE(BoundImageAtomicSMax32, U32, U32, Opaque, U32, )
517OPCODE(BoundImageAtomicUMax32, U32, U32, Opaque, U32, )
518OPCODE(BoundImageAtomicInc32, U32, U32, Opaque, U32, )
519OPCODE(BoundImageAtomicDec32, U32, U32, Opaque, U32, )
520OPCODE(BoundImageAtomicAnd32, U32, U32, Opaque, U32, )
521OPCODE(BoundImageAtomicOr32, U32, U32, Opaque, U32, )
522OPCODE(BoundImageAtomicXor32, U32, U32, Opaque, U32, )
523OPCODE(BoundImageAtomicExchange32, U32, U32, Opaque, U32, )
524
525OPCODE(ImageAtomicIAdd32, U32, Opaque, Opaque, U32, )
526OPCODE(ImageAtomicSMin32, U32, Opaque, Opaque, U32, )
527OPCODE(ImageAtomicUMin32, U32, Opaque, Opaque, U32, )
528OPCODE(ImageAtomicSMax32, U32, Opaque, Opaque, U32, )
529OPCODE(ImageAtomicUMax32, U32, Opaque, Opaque, U32, )
530OPCODE(ImageAtomicInc32, U32, Opaque, Opaque, U32, )
531OPCODE(ImageAtomicDec32, U32, Opaque, Opaque, U32, )
532OPCODE(ImageAtomicAnd32, U32, Opaque, Opaque, U32, )
533OPCODE(ImageAtomicOr32, U32, Opaque, Opaque, U32, )
534OPCODE(ImageAtomicXor32, U32, Opaque, Opaque, U32, )
535OPCODE(ImageAtomicExchange32, U32, Opaque, Opaque, U32, )
536
499// Warp operations 537// Warp operations
500OPCODE(LaneId, U32, ) 538OPCODE(LaneId, U32, )
501OPCODE(VoteAll, U1, U1, ) 539OPCODE(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---")
244INST(STL, "STL", "1110 1111 0101 0---") 244INST(STL, "STL", "1110 1111 0101 0---")
245INST(STP, "STP", "1110 1110 1010 0---") 245INST(STP, "STP", "1110 1110 1010 0---")
246INST(STS, "STS", "1110 1111 0101 1---") 246INST(STS, "STS", "1110 1111 0101 1---")
247INST(SUATOM_cas, "SUATOM", "1110 1010 ---- ----") 247INST(SUATOM, "SUATOM", "1110 1010 0--- ----")
248INST(SUATOM_cas, "SUATOM_cas", "1110 1010 1--- ----")
248INST(SULD, "SULD", "1110 1011 000- ----") 249INST(SULD, "SULD", "1110 1011 000- ----")
249INST(SURED, "SURED", "1110 1011 010- ----") 250INST(SURED, "SURED", "1110 1011 010- ----")
250INST(SUST, "SUST", "1110 1011 001- ----") 251INST(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
252void TranslatorVisitor::SURED(u64) {
253 ThrowNotImplemented(Opcode::SURED);
254}
255
256void TranslatorVisitor::SYNC(u64) { 252void 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
13namespace Shader::Maxwell {
14namespace {
15enum class Type : u64 {
16 _1D,
17 BUFFER_1D,
18 ARRAY_1D,
19 _2D,
20 ARRAY_2D,
21 _3D,
22};
23
24enum class Size : u64 {
25 U32,
26 S32,
27 U64,
28 S64,
29 F32FTZRN,
30 F16x2FTZRN,
31 SD32,
32 SD64,
33};
34
35enum class AtomicOp : u64 {
36 ADD,
37 MIN,
38 MAX,
39 INC,
40 DEC,
41 AND,
42 OR,
43 XOR,
44 EXCH,
45};
46
47enum class Clamp : u64 {
48 IGN,
49 Default,
50 TRAP,
51};
52
53TextureType 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
71IR::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
85IR::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
112ImageFormat 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
124bool 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
135void 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
165void 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
185void 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{};