emit_glasm_warp.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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/glasm/emit_context.h"
  5. #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
  6. #include "shader_recompiler/frontend/ir/value.h"
  7. #include "shader_recompiler/profile.h"
  8. namespace Shader::Backend::GLASM {
  9. void EmitLaneId(EmitContext& ctx, IR::Inst& inst) {
  10. ctx.Add("MOV.S {}.x,{}.threadid;", inst, ctx.stage_name);
  11. }
  12. void EmitVoteAll(EmitContext& ctx, IR::Inst& inst, ScalarS32 pred) {
  13. ctx.Add("TGALL.S {}.x,{};", inst, pred);
  14. }
  15. void EmitVoteAny(EmitContext& ctx, IR::Inst& inst, ScalarS32 pred) {
  16. ctx.Add("TGANY.S {}.x,{};", inst, pred);
  17. }
  18. void EmitVoteEqual(EmitContext& ctx, IR::Inst& inst, ScalarS32 pred) {
  19. ctx.Add("TGEQ.S {}.x,{};", inst, pred);
  20. }
  21. void EmitSubgroupBallot(EmitContext& ctx, IR::Inst& inst, ScalarS32 pred) {
  22. ctx.Add("TGBALLOT {}.x,{};", inst, pred);
  23. }
  24. void EmitSubgroupEqMask(EmitContext& ctx, IR::Inst& inst) {
  25. ctx.Add("MOV.U {},{}.threadeqmask;", inst, ctx.stage_name);
  26. }
  27. void EmitSubgroupLtMask(EmitContext& ctx, IR::Inst& inst) {
  28. ctx.Add("MOV.U {},{}.threadltmask;", inst, ctx.stage_name);
  29. }
  30. void EmitSubgroupLeMask(EmitContext& ctx, IR::Inst& inst) {
  31. ctx.Add("MOV.U {},{}.threadlemask;", inst, ctx.stage_name);
  32. }
  33. void EmitSubgroupGtMask(EmitContext& ctx, IR::Inst& inst) {
  34. ctx.Add("MOV.U {},{}.threadgtmask;", inst, ctx.stage_name);
  35. }
  36. void EmitSubgroupGeMask(EmitContext& ctx, IR::Inst& inst) {
  37. ctx.Add("MOV.U {},{}.threadgemask;", inst, ctx.stage_name);
  38. }
  39. static void Shuffle(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index,
  40. const IR::Value& clamp, const IR::Value& segmentation_mask,
  41. std::string_view op) {
  42. IR::Inst* const in_bounds{inst.GetAssociatedPseudoOperation(IR::Opcode::GetInBoundsFromOp)};
  43. if (in_bounds) {
  44. in_bounds->Invalidate();
  45. }
  46. std::string mask;
  47. if (clamp.IsImmediate() && segmentation_mask.IsImmediate()) {
  48. mask = fmt::to_string(clamp.U32() | (segmentation_mask.U32() << 8));
  49. } else {
  50. mask = "RC";
  51. ctx.Add("BFI.U RC.x,{{5,8,0,0}},{},{};",
  52. ScalarU32{ctx.reg_alloc.Consume(segmentation_mask)},
  53. ScalarU32{ctx.reg_alloc.Consume(clamp)});
  54. }
  55. const Register value_ret{ctx.reg_alloc.Define(inst)};
  56. if (in_bounds) {
  57. const Register bounds_ret{ctx.reg_alloc.Define(*in_bounds)};
  58. ctx.Add("SHF{}.U {},{},{},{};"
  59. "MOV.U {}.x,{}.y;",
  60. op, bounds_ret, value, index, mask, value_ret, bounds_ret);
  61. } else {
  62. ctx.Add("SHF{}.U {},{},{},{};"
  63. "MOV.U {}.x,{}.y;",
  64. op, value_ret, value, index, mask, value_ret, value_ret);
  65. }
  66. }
  67. void EmitShuffleIndex(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index,
  68. const IR::Value& clamp, const IR::Value& segmentation_mask) {
  69. Shuffle(ctx, inst, value, index, clamp, segmentation_mask, "IDX");
  70. }
  71. void EmitShuffleUp(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index,
  72. const IR::Value& clamp, const IR::Value& segmentation_mask) {
  73. Shuffle(ctx, inst, value, index, clamp, segmentation_mask, "UP");
  74. }
  75. void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index,
  76. const IR::Value& clamp, const IR::Value& segmentation_mask) {
  77. Shuffle(ctx, inst, value, index, clamp, segmentation_mask, "DOWN");
  78. }
  79. void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index,
  80. const IR::Value& clamp, const IR::Value& segmentation_mask) {
  81. Shuffle(ctx, inst, value, index, clamp, segmentation_mask, "XOR");
  82. }
  83. void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, ScalarF32 op_a, ScalarF32 op_b,
  84. ScalarU32 swizzle) {
  85. const auto ret{ctx.reg_alloc.Define(inst)};
  86. ctx.Add("AND.U RC.z,{}.threadid,3;"
  87. "SHL.U RC.z,RC.z,1;"
  88. "SHR.U RC.z,{},RC.z;"
  89. "AND.U RC.z,RC.z,3;"
  90. "MUL.F RC.x,{},FSWZA[RC.z];"
  91. "MUL.F RC.y,{},FSWZB[RC.z];"
  92. "ADD.F {}.x,RC.x,RC.y;",
  93. ctx.stage_name, swizzle, op_a, op_b, ret);
  94. }
  95. void EmitDPdxFine(EmitContext& ctx, IR::Inst& inst, ScalarF32 p) {
  96. if (ctx.profile.support_derivative_control) {
  97. ctx.Add("DDX.FINE {}.x,{};", inst, p);
  98. } else {
  99. LOG_WARNING(Shader_GLASM, "Fine derivatives not supported by device");
  100. ctx.Add("DDX {}.x,{};", inst, p);
  101. }
  102. }
  103. void EmitDPdyFine(EmitContext& ctx, IR::Inst& inst, ScalarF32 p) {
  104. if (ctx.profile.support_derivative_control) {
  105. ctx.Add("DDY.FINE {}.x,{};", inst, p);
  106. } else {
  107. LOG_WARNING(Shader_GLASM, "Fine derivatives not supported by device");
  108. ctx.Add("DDY {}.x,{};", inst, p);
  109. }
  110. }
  111. void EmitDPdxCoarse(EmitContext& ctx, IR::Inst& inst, ScalarF32 p) {
  112. if (ctx.profile.support_derivative_control) {
  113. ctx.Add("DDX.COARSE {}.x,{};", inst, p);
  114. } else {
  115. LOG_WARNING(Shader_GLASM, "Coarse derivatives not supported by device");
  116. ctx.Add("DDX {}.x,{};", inst, p);
  117. }
  118. }
  119. void EmitDPdyCoarse(EmitContext& ctx, IR::Inst& inst, ScalarF32 p) {
  120. if (ctx.profile.support_derivative_control) {
  121. ctx.Add("DDY.COARSE {}.x,{};", inst, p);
  122. } else {
  123. LOG_WARNING(Shader_GLASM, "Coarse derivatives not supported by device");
  124. ctx.Add("DDY {}.x,{};", inst, p);
  125. }
  126. }
  127. } // namespace Shader::Backend::GLASM