summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp')
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp418
1 files changed, 418 insertions, 0 deletions
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp
new file mode 100644
index 000000000..772acc5a4
--- /dev/null
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp
@@ -0,0 +1,418 @@
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 <string_view>
6
7#include "shader_recompiler/backend/glsl/emit_context.h"
8#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
9#include "shader_recompiler/frontend/ir/value.h"
10
11namespace Shader::Backend::GLSL {
12namespace {
13constexpr char cas_loop[]{
14 "for (;;){{uint old={};{}=atomicCompSwap({},old,{}({},{}));if({}==old){{break;}}}}"};
15
16void SharedCasFunction(EmitContext& ctx, IR::Inst& inst, std::string_view offset,
17 std::string_view value, std::string_view function) {
18 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)};
19 const std::string smem{fmt::format("smem[{}>>2]", offset)};
20 ctx.Add(cas_loop, smem, ret, smem, function, smem, value, ret);
21}
22
23void SsboCasFunction(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
24 const IR::Value& offset, std::string_view value, std::string_view function) {
25 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)};
26 const std::string ssbo{fmt::format("{}_ssbo{}[{}>>2]", ctx.stage_name, binding.U32(),
27 ctx.var_alloc.Consume(offset))};
28 ctx.Add(cas_loop, ssbo, ret, ssbo, function, ssbo, value, ret);
29}
30
31void SsboCasFunctionF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
32 const IR::Value& offset, std::string_view value,
33 std::string_view function) {
34 const std::string ssbo{fmt::format("{}_ssbo{}[{}>>2]", ctx.stage_name, binding.U32(),
35 ctx.var_alloc.Consume(offset))};
36 const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)};
37 ctx.Add(cas_loop, ssbo, ret, ssbo, function, ssbo, value, ret);
38 ctx.AddF32("{}=utof({});", inst, ret);
39}
40} // Anonymous namespace
41
42void EmitSharedAtomicIAdd32(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
43 std::string_view value) {
44 ctx.AddU32("{}=atomicAdd(smem[{}>>2],{});", inst, pointer_offset, value);
45}
46
47void EmitSharedAtomicSMin32(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
48 std::string_view value) {
49 const std::string u32_value{fmt::format("uint({})", value)};
50 SharedCasFunction(ctx, inst, pointer_offset, u32_value, "CasMinS32");
51}
52
53void EmitSharedAtomicUMin32(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
54 std::string_view value) {
55 ctx.AddU32("{}=atomicMin(smem[{}>>2],{});", inst, pointer_offset, value);
56}
57
58void EmitSharedAtomicSMax32(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
59 std::string_view value) {
60 const std::string u32_value{fmt::format("uint({})", value)};
61 SharedCasFunction(ctx, inst, pointer_offset, u32_value, "CasMaxS32");
62}
63
64void EmitSharedAtomicUMax32(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
65 std::string_view value) {
66 ctx.AddU32("{}=atomicMax(smem[{}>>2],{});", inst, pointer_offset, value);
67}
68
69void EmitSharedAtomicInc32(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
70 std::string_view value) {
71 SharedCasFunction(ctx, inst, pointer_offset, value, "CasIncrement");
72}
73
74void EmitSharedAtomicDec32(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
75 std::string_view value) {
76 SharedCasFunction(ctx, inst, pointer_offset, value, "CasDecrement");
77}
78
79void EmitSharedAtomicAnd32(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
80 std::string_view value) {
81 ctx.AddU32("{}=atomicAnd(smem[{}>>2],{});", inst, pointer_offset, value);
82}
83
84void EmitSharedAtomicOr32(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
85 std::string_view value) {
86 ctx.AddU32("{}=atomicOr(smem[{}>>2],{});", inst, pointer_offset, value);
87}
88
89void EmitSharedAtomicXor32(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
90 std::string_view value) {
91 ctx.AddU32("{}=atomicXor(smem[{}>>2],{});", inst, pointer_offset, value);
92}
93
94void EmitSharedAtomicExchange32(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
95 std::string_view value) {
96 ctx.AddU32("{}=atomicExchange(smem[{}>>2],{});", inst, pointer_offset, value);
97}
98
99void EmitSharedAtomicExchange64(EmitContext& ctx, IR::Inst& inst, std::string_view pointer_offset,
100 std::string_view value) {
101 LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to non-atomic");
102 ctx.AddU64("{}=packUint2x32(uvec2(smem[{}>>2],smem[({}+4)>>2]));", inst, pointer_offset,
103 pointer_offset);
104 ctx.Add("smem[{}>>2]=unpackUint2x32({}).x;smem[({}+4)>>2]=unpackUint2x32({}).y;",
105 pointer_offset, value, pointer_offset, value);
106}
107
108void EmitStorageAtomicIAdd32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
109 const IR::Value& offset, std::string_view value) {
110 ctx.AddU32("{}=atomicAdd({}_ssbo{}[{}>>2],{});", inst, ctx.stage_name, binding.U32(),
111 ctx.var_alloc.Consume(offset), value);
112}
113
114void EmitStorageAtomicSMin32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
115 const IR::Value& offset, std::string_view value) {
116 const std::string u32_value{fmt::format("uint({})", value)};
117 SsboCasFunction(ctx, inst, binding, offset, u32_value, "CasMinS32");
118}
119
120void EmitStorageAtomicUMin32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
121 const IR::Value& offset, std::string_view value) {
122 ctx.AddU32("{}=atomicMin({}_ssbo{}[{}>>2],{});", inst, ctx.stage_name, binding.U32(),
123 ctx.var_alloc.Consume(offset), value);
124}
125
126void EmitStorageAtomicSMax32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
127 const IR::Value& offset, std::string_view value) {
128 const std::string u32_value{fmt::format("uint({})", value)};
129 SsboCasFunction(ctx, inst, binding, offset, u32_value, "CasMaxS32");
130}
131
132void EmitStorageAtomicUMax32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
133 const IR::Value& offset, std::string_view value) {
134 ctx.AddU32("{}=atomicMax({}_ssbo{}[{}>>2],{});", inst, ctx.stage_name, binding.U32(),
135 ctx.var_alloc.Consume(offset), value);
136}
137
138void EmitStorageAtomicInc32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
139 const IR::Value& offset, std::string_view value) {
140 SsboCasFunction(ctx, inst, binding, offset, value, "CasIncrement");
141}
142
143void EmitStorageAtomicDec32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
144 const IR::Value& offset, std::string_view value) {
145 SsboCasFunction(ctx, inst, binding, offset, value, "CasDecrement");
146}
147
148void EmitStorageAtomicAnd32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
149 const IR::Value& offset, std::string_view value) {
150 ctx.AddU32("{}=atomicAnd({}_ssbo{}[{}>>2],{});", inst, ctx.stage_name, binding.U32(),
151 ctx.var_alloc.Consume(offset), value);
152}
153
154void EmitStorageAtomicOr32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
155 const IR::Value& offset, std::string_view value) {
156 ctx.AddU32("{}=atomicOr({}_ssbo{}[{}>>2],{});", inst, ctx.stage_name, binding.U32(),
157 ctx.var_alloc.Consume(offset), value);
158}
159
160void EmitStorageAtomicXor32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
161 const IR::Value& offset, std::string_view value) {
162 ctx.AddU32("{}=atomicXor({}_ssbo{}[{}>>2],{});", inst, ctx.stage_name, binding.U32(),
163 ctx.var_alloc.Consume(offset), value);
164}
165
166void EmitStorageAtomicExchange32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
167 const IR::Value& offset, std::string_view value) {
168 ctx.AddU32("{}=atomicExchange({}_ssbo{}[{}>>2],{});", inst, ctx.stage_name, binding.U32(),
169 ctx.var_alloc.Consume(offset), value);
170}
171
172void EmitStorageAtomicIAdd64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
173 const IR::Value& offset, std::string_view value) {
174 LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to non-atomic");
175 ctx.AddU64("{}=packUint2x32(uvec2({}_ssbo{}[{}>>2],{}_ssbo{}[({}>>2)+1]));", inst,
176 ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name,
177 binding.U32(), ctx.var_alloc.Consume(offset));
178 ctx.Add("{}_ssbo{}[{}>>2]+=unpackUint2x32({}).x;{}_ssbo{}[({}>>2)+1]+=unpackUint2x32({}).y;",
179 ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value, ctx.stage_name,
180 binding.U32(), ctx.var_alloc.Consume(offset), value);
181}
182
183void EmitStorageAtomicSMin64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
184 const IR::Value& offset, std::string_view value) {
185 LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to non-atomic");
186 ctx.AddU64("{}=packInt2x32(ivec2({}_ssbo{}[{}>>2],{}_ssbo{}[({}>>2)+1]));", inst,
187 ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name,
188 binding.U32(), ctx.var_alloc.Consume(offset));
189 ctx.Add("for(int i=0;i<2;++i){{ "
190 "{}_ssbo{}[({}>>2)+i]=uint(min(int({}_ssbo{}[({}>>2)+i]),unpackInt2x32(int64_t({}))[i])"
191 ");}}",
192 ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name,
193 binding.U32(), ctx.var_alloc.Consume(offset), value);
194}
195
196void EmitStorageAtomicUMin64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
197 const IR::Value& offset, std::string_view value) {
198 LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to non-atomic");
199 ctx.AddU64("{}=packUint2x32(uvec2({}_ssbo{}[{}>>2],{}_ssbo{}[({}>>2)+1]));", inst,
200 ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name,
201 binding.U32(), ctx.var_alloc.Consume(offset));
202 ctx.Add("for(int i=0;i<2;++i){{ "
203 "{}_ssbo{}[({}>>2)+i]=min({}_ssbo{}[({}>>2)+i],unpackUint2x32(uint64_t({}))[i]);}}",
204 ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name,
205 binding.U32(), ctx.var_alloc.Consume(offset), value);
206}
207
208void EmitStorageAtomicSMax64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
209 const IR::Value& offset, std::string_view value) {
210 LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to non-atomic");
211 ctx.AddU64("{}=packInt2x32(ivec2({}_ssbo{}[{}>>2],{}_ssbo{}[({}>>2)+1]));", inst,
212 ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name,
213 binding.U32(), ctx.var_alloc.Consume(offset));
214 ctx.Add("for(int i=0;i<2;++i){{ "
215 "{}_ssbo{}[({}>>2)+i]=uint(max(int({}_ssbo{}[({}>>2)+i]),unpackInt2x32(int64_t({}))[i])"
216 ");}}",
217 ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name,
218 binding.U32(), ctx.var_alloc.Consume(offset), value);
219}
220
221void EmitStorageAtomicUMax64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
222 const IR::Value& offset, std::string_view value) {
223 LOG_WARNING(Shader_GLSL, "Int64 atomics not supported, fallback to non-atomic");
224 ctx.AddU64("{}=packUint2x32(uvec2({}_ssbo{}[{}>>2],{}_ssbo{}[({}>>2)+1]));", inst,
225 ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name,
226 binding.U32(), ctx.var_alloc.Consume(offset));
227 ctx.Add("for(int "
228 "i=0;i<2;++i){{{}_ssbo{}[({}>>2)+i]=max({}_ssbo{}[({}>>2)+i],unpackUint2x32(uint64_t({}"
229 "))[i]);}}",
230 ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), ctx.stage_name,
231 binding.U32(), ctx.var_alloc.Consume(offset), value);
232}
233
234void EmitStorageAtomicAnd64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
235 const IR::Value& offset, std::string_view value) {
236 ctx.AddU64(
237 "{}=packUint2x32(uvec2(atomicAnd({}_ssbo{}[{}>>2],unpackUint2x32({}).x),atomicAnd({}_"
238 "ssbo{}[({}>>2)+1],unpackUint2x32({}).y)));",
239 inst, ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value, ctx.stage_name,
240 binding.U32(), ctx.var_alloc.Consume(offset), value);
241}
242
243void EmitStorageAtomicOr64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
244 const IR::Value& offset, std::string_view value) {
245 ctx.AddU64("{}=packUint2x32(uvec2(atomicOr({}_ssbo{}[{}>>2],unpackUint2x32({}).x),atomicOr({}_"
246 "ssbo{}[({}>>2)+1],unpackUint2x32({}).y)));",
247 inst, ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value,
248 ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value);
249}
250
251void EmitStorageAtomicXor64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
252 const IR::Value& offset, std::string_view value) {
253 ctx.AddU64(
254 "{}=packUint2x32(uvec2(atomicXor({}_ssbo{}[{}>>2],unpackUint2x32({}).x),atomicXor({}_"
255 "ssbo{}[({}>>2)+1],unpackUint2x32({}).y)));",
256 inst, ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value, ctx.stage_name,
257 binding.U32(), ctx.var_alloc.Consume(offset), value);
258}
259
260void EmitStorageAtomicExchange64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
261 const IR::Value& offset, std::string_view value) {
262 ctx.AddU64("{}=packUint2x32(uvec2(atomicExchange({}_ssbo{}[{}>>2],unpackUint2x32({}).x),"
263 "atomicExchange({}_ssbo{}[({}>>2)+1],unpackUint2x32({}).y)));",
264 inst, ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value,
265 ctx.stage_name, binding.U32(), ctx.var_alloc.Consume(offset), value);
266}
267
268void EmitStorageAtomicAddF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
269 const IR::Value& offset, std::string_view value) {
270 SsboCasFunctionF32(ctx, inst, binding, offset, value, "CasFloatAdd");
271}
272
273void EmitStorageAtomicAddF16x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
274 const IR::Value& offset, std::string_view value) {
275 SsboCasFunction(ctx, inst, binding, offset, value, "CasFloatAdd16x2");
276}
277
278void EmitStorageAtomicAddF32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
279 const IR::Value& offset, std::string_view value) {
280 SsboCasFunction(ctx, inst, binding, offset, value, "CasFloatAdd32x2");
281}
282
283void EmitStorageAtomicMinF16x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
284 const IR::Value& offset, std::string_view value) {
285 SsboCasFunction(ctx, inst, binding, offset, value, "CasFloatMin16x2");
286}
287
288void EmitStorageAtomicMinF32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
289 const IR::Value& offset, std::string_view value) {
290 SsboCasFunction(ctx, inst, binding, offset, value, "CasFloatMin32x2");
291}
292
293void EmitStorageAtomicMaxF16x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
294 const IR::Value& offset, std::string_view value) {
295 SsboCasFunction(ctx, inst, binding, offset, value, "CasFloatMax16x2");
296}
297
298void EmitStorageAtomicMaxF32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
299 const IR::Value& offset, std::string_view value) {
300 SsboCasFunction(ctx, inst, binding, offset, value, "CasFloatMax32x2");
301}
302
303void EmitGlobalAtomicIAdd32(EmitContext&) {
304 throw NotImplementedException("GLSL Instrucion");
305}
306
307void EmitGlobalAtomicSMin32(EmitContext&) {
308 throw NotImplementedException("GLSL Instrucion");
309}
310
311void EmitGlobalAtomicUMin32(EmitContext&) {
312 throw NotImplementedException("GLSL Instrucion");
313}
314
315void EmitGlobalAtomicSMax32(EmitContext&) {
316 throw NotImplementedException("GLSL Instrucion");
317}
318
319void EmitGlobalAtomicUMax32(EmitContext&) {
320 throw NotImplementedException("GLSL Instrucion");
321}
322
323void EmitGlobalAtomicInc32(EmitContext&) {
324 throw NotImplementedException("GLSL Instrucion");
325}
326
327void EmitGlobalAtomicDec32(EmitContext&) {
328 throw NotImplementedException("GLSL Instrucion");
329}
330
331void EmitGlobalAtomicAnd32(EmitContext&) {
332 throw NotImplementedException("GLSL Instrucion");
333}
334
335void EmitGlobalAtomicOr32(EmitContext&) {
336 throw NotImplementedException("GLSL Instrucion");
337}
338
339void EmitGlobalAtomicXor32(EmitContext&) {
340 throw NotImplementedException("GLSL Instrucion");
341}
342
343void EmitGlobalAtomicExchange32(EmitContext&) {
344 throw NotImplementedException("GLSL Instrucion");
345}
346
347void EmitGlobalAtomicIAdd64(EmitContext&) {
348 throw NotImplementedException("GLSL Instrucion");
349}
350
351void EmitGlobalAtomicSMin64(EmitContext&) {
352 throw NotImplementedException("GLSL Instrucion");
353}
354
355void EmitGlobalAtomicUMin64(EmitContext&) {
356 throw NotImplementedException("GLSL Instrucion");
357}
358
359void EmitGlobalAtomicSMax64(EmitContext&) {
360 throw NotImplementedException("GLSL Instrucion");
361}
362
363void EmitGlobalAtomicUMax64(EmitContext&) {
364 throw NotImplementedException("GLSL Instrucion");
365}
366
367void EmitGlobalAtomicInc64(EmitContext&) {
368 throw NotImplementedException("GLSL Instrucion");
369}
370
371void EmitGlobalAtomicDec64(EmitContext&) {
372 throw NotImplementedException("GLSL Instrucion");
373}
374
375void EmitGlobalAtomicAnd64(EmitContext&) {
376 throw NotImplementedException("GLSL Instrucion");
377}
378
379void EmitGlobalAtomicOr64(EmitContext&) {
380 throw NotImplementedException("GLSL Instrucion");
381}
382
383void EmitGlobalAtomicXor64(EmitContext&) {
384 throw NotImplementedException("GLSL Instrucion");
385}
386
387void EmitGlobalAtomicExchange64(EmitContext&) {
388 throw NotImplementedException("GLSL Instrucion");
389}
390
391void EmitGlobalAtomicAddF32(EmitContext&) {
392 throw NotImplementedException("GLSL Instrucion");
393}
394
395void EmitGlobalAtomicAddF16x2(EmitContext&) {
396 throw NotImplementedException("GLSL Instrucion");
397}
398
399void EmitGlobalAtomicAddF32x2(EmitContext&) {
400 throw NotImplementedException("GLSL Instrucion");
401}
402
403void EmitGlobalAtomicMinF16x2(EmitContext&) {
404 throw NotImplementedException("GLSL Instrucion");
405}
406
407void EmitGlobalAtomicMinF32x2(EmitContext&) {
408 throw NotImplementedException("GLSL Instrucion");
409}
410
411void EmitGlobalAtomicMaxF16x2(EmitContext&) {
412 throw NotImplementedException("GLSL Instrucion");
413}
414
415void EmitGlobalAtomicMaxF32x2(EmitContext&) {
416 throw NotImplementedException("GLSL Instrucion");
417}
418} // namespace Shader::Backend::GLSL