InstEmitVideoArithmetic.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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 Vmad(EmitterContext context)
  11. {
  12. InstVmad op = context.GetOp<InstVmad>();
  13. bool aSigned = (op.ASelect & VectorSelect.S8B0) != 0;
  14. bool bSigned = (op.BSelect & VectorSelect.S8B0) != 0;
  15. Operand srcA = InstEmitAluHelper.Extend(context, GetSrcReg(context, op.SrcA), op.ASelect);
  16. Operand srcC = context.INegate(GetSrcReg(context, op.SrcC), op.AvgMode == AvgMode.NegB);
  17. Operand srcB;
  18. if (op.BVideo)
  19. {
  20. srcB = InstEmitAluHelper.Extend(context, GetSrcReg(context, op.SrcB), op.BSelect);
  21. }
  22. else
  23. {
  24. int imm = op.Imm16;
  25. if (bSigned)
  26. {
  27. imm = (imm << 16) >> 16;
  28. }
  29. srcB = Const(imm);
  30. }
  31. Operand productLow = context.IMultiply(srcA, srcB);
  32. Operand productHigh;
  33. if (aSigned == bSigned)
  34. {
  35. productHigh = aSigned
  36. ? context.MultiplyHighS32(srcA, srcB)
  37. : context.MultiplyHighU32(srcA, srcB);
  38. }
  39. else
  40. {
  41. Operand temp = aSigned
  42. ? context.IMultiply(srcB, context.ShiftRightS32(srcA, Const(31)))
  43. : context.IMultiply(srcA, context.ShiftRightS32(srcB, Const(31)));
  44. productHigh = context.IAdd(temp, context.MultiplyHighU32(srcA, srcB));
  45. }
  46. if (op.AvgMode == AvgMode.NegA)
  47. {
  48. (productLow, productHigh) = InstEmitAluHelper.NegateLong(context, productLow, productHigh);
  49. }
  50. Operand resLow = InstEmitAluHelper.AddWithCarry(context, productLow, srcC, out Operand sumCarry);
  51. Operand resHigh = context.IAdd(productHigh, sumCarry);
  52. if (op.AvgMode == AvgMode.PlusOne)
  53. {
  54. resLow = InstEmitAluHelper.AddWithCarry(context, resLow, Const(1), out Operand poCarry);
  55. resHigh = context.IAdd(resHigh, poCarry);
  56. }
  57. bool resSigned = op.ASelect == VectorSelect.S32 ||
  58. op.BSelect == VectorSelect.S32 ||
  59. op.AvgMode == AvgMode.NegB ||
  60. op.AvgMode == AvgMode.NegA;
  61. int shift = op.VideoScale switch
  62. {
  63. VideoScale.Shr7 => 7,
  64. VideoScale.Shr15 => 15,
  65. _ => 0
  66. };
  67. if (shift != 0)
  68. {
  69. // Low = (Low >> Shift) | (High << (32 - Shift))
  70. // High >>= Shift
  71. resLow = context.ShiftRightU32(resLow, Const(shift));
  72. resLow = context.BitwiseOr(resLow, context.ShiftLeft(resHigh, Const(32 - shift)));
  73. resHigh = resSigned
  74. ? context.ShiftRightS32(resHigh, Const(shift))
  75. : context.ShiftRightU32(resHigh, Const(shift));
  76. }
  77. Operand res = resLow;
  78. if (op.Sat)
  79. {
  80. Operand sign = context.ShiftRightS32(resHigh, Const(31));
  81. if (resSigned)
  82. {
  83. Operand overflow = context.ICompareNotEqual(resHigh, context.ShiftRightS32(resLow, Const(31)));
  84. Operand clampValue = context.ConditionalSelect(sign, Const(int.MinValue), Const(int.MaxValue));
  85. res = context.ConditionalSelect(overflow, clampValue, resLow);
  86. }
  87. else
  88. {
  89. Operand overflow = context.ICompareNotEqual(resHigh, Const(0));
  90. res = context.ConditionalSelect(overflow, context.BitwiseNot(sign), resLow);
  91. }
  92. }
  93. context.Copy(GetDest(op.Dest), res);
  94. // TODO: CC.
  95. }
  96. }
  97. }