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