emit_glsl_atomic.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <string_view>
  5. #include "shader_recompiler/backend/glsl/emit_context.h"
  6. #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
  7. #include "shader_recompiler/frontend/ir/value.h"
  8. namespace Shader::Backend::GLSL {
  9. namespace {
  10. static constexpr std::string_view cas_loop{R"(uint {};
  11. for (;;){{
  12. uint old_value={};
  13. {}=atomicCompSwap({},old_value,{}({},{}));
  14. if ({}==old_value){{break;}}
  15. }})"};
  16. void CasFunction(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  17. const IR::Value& offset, std::string_view value, std::string_view function) {
  18. const auto ret{ctx.reg_alloc.Define(inst)};
  19. const std::string ssbo{fmt::format("ssbo{}[{}]", binding.U32(), offset.U32())};
  20. ctx.Add(cas_loop.data(), ret, ssbo, ret, ssbo, function, ssbo, value, ret);
  21. }
  22. void CasFunctionF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  23. const IR::Value& offset, std::string_view value, std::string_view function) {
  24. const std::string ssbo{fmt::format("ssbo{}[{}]", binding.U32(), offset.U32())};
  25. const std::string u32_value{fmt::format("floatBitsToUint({})", value)};
  26. const auto ret{ctx.reg_alloc.Define(inst)};
  27. const auto ret_32{ret + "_u32"};
  28. ctx.Add(cas_loop.data(), ret_32, ssbo, ret_32, ssbo, function, ssbo, value, ret_32);
  29. ctx.Add("float {}=uintBitsToFloat({});", ret, ret_32);
  30. }
  31. } // namespace
  32. void EmitStorageAtomicIAdd32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  33. const IR::Value& offset, std::string_view value) {
  34. ctx.AddU32("{}=atomicAdd(ssbo{}[{}],{});", inst, binding.U32(), offset.U32(), value);
  35. }
  36. void EmitStorageAtomicSMin32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  37. const IR::Value& offset, std::string_view value) {
  38. const std::string u32_value{fmt::format("uint({})", value)};
  39. CasFunction(ctx, inst, binding, offset, u32_value, "CasMinS32");
  40. }
  41. void EmitStorageAtomicUMin32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  42. const IR::Value& offset, std::string_view value) {
  43. ctx.AddU32("{}=atomicMin(ssbo{}[{}],{});", inst, binding.U32(), offset.U32(), value);
  44. }
  45. void EmitStorageAtomicSMax32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  46. const IR::Value& offset, std::string_view value) {
  47. const std::string u32_value{fmt::format("uint({})", value)};
  48. CasFunction(ctx, inst, binding, offset, u32_value, "CasMaxS32");
  49. }
  50. void EmitStorageAtomicUMax32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  51. const IR::Value& offset, std::string_view value) {
  52. ctx.AddU32("{}=atomicMax(ssbo{}[{}],{});", inst, binding.U32(), offset.U32(), value);
  53. }
  54. void EmitStorageAtomicInc32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  55. const IR::Value& offset, std::string_view value) {
  56. CasFunction(ctx, inst, binding, offset, value, "CasIncrement");
  57. }
  58. void EmitStorageAtomicDec32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  59. const IR::Value& offset, std::string_view value) {
  60. CasFunction(ctx, inst, binding, offset, value, "CasDecrement");
  61. }
  62. void EmitStorageAtomicAnd32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  63. const IR::Value& offset, std::string_view value) {
  64. ctx.AddU32("{}=atomicAnd(ssbo{}[{}],{});", inst, binding.U32(), offset.U32(), value);
  65. }
  66. void EmitStorageAtomicOr32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  67. const IR::Value& offset, std::string_view value) {
  68. ctx.AddU32("{}=atomicOr(ssbo{}[{}],{});", inst, binding.U32(), offset.U32(), value);
  69. }
  70. void EmitStorageAtomicXor32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  71. const IR::Value& offset, std::string_view value) {
  72. ctx.AddU32("{}=atomicXor(ssbo{}[{}],{});", inst, binding.U32(), offset.U32(), value);
  73. }
  74. void EmitStorageAtomicExchange32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  75. const IR::Value& offset, std::string_view value) {
  76. ctx.AddU32("{}=atomicExchange(ssbo{}[{}],{});", inst, binding.U32(), offset.U32(), value);
  77. }
  78. void EmitStorageAtomicIAdd64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  79. const IR::Value& offset, std::string_view value) {
  80. // LOG_WARNING(..., "Op falling to non-atomic");
  81. ctx.AddU64("{}=uint64_t(uvec2(ssbo{}[{}],ssbo{}[{}]));", inst, binding.U32(), offset.U32(),
  82. binding.U32(), offset.U32() + 1);
  83. ctx.Add("ssbo{}[{}]+=unpackUint2x32({}).x;ssbo{}[{}]+=unpackUint2x32({}).y;", binding.U32(),
  84. offset.U32(), value, binding.U32(), offset.U32() + 1, value);
  85. }
  86. void EmitStorageAtomicSMin64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  87. const IR::Value& offset, std::string_view value) {
  88. // LOG_WARNING(..., "Op falling to non-atomic");
  89. ctx.AddS64("{}=int64_t(ivec2(ssbo{}[{}],ssbo{}[{}]));", inst, binding.U32(), offset.U32(),
  90. binding.U32(), offset.U32() + 1);
  91. ctx.Add("for(int i=0;i<2;++i){{ "
  92. "ssbo{}[{}+i]=uint(min(int(ssbo{}[{}+i]),unpackInt2x32(int64_t({}))[i]));}}",
  93. binding.U32(), offset.U32(), binding.U32(), offset.U32(), value);
  94. }
  95. void EmitStorageAtomicUMin64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  96. const IR::Value& offset, std::string_view value) {
  97. // LOG_WARNING(..., "Op falling to non-atomic");
  98. ctx.AddU64("{}=uint64_t(uvec2(ssbo{}[{}],ssbo{}[{}]));", inst, binding.U32(), offset.U32(),
  99. binding.U32(), offset.U32() + 1);
  100. ctx.Add(
  101. "for(int i=0;i<2;++i){{ ssbo{}[{}+i]=min(ssbo{}[{}+i],unpackUint2x32(uint64_t({}))[i]);}}",
  102. binding.U32(), offset.U32(), binding.U32(), offset.U32(), value);
  103. }
  104. void EmitStorageAtomicSMax64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  105. const IR::Value& offset, std::string_view value) {
  106. // LOG_WARNING(..., "Op falling to non-atomic");
  107. ctx.AddS64("{}=int64_t(ivec2(ssbo{}[{}],ssbo{}[{}]));", inst, binding.U32(), offset.U32(),
  108. binding.U32(), offset.U32() + 1);
  109. ctx.Add("for(int i=0;i<2;++i){{ "
  110. "ssbo{}[{}+i]=uint(max(int(ssbo{}[{}+i]),unpackInt2x32(int64_t({}))[i]));}}",
  111. binding.U32(), offset.U32(), binding.U32(), offset.U32(), value);
  112. }
  113. void EmitStorageAtomicUMax64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  114. const IR::Value& offset, std::string_view value) {
  115. // LOG_WARNING(..., "Op falling to non-atomic");
  116. ctx.AddU64("{}=uint64_t(uvec2(ssbo{}[{}],ssbo{}[{}]));", inst, binding.U32(), offset.U32(),
  117. binding.U32(), offset.U32() + 1);
  118. ctx.Add(
  119. "for(int i=0;i<2;++i){{ssbo{}[{}+i]=max(ssbo{}[{}+i],unpackUint2x32(uint64_t({}))[i]);}}",
  120. binding.U32(), offset.U32(), binding.U32(), offset.U32(), value);
  121. }
  122. void EmitStorageAtomicAnd64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  123. const IR::Value& offset, std::string_view value) {
  124. ctx.AddU64("{}=uint64_t(uvec2(atomicAnd(ssbo{}[{}],unpackUint2x32({}).x),atomicAnd(ssbo{}[{}],"
  125. "unpackUint2x32({}).y)));",
  126. inst, binding.U32(), offset.U32(), value, binding.U32(), offset.U32() + 1, value);
  127. }
  128. void EmitStorageAtomicOr64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  129. const IR::Value& offset, std::string_view value) {
  130. ctx.AddU64("{}=uint64_t(uvec2(atomicOr(ssbo{}[{}],unpackUint2x32({}).x),atomicOr(ssbo{}[{}],"
  131. "unpackUint2x32({}).y)));",
  132. inst, binding.U32(), offset.U32(), value, binding.U32(), offset.U32() + 1, value);
  133. }
  134. void EmitStorageAtomicXor64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  135. const IR::Value& offset, std::string_view value) {
  136. ctx.AddU64("{}=uint64_t(uvec2(atomicXor(ssbo{}[{}],unpackUint2x32({}).x),atomicXor(ssbo{}[{}],"
  137. "unpackUint2x32({}).y)));",
  138. inst, binding.U32(), offset.U32(), value, binding.U32(), offset.U32() + 1, value);
  139. }
  140. void EmitStorageAtomicExchange64(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  141. const IR::Value& offset, std::string_view value) {
  142. ctx.AddU64("{}=uint64_t(uvec2(atomicExchange(ssbo{}[{}],unpackUint2x32({}).x),atomicExchange("
  143. "ssbo{}[{}],unpackUint2x32({}).y)));",
  144. inst, binding.U32(), offset.U32(), value, binding.U32(), offset.U32() + 1, value);
  145. }
  146. void EmitStorageAtomicAddF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  147. const IR::Value& offset, std::string_view value) {
  148. CasFunctionF32(ctx, inst, binding, offset, value, "CasFloatAdd");
  149. }
  150. void EmitStorageAtomicAddF16x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  151. const IR::Value& offset, std::string_view value) {
  152. CasFunction(ctx, inst, binding, offset, value, "CasFloatAdd16x2");
  153. }
  154. void EmitStorageAtomicAddF32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  155. const IR::Value& offset, std::string_view value) {
  156. CasFunction(ctx, inst, binding, offset, value, "CasFloatAdd32x2");
  157. }
  158. void EmitStorageAtomicMinF16x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  159. const IR::Value& offset, std::string_view value) {
  160. CasFunction(ctx, inst, binding, offset, value, "CasFloatMin16x2");
  161. }
  162. void EmitStorageAtomicMinF32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  163. const IR::Value& offset, std::string_view value) {
  164. CasFunction(ctx, inst, binding, offset, value, "CasFloatMin32x2");
  165. }
  166. void EmitStorageAtomicMaxF16x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  167. const IR::Value& offset, std::string_view value) {
  168. CasFunction(ctx, inst, binding, offset, value, "CasFloatMax16x2");
  169. }
  170. void EmitStorageAtomicMaxF32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
  171. const IR::Value& offset, std::string_view value) {
  172. CasFunction(ctx, inst, binding, offset, value, "CasFloatMax32x2");
  173. }
  174. void EmitGlobalAtomicIAdd32(EmitContext&) {
  175. throw NotImplementedException("GLSL Instrucion");
  176. }
  177. void EmitGlobalAtomicSMin32(EmitContext&) {
  178. throw NotImplementedException("GLSL Instrucion");
  179. }
  180. void EmitGlobalAtomicUMin32(EmitContext&) {
  181. throw NotImplementedException("GLSL Instrucion");
  182. }
  183. void EmitGlobalAtomicSMax32(EmitContext&) {
  184. throw NotImplementedException("GLSL Instrucion");
  185. }
  186. void EmitGlobalAtomicUMax32(EmitContext&) {
  187. throw NotImplementedException("GLSL Instrucion");
  188. }
  189. void EmitGlobalAtomicInc32(EmitContext&) {
  190. throw NotImplementedException("GLSL Instrucion");
  191. }
  192. void EmitGlobalAtomicDec32(EmitContext&) {
  193. throw NotImplementedException("GLSL Instrucion");
  194. }
  195. void EmitGlobalAtomicAnd32(EmitContext&) {
  196. throw NotImplementedException("GLSL Instrucion");
  197. }
  198. void EmitGlobalAtomicOr32(EmitContext&) {
  199. throw NotImplementedException("GLSL Instrucion");
  200. }
  201. void EmitGlobalAtomicXor32(EmitContext&) {
  202. throw NotImplementedException("GLSL Instrucion");
  203. }
  204. void EmitGlobalAtomicExchange32(EmitContext&) {
  205. throw NotImplementedException("GLSL Instrucion");
  206. }
  207. void EmitGlobalAtomicIAdd64(EmitContext&) {
  208. throw NotImplementedException("GLSL Instrucion");
  209. }
  210. void EmitGlobalAtomicSMin64(EmitContext&) {
  211. throw NotImplementedException("GLSL Instrucion");
  212. }
  213. void EmitGlobalAtomicUMin64(EmitContext&) {
  214. throw NotImplementedException("GLSL Instrucion");
  215. }
  216. void EmitGlobalAtomicSMax64(EmitContext&) {
  217. throw NotImplementedException("GLSL Instrucion");
  218. }
  219. void EmitGlobalAtomicUMax64(EmitContext&) {
  220. throw NotImplementedException("GLSL Instrucion");
  221. }
  222. void EmitGlobalAtomicInc64(EmitContext&) {
  223. throw NotImplementedException("GLSL Instrucion");
  224. }
  225. void EmitGlobalAtomicDec64(EmitContext&) {
  226. throw NotImplementedException("GLSL Instrucion");
  227. }
  228. void EmitGlobalAtomicAnd64(EmitContext&) {
  229. throw NotImplementedException("GLSL Instrucion");
  230. }
  231. void EmitGlobalAtomicOr64(EmitContext&) {
  232. throw NotImplementedException("GLSL Instrucion");
  233. }
  234. void EmitGlobalAtomicXor64(EmitContext&) {
  235. throw NotImplementedException("GLSL Instrucion");
  236. }
  237. void EmitGlobalAtomicExchange64(EmitContext&) {
  238. throw NotImplementedException("GLSL Instrucion");
  239. }
  240. void EmitGlobalAtomicAddF32(EmitContext&) {
  241. throw NotImplementedException("GLSL Instrucion");
  242. }
  243. void EmitGlobalAtomicAddF16x2(EmitContext&) {
  244. throw NotImplementedException("GLSL Instrucion");
  245. }
  246. void EmitGlobalAtomicAddF32x2(EmitContext&) {
  247. throw NotImplementedException("GLSL Instrucion");
  248. }
  249. void EmitGlobalAtomicMinF16x2(EmitContext&) {
  250. throw NotImplementedException("GLSL Instrucion");
  251. }
  252. void EmitGlobalAtomicMinF32x2(EmitContext&) {
  253. throw NotImplementedException("GLSL Instrucion");
  254. }
  255. void EmitGlobalAtomicMaxF16x2(EmitContext&) {
  256. throw NotImplementedException("GLSL Instrucion");
  257. }
  258. void EmitGlobalAtomicMaxF32x2(EmitContext&) {
  259. throw NotImplementedException("GLSL Instrucion");
  260. }
  261. } // namespace Shader::Backend::GLSL