emit_spirv_shared_memory.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "shader_recompiler/backend/spirv/emit_spirv.h"
  5. #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
  6. #include "shader_recompiler/backend/spirv/spirv_emit_context.h"
  7. namespace Shader::Backend::SPIRV {
  8. namespace {
  9. Id Pointer(EmitContext& ctx, Id pointer_type, Id array, Id offset, u32 shift) {
  10. const Id shift_id{ctx.Const(shift)};
  11. const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
  12. return ctx.OpAccessChain(pointer_type, array, ctx.u32_zero_value, index);
  13. }
  14. Id Word(EmitContext& ctx, Id offset) {
  15. const Id shift_id{ctx.Const(2U)};
  16. const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
  17. const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index)};
  18. return ctx.OpLoad(ctx.U32[1], pointer);
  19. }
  20. std::pair<Id, Id> ExtractArgs(EmitContext& ctx, Id offset, u32 mask, u32 count) {
  21. const Id shift{ctx.OpShiftLeftLogical(ctx.U32[1], offset, ctx.Const(3U))};
  22. const Id bit{ctx.OpBitwiseAnd(ctx.U32[1], shift, ctx.Const(mask))};
  23. const Id count_id{ctx.Const(count)};
  24. return {bit, count_id};
  25. }
  26. } // Anonymous namespace
  27. Id EmitLoadSharedU8(EmitContext& ctx, Id offset) {
  28. if (ctx.profile.support_explicit_workgroup_layout) {
  29. const Id pointer{
  30. ctx.OpAccessChain(ctx.shared_u8, ctx.shared_memory_u8, ctx.u32_zero_value, offset)};
  31. return ctx.OpUConvert(ctx.U32[1], ctx.OpLoad(ctx.U8, pointer));
  32. } else {
  33. const auto [bit, count]{ExtractArgs(ctx, offset, 24, 8)};
  34. return ctx.OpBitFieldUExtract(ctx.U32[1], Word(ctx, offset), bit, count);
  35. }
  36. }
  37. Id EmitLoadSharedS8(EmitContext& ctx, Id offset) {
  38. if (ctx.profile.support_explicit_workgroup_layout) {
  39. const Id pointer{
  40. ctx.OpAccessChain(ctx.shared_u8, ctx.shared_memory_u8, ctx.u32_zero_value, offset)};
  41. return ctx.OpSConvert(ctx.U32[1], ctx.OpLoad(ctx.U8, pointer));
  42. } else {
  43. const auto [bit, count]{ExtractArgs(ctx, offset, 24, 8)};
  44. return ctx.OpBitFieldSExtract(ctx.U32[1], Word(ctx, offset), bit, count);
  45. }
  46. }
  47. Id EmitLoadSharedU16(EmitContext& ctx, Id offset) {
  48. if (ctx.profile.support_explicit_workgroup_layout) {
  49. const Id pointer{Pointer(ctx, ctx.shared_u16, ctx.shared_memory_u16, offset, 1)};
  50. return ctx.OpUConvert(ctx.U32[1], ctx.OpLoad(ctx.U16, pointer));
  51. } else {
  52. const auto [bit, count]{ExtractArgs(ctx, offset, 16, 16)};
  53. return ctx.OpBitFieldUExtract(ctx.U32[1], Word(ctx, offset), bit, count);
  54. }
  55. }
  56. Id EmitLoadSharedS16(EmitContext& ctx, Id offset) {
  57. if (ctx.profile.support_explicit_workgroup_layout) {
  58. const Id pointer{Pointer(ctx, ctx.shared_u16, ctx.shared_memory_u16, offset, 1)};
  59. return ctx.OpSConvert(ctx.U32[1], ctx.OpLoad(ctx.U16, pointer));
  60. } else {
  61. const auto [bit, count]{ExtractArgs(ctx, offset, 16, 16)};
  62. return ctx.OpBitFieldSExtract(ctx.U32[1], Word(ctx, offset), bit, count);
  63. }
  64. }
  65. Id EmitLoadSharedU32(EmitContext& ctx, Id offset) {
  66. if (ctx.profile.support_explicit_workgroup_layout) {
  67. const Id pointer{Pointer(ctx, ctx.shared_u32, ctx.shared_memory_u32, offset, 2)};
  68. return ctx.OpLoad(ctx.U32[1], pointer);
  69. } else {
  70. return Word(ctx, offset);
  71. }
  72. }
  73. Id EmitLoadSharedU64(EmitContext& ctx, Id offset) {
  74. if (ctx.profile.support_explicit_workgroup_layout) {
  75. const Id pointer{Pointer(ctx, ctx.shared_u32x2, ctx.shared_memory_u32x2, offset, 3)};
  76. return ctx.OpLoad(ctx.U32[2], pointer);
  77. } else {
  78. const Id shift_id{ctx.Const(2U)};
  79. const Id base_index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
  80. const Id next_index{ctx.OpIAdd(ctx.U32[1], base_index, ctx.Const(1U))};
  81. const Id lhs_pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, base_index)};
  82. const Id rhs_pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, next_index)};
  83. return ctx.OpCompositeConstruct(ctx.U32[2], ctx.OpLoad(ctx.U32[1], lhs_pointer),
  84. ctx.OpLoad(ctx.U32[1], rhs_pointer));
  85. }
  86. }
  87. Id EmitLoadSharedU128(EmitContext& ctx, Id offset) {
  88. if (ctx.profile.support_explicit_workgroup_layout) {
  89. const Id pointer{Pointer(ctx, ctx.shared_u32x4, ctx.shared_memory_u32x4, offset, 4)};
  90. return ctx.OpLoad(ctx.U32[4], pointer);
  91. }
  92. const Id shift_id{ctx.Const(2U)};
  93. const Id base_index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
  94. std::array<Id, 4> values{};
  95. for (u32 i = 0; i < 4; ++i) {
  96. const Id index{i == 0 ? base_index : ctx.OpIAdd(ctx.U32[1], base_index, ctx.Const(i))};
  97. const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index)};
  98. values[i] = ctx.OpLoad(ctx.U32[1], pointer);
  99. }
  100. return ctx.OpCompositeConstruct(ctx.U32[4], values);
  101. }
  102. void EmitWriteSharedU8(EmitContext& ctx, Id offset, Id value) {
  103. if (ctx.profile.support_explicit_workgroup_layout) {
  104. const Id pointer{
  105. ctx.OpAccessChain(ctx.shared_u8, ctx.shared_memory_u8, ctx.u32_zero_value, offset)};
  106. ctx.OpStore(pointer, ctx.OpUConvert(ctx.U8, value));
  107. } else {
  108. ctx.OpFunctionCall(ctx.void_id, ctx.shared_store_u8_func, offset, value);
  109. }
  110. }
  111. void EmitWriteSharedU16(EmitContext& ctx, Id offset, Id value) {
  112. if (ctx.profile.support_explicit_workgroup_layout) {
  113. const Id pointer{Pointer(ctx, ctx.shared_u16, ctx.shared_memory_u16, offset, 1)};
  114. ctx.OpStore(pointer, ctx.OpUConvert(ctx.U16, value));
  115. } else {
  116. ctx.OpFunctionCall(ctx.void_id, ctx.shared_store_u16_func, offset, value);
  117. }
  118. }
  119. void EmitWriteSharedU32(EmitContext& ctx, Id offset, Id value) {
  120. Id pointer{};
  121. if (ctx.profile.support_explicit_workgroup_layout) {
  122. pointer = Pointer(ctx, ctx.shared_u32, ctx.shared_memory_u32, offset, 2);
  123. } else {
  124. const Id shift{ctx.Const(2U)};
  125. const Id word_offset{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift)};
  126. pointer = ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, word_offset);
  127. }
  128. ctx.OpStore(pointer, value);
  129. }
  130. void EmitWriteSharedU64(EmitContext& ctx, Id offset, Id value) {
  131. if (ctx.profile.support_explicit_workgroup_layout) {
  132. const Id pointer{Pointer(ctx, ctx.shared_u32x2, ctx.shared_memory_u32x2, offset, 3)};
  133. ctx.OpStore(pointer, value);
  134. return;
  135. }
  136. const Id shift{ctx.Const(2U)};
  137. const Id word_offset{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift)};
  138. const Id next_offset{ctx.OpIAdd(ctx.U32[1], word_offset, ctx.Const(1U))};
  139. const Id lhs_pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, word_offset)};
  140. const Id rhs_pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, next_offset)};
  141. ctx.OpStore(lhs_pointer, ctx.OpCompositeExtract(ctx.U32[1], value, 0U));
  142. ctx.OpStore(rhs_pointer, ctx.OpCompositeExtract(ctx.U32[1], value, 1U));
  143. }
  144. void EmitWriteSharedU128(EmitContext& ctx, Id offset, Id value) {
  145. if (ctx.profile.support_explicit_workgroup_layout) {
  146. const Id pointer{Pointer(ctx, ctx.shared_u32x4, ctx.shared_memory_u32x4, offset, 4)};
  147. ctx.OpStore(pointer, value);
  148. return;
  149. }
  150. const Id shift{ctx.Const(2U)};
  151. const Id base_index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift)};
  152. for (u32 i = 0; i < 4; ++i) {
  153. const Id index{i == 0 ? base_index : ctx.OpIAdd(ctx.U32[1], base_index, ctx.Const(i))};
  154. const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index)};
  155. ctx.OpStore(pointer, ctx.OpCompositeExtract(ctx.U32[1], value, i));
  156. }
  157. }
  158. } // namespace Shader::Backend::SPIRV