InstEmitWarp.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. using Ryujinx.Graphics.Shader.Decoders;
  2. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3. using Ryujinx.Graphics.Shader.Translation;
  4. using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
  5. using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  6. namespace Ryujinx.Graphics.Shader.Instructions
  7. {
  8. static partial class InstEmit
  9. {
  10. public static void Fswzadd(EmitterContext context)
  11. {
  12. InstFswzadd op = context.GetOp<InstFswzadd>();
  13. Operand srcA = GetSrcReg(context, op.SrcA);
  14. Operand srcB = GetSrcReg(context, op.SrcB);
  15. Operand dest = GetDest(op.Dest);
  16. context.Copy(dest, context.FPSwizzleAdd(srcA, srcB, op.PnWord));
  17. InstEmitAluHelper.SetFPZnFlags(context, dest, op.WriteCC);
  18. }
  19. public static void Shfl(EmitterContext context)
  20. {
  21. InstShfl op = context.GetOp<InstShfl>();
  22. Operand pred = Register(op.DestPred, RegisterType.Predicate);
  23. Operand srcA = GetSrcReg(context, op.SrcA);
  24. Operand srcB = op.BFixShfl ? Const(op.SrcBImm) : GetSrcReg(context, op.SrcB);
  25. Operand srcC = op.CFixShfl ? Const(op.SrcCImm) : GetSrcReg(context, op.SrcC);
  26. (Operand res, Operand valid) = op.ShflMode switch
  27. {
  28. ShflMode.Idx => context.Shuffle(srcA, srcB, srcC),
  29. ShflMode.Up => context.ShuffleUp(srcA, srcB, srcC),
  30. ShflMode.Down => context.ShuffleDown(srcA, srcB, srcC),
  31. ShflMode.Bfly => context.ShuffleXor(srcA, srcB, srcC),
  32. _ => (null, null),
  33. };
  34. context.Copy(GetDest(op.Dest), res);
  35. context.Copy(pred, valid);
  36. }
  37. public static void Vote(EmitterContext context)
  38. {
  39. InstVote op = context.GetOp<InstVote>();
  40. Operand pred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
  41. Operand res = EmitVote(context, op.VoteMode, pred);
  42. if (res != null)
  43. {
  44. context.Copy(Register(op.VpDest, RegisterType.Predicate), res);
  45. }
  46. else
  47. {
  48. context.TranslatorContext.GpuAccessor.Log($"Invalid vote operation: {op.VoteMode}.");
  49. }
  50. if (op.Dest != RegisterConsts.RegisterZeroIndex)
  51. {
  52. context.Copy(GetDest(op.Dest), EmitBallot(context, pred));
  53. }
  54. }
  55. private static Operand EmitVote(EmitterContext context, VoteMode voteMode, Operand pred)
  56. {
  57. int subgroupSize = context.TranslatorContext.GpuAccessor.QueryHostSubgroupSize();
  58. if (subgroupSize <= 32)
  59. {
  60. return voteMode switch
  61. {
  62. VoteMode.All => context.VoteAll(pred),
  63. VoteMode.Any => context.VoteAny(pred),
  64. VoteMode.Eq => context.VoteAllEqual(pred),
  65. _ => null,
  66. };
  67. }
  68. // Emulate vote with ballot masks.
  69. // We do that when the GPU thread count is not 32,
  70. // since the shader code assumes it is 32.
  71. // allInvocations => ballot(pred) == ballot(true),
  72. // anyInvocation => ballot(pred) != 0,
  73. // allInvocationsEqual => ballot(pred) == balot(true) || ballot(pred) == 0
  74. Operand ballotMask = EmitBallot(context, pred);
  75. Operand AllTrue() => context.ICompareEqual(ballotMask, EmitBallot(context, Const(IrConsts.True)));
  76. return voteMode switch
  77. {
  78. VoteMode.All => AllTrue(),
  79. VoteMode.Any => context.ICompareNotEqual(ballotMask, Const(0)),
  80. VoteMode.Eq => context.BitwiseOr(AllTrue(), context.ICompareEqual(ballotMask, Const(0))),
  81. _ => null,
  82. };
  83. }
  84. private static Operand EmitBallot(EmitterContext context, Operand pred)
  85. {
  86. int subgroupSize = context.TranslatorContext.GpuAccessor.QueryHostSubgroupSize();
  87. if (subgroupSize <= 32)
  88. {
  89. return context.Ballot(pred, 0);
  90. }
  91. else if (subgroupSize == 64)
  92. {
  93. // TODO: Add support for vector destination and do that with a single operation.
  94. Operand laneId = context.Load(StorageKind.Input, IoVariable.SubgroupLaneId);
  95. Operand low = context.Ballot(pred, 0);
  96. Operand high = context.Ballot(pred, 1);
  97. return context.ConditionalSelect(context.BitwiseAnd(laneId, Const(32)), high, low);
  98. }
  99. else
  100. {
  101. // TODO: Add support for vector destination and do that with a single operation.
  102. Operand laneId = context.Load(StorageKind.Input, IoVariable.SubgroupLaneId);
  103. Operand element = context.ShiftRightU32(laneId, Const(5));
  104. Operand res = context.Ballot(pred, 0);
  105. res = context.ConditionalSelect(
  106. context.ICompareEqual(element, Const(1)),
  107. context.Ballot(pred, 1), res);
  108. res = context.ConditionalSelect(
  109. context.ICompareEqual(element, Const(2)),
  110. context.Ballot(pred, 2), res);
  111. res = context.ConditionalSelect(
  112. context.ICompareEqual(element, Const(3)),
  113. context.Ballot(pred, 3), res);
  114. return res;
  115. }
  116. }
  117. }
  118. }