emit_spirv_shared_memory.cpp 7.6 KB

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