diff options
Diffstat (limited to 'Ryujinx.Graphics.Shader/Instructions')
7 files changed, 249 insertions, 106 deletions
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs index c5a1e135..b0cb7028 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs @@ -75,69 +75,6 @@ namespace Ryujinx.Graphics.Shader.Instructions context.Config.GpuAccessor.Log("Shader instruction Cs2r is not implemented."); } - public static void DmnmxR(EmitterContext context) - { - InstDmnmxR op = context.GetOp<InstDmnmxR>(); - - context.Config.GpuAccessor.Log("Shader instruction DmnmxR is not implemented."); - } - - public static void DmnmxI(EmitterContext context) - { - InstDmnmxI op = context.GetOp<InstDmnmxI>(); - - context.Config.GpuAccessor.Log("Shader instruction DmnmxI is not implemented."); - } - - public static void DmnmxC(EmitterContext context) - { - InstDmnmxC op = context.GetOp<InstDmnmxC>(); - - context.Config.GpuAccessor.Log("Shader instruction DmnmxC is not implemented."); - } - - public static void DsetR(EmitterContext context) - { - InstDsetR op = context.GetOp<InstDsetR>(); - - context.Config.GpuAccessor.Log("Shader instruction DsetR is not implemented."); - } - - public static void DsetI(EmitterContext context) - { - InstDsetI op = context.GetOp<InstDsetI>(); - - context.Config.GpuAccessor.Log("Shader instruction DsetI is not implemented."); - } - - public static void DsetC(EmitterContext context) - { - InstDsetC op = context.GetOp<InstDsetC>(); - - context.Config.GpuAccessor.Log("Shader instruction DsetC is not implemented."); - } - - public static void DsetpR(EmitterContext context) - { - InstDsetpR op = context.GetOp<InstDsetpR>(); - - context.Config.GpuAccessor.Log("Shader instruction DsetpR is not implemented."); - } - - public static void DsetpI(EmitterContext context) - { - InstDsetpI op = context.GetOp<InstDsetpI>(); - - context.Config.GpuAccessor.Log("Shader instruction DsetpI is not implemented."); - } - - public static void DsetpC(EmitterContext context) - { - InstDsetpC op = context.GetOp<InstDsetpC>(); - - context.Config.GpuAccessor.Log("Shader instruction DsetpC is not implemented."); - } - public static void FchkR(EmitterContext context) { InstFchkR op = context.GetOp<InstFchkR>(); diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitConversion.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitConversion.cs index 62124554..bebd96dd 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitConversion.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitConversion.cs @@ -98,7 +98,7 @@ namespace Ryujinx.Graphics.Shader.Instructions var src = GetSrcReg(context, op.SrcB); - EmitI2I(context, op.ISrcFmt, op.IDstFmt, src, op.ByteSel, op.Dest, op.AbsB, op.NegB, op.Sat); + EmitI2I(context, op.ISrcFmt, op.IDstFmt, src, op.ByteSel, op.Dest, op.AbsB, op.NegB, op.Sat, op.WriteCC); } public static void I2iI(EmitterContext context) @@ -107,7 +107,7 @@ namespace Ryujinx.Graphics.Shader.Instructions var src = GetSrcImm(context, Imm20ToSInt(op.Imm20)); - EmitI2I(context, op.ISrcFmt, op.IDstFmt, src, op.ByteSel, op.Dest, op.AbsB, op.NegB, op.Sat); + EmitI2I(context, op.ISrcFmt, op.IDstFmt, src, op.ByteSel, op.Dest, op.AbsB, op.NegB, op.Sat, op.WriteCC); } public static void I2iC(EmitterContext context) @@ -116,7 +116,7 @@ namespace Ryujinx.Graphics.Shader.Instructions var src = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset); - EmitI2I(context, op.ISrcFmt, op.IDstFmt, src, op.ByteSel, op.Dest, op.AbsB, op.NegB, op.Sat); + EmitI2I(context, op.ISrcFmt, op.IDstFmt, src, op.ByteSel, op.Dest, op.AbsB, op.NegB, op.Sat, op.WriteCC); } private static void EmitF2F( @@ -176,7 +176,6 @@ namespace Ryujinx.Graphics.Shader.Instructions if (dstType == IDstFmt.U64) { context.Config.GpuAccessor.Log("Unimplemented 64-bits F2I."); - return; } Instruction fpType = srcType.ToInstFPType(); @@ -198,7 +197,9 @@ namespace Ryujinx.Graphics.Shader.Instructions if (!isSignedInt) { // Negative float to uint cast is undefined, so we clamp the value before conversion. - srcB = context.FPMaximum(srcB, ConstF(0), fpType); + Operand c0 = srcType == DstFmt.F64 ? context.PackDouble2x32(0.0) : ConstF(0); + + srcB = context.FPMaximum(srcB, c0, fpType); } if (srcType == DstFmt.F64) @@ -292,7 +293,8 @@ namespace Ryujinx.Graphics.Shader.Instructions int rd, bool absolute, bool negate, - bool saturate) + bool saturate, + bool writeCC) { if ((srcType & ~ISrcDstFmt.S8) > ISrcDstFmt.U32 || (dstType & ~ISrcDstFmt.S8) > ISrcDstFmt.U32) { @@ -337,7 +339,7 @@ namespace Ryujinx.Graphics.Shader.Instructions context.Copy(GetDest(rd), src); - // TODO: CC. + SetZnFlags(context, src, writeCC); } private static Operand UnpackReg(EmitterContext context, DstFmt floatType, bool h, int reg) diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitFloatArithmetic.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitFloatArithmetic.cs index 2318f2b7..11d724c4 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitFloatArithmetic.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitFloatArithmetic.cs @@ -528,18 +528,5 @@ namespace Ryujinx.Graphics.Shader.Instructions context.Copy(GetDest(rd), GetHalfPacked(context, swizzle, res, rd)); } - - private static void SetDest(EmitterContext context, Operand value, int rd, bool isFP64) - { - if (isFP64) - { - context.Copy(GetDest(rd), context.UnpackDouble2x32Low(value)); - context.Copy(GetDest2(rd), context.UnpackDouble2x32High(value)); - } - else - { - context.Copy(GetDest(rd), value); - } - } } }
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitFloatComparison.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitFloatComparison.cs index b7b5f9ba..8f99ddb3 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitFloatComparison.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitFloatComparison.cs @@ -11,6 +11,156 @@ namespace Ryujinx.Graphics.Shader.Instructions { static partial class InstEmit { + public static void DsetR(EmitterContext context) + { + InstDsetR op = context.GetOp<InstDsetR>(); + + var srcA = GetSrcReg(context, op.SrcA, isFP64: true); + var srcB = GetSrcReg(context, op.SrcB, isFP64: true); + + EmitFset( + context, + op.FComp, + op.Bop, + srcA, + srcB, + op.SrcPred, + op.SrcPredInv, + op.Dest, + op.AbsA, + op.AbsB, + op.NegA, + op.NegB, + op.BVal, + op.WriteCC, + isFP64: true); + } + + public static void DsetI(EmitterContext context) + { + InstDsetI op = context.GetOp<InstDsetI>(); + + var srcA = GetSrcReg(context, op.SrcA, isFP64: true); + var srcB = GetSrcImm(context, Imm20ToFloat(op.Imm20), isFP64: true); + + EmitFset( + context, + op.FComp, + op.Bop, + srcA, + srcB, + op.SrcPred, + op.SrcPredInv, + op.Dest, + op.AbsA, + op.AbsB, + op.NegA, + op.NegB, + op.BVal, + op.WriteCC, + isFP64: true); + } + + public static void DsetC(EmitterContext context) + { + InstDsetC op = context.GetOp<InstDsetC>(); + + var srcA = GetSrcReg(context, op.SrcA, isFP64: true); + var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset, isFP64: true); + + EmitFset( + context, + op.FComp, + op.Bop, + srcA, + srcB, + op.SrcPred, + op.SrcPredInv, + op.Dest, + op.AbsA, + op.AbsB, + op.NegA, + op.NegB, + op.BVal, + op.WriteCC, + isFP64: true); + } + + public static void DsetpR(EmitterContext context) + { + InstDsetpR op = context.GetOp<InstDsetpR>(); + + var srcA = GetSrcReg(context, op.SrcA, isFP64: true); + var srcB = GetSrcReg(context, op.SrcB, isFP64: true); + + EmitFsetp( + context, + op.FComp, + op.Bop, + srcA, + srcB, + op.SrcPred, + op.SrcPredInv, + op.DestPred, + op.DestPredInv, + op.AbsA, + op.AbsB, + op.NegA, + op.NegB, + writeCC: false, + isFP64: true); + } + + public static void DsetpI(EmitterContext context) + { + InstDsetpI op = context.GetOp<InstDsetpI>(); + + var srcA = GetSrcReg(context, op.SrcA, isFP64: true); + var srcB = GetSrcImm(context, Imm20ToFloat(op.Imm20), isFP64: true); + + EmitFsetp( + context, + op.FComp, + op.Bop, + srcA, + srcB, + op.SrcPred, + op.SrcPredInv, + op.DestPred, + op.DestPredInv, + op.AbsA, + op.AbsB, + op.NegA, + op.NegB, + writeCC: false, + isFP64: true); + } + + public static void DsetpC(EmitterContext context) + { + InstDsetpC op = context.GetOp<InstDsetpC>(); + + var srcA = GetSrcReg(context, op.SrcA, isFP64: true); + var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset, isFP64: true); + + EmitFsetp( + context, + op.FComp, + op.Bop, + srcA, + srcB, + op.SrcPred, + op.SrcPredInv, + op.DestPred, + op.DestPredInv, + op.AbsA, + op.AbsB, + op.NegA, + op.NegB, + writeCC: false, + isFP64: true); + } + public static void FcmpR(EmitterContext context) { InstFcmpR op = context.GetOp<InstFcmpR>(); @@ -240,12 +390,15 @@ namespace Ryujinx.Graphics.Shader.Instructions bool negateA, bool negateB, bool boolFloat, - bool writeCC) + bool writeCC, + bool isFP64 = false) { - srcA = context.FPAbsNeg(srcA, absoluteA, negateA); - srcB = context.FPAbsNeg(srcB, absoluteB, negateB); + Instruction fpType = isFP64 ? Instruction.FP64 : Instruction.FP32; + + srcA = context.FPAbsNeg(srcA, absoluteA, negateA, fpType); + srcB = context.FPAbsNeg(srcB, absoluteB, negateB, fpType); - Operand res = GetFPComparison(context, cmpOp, srcA, srcB); + Operand res = GetFPComparison(context, cmpOp, srcA, srcB, fpType); Operand pred = GetPredicate(context, srcPred, srcPredInv); res = GetPredLogicalOp(context, logicOp, res, pred); @@ -282,12 +435,15 @@ namespace Ryujinx.Graphics.Shader.Instructions bool absoluteB, bool negateA, bool negateB, - bool writeCC) + bool writeCC, + bool isFP64 = false) { - srcA = context.FPAbsNeg(srcA, absoluteA, negateA); - srcB = context.FPAbsNeg(srcB, absoluteB, negateB); + Instruction fpType = isFP64 ? Instruction.FP64 : Instruction.FP32; + + srcA = context.FPAbsNeg(srcA, absoluteA, negateA, fpType); + srcB = context.FPAbsNeg(srcB, absoluteB, negateB, fpType); - Operand p0Res = GetFPComparison(context, cmpOp, srcA, srcB); + Operand p0Res = GetFPComparison(context, cmpOp, srcA, srcB, fpType); Operand p1Res = context.BitwiseNot(p0Res); Operand pred = GetPredicate(context, srcPred, srcPredInv); @@ -367,7 +523,7 @@ namespace Ryujinx.Graphics.Shader.Instructions context.Copy(Register(destPredInv, RegisterType.Predicate), p1Res); } - private static Operand GetFPComparison(EmitterContext context, FComp cond, Operand srcA, Operand srcB) + private static Operand GetFPComparison(EmitterContext context, FComp cond, Operand srcA, Operand srcB, Instruction fpType = Instruction.FP32) { Operand res; @@ -381,7 +537,7 @@ namespace Ryujinx.Graphics.Shader.Instructions } else if (cond == FComp.Nan || cond == FComp.Num) { - res = context.BitwiseOr(context.IsNan(srcA), context.IsNan(srcB)); + res = context.BitwiseOr(context.IsNan(srcA, fpType), context.IsNan(srcB, fpType)); if (cond == FComp.Num) { @@ -404,12 +560,12 @@ namespace Ryujinx.Graphics.Shader.Instructions default: throw new ArgumentException($"Unexpected condition \"{cond}\"."); } - res = context.Add(inst | Instruction.FP32, Local(), srcA, srcB); + res = context.Add(inst | fpType, Local(), srcA, srcB); if ((cond & FComp.Nan) != 0) { - res = context.BitwiseOr(res, context.IsNan(srcA)); - res = context.BitwiseOr(res, context.IsNan(srcB)); + res = context.BitwiseOr(res, context.IsNan(srcA, fpType)); + res = context.BitwiseOr(res, context.IsNan(srcB, fpType)); } } diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitFloatMinMax.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitFloatMinMax.cs index 3e91fc8a..412a5305 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitFloatMinMax.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitFloatMinMax.cs @@ -9,6 +9,39 @@ namespace Ryujinx.Graphics.Shader.Instructions { static partial class InstEmit { + public static void DmnmxR(EmitterContext context) + { + InstDmnmxR op = context.GetOp<InstDmnmxR>(); + + var srcA = GetSrcReg(context, op.SrcA, isFP64: true); + var srcB = GetSrcReg(context, op.SrcB, isFP64: true); + var srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv); + + EmitFmnmx(context, srcA, srcB, srcPred, op.Dest, op.AbsA, op.AbsB, op.NegA, op.NegB, op.WriteCC, isFP64: true); + } + + public static void DmnmxI(EmitterContext context) + { + InstDmnmxI op = context.GetOp<InstDmnmxI>(); + + var srcA = GetSrcReg(context, op.SrcA, isFP64: true); + var srcB = GetSrcImm(context, Imm20ToFloat(op.Imm20), isFP64: true); + var srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv); + + EmitFmnmx(context, srcA, srcB, srcPred, op.Dest, op.AbsA, op.AbsB, op.NegA, op.NegB, op.WriteCC, isFP64: true); + } + + public static void DmnmxC(EmitterContext context) + { + InstDmnmxC op = context.GetOp<InstDmnmxC>(); + + var srcA = GetSrcReg(context, op.SrcA, isFP64: true); + var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset, isFP64: true); + var srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv); + + EmitFmnmx(context, srcA, srcB, srcPred, op.Dest, op.AbsA, op.AbsB, op.NegA, op.NegB, op.WriteCC, isFP64: true); + } + public static void FmnmxR(EmitterContext context) { InstFmnmxR op = context.GetOp<InstFmnmxR>(); @@ -52,19 +85,22 @@ namespace Ryujinx.Graphics.Shader.Instructions bool absoluteB, bool negateA, bool negateB, - bool writeCC) + bool writeCC, + bool isFP64 = false) { - srcA = context.FPAbsNeg(srcA, absoluteA, negateA); - srcB = context.FPAbsNeg(srcB, absoluteB, negateB); + Instruction fpType = isFP64 ? Instruction.FP64 : Instruction.FP32; + + srcA = context.FPAbsNeg(srcA, absoluteA, negateA, fpType); + srcB = context.FPAbsNeg(srcB, absoluteB, negateB, fpType); - Operand resMin = context.FPMinimum(srcA, srcB); - Operand resMax = context.FPMaximum(srcA, srcB); + Operand resMin = context.FPMinimum(srcA, srcB, fpType); + Operand resMax = context.FPMaximum(srcA, srcB, fpType); - Operand dest = GetDest(rd); + Operand res = context.ConditionalSelect(srcPred, resMin, resMax); - context.Copy(dest, context.ConditionalSelect(srcPred, resMin, resMax)); + SetDest(context, res, rd, isFP64); - SetFPZnFlags(context, dest, writeCC); + SetFPZnFlags(context, res, writeCC, fpType); } } }
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs index 9f5bbdf7..dd6ff8e9 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs @@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.Shader.Instructions { if (isFP64) { - return context.FP32ConvertToFP64(Const(imm)); + return context.PackDouble2x32(Const(0), Const(imm)); } else { @@ -218,6 +218,19 @@ namespace Ryujinx.Graphics.Shader.Instructions return local; } + public static void SetDest(EmitterContext context, Operand value, int rd, bool isFP64) + { + if (isFP64) + { + context.Copy(GetDest(rd), context.UnpackDouble2x32Low(value)); + context.Copy(GetDest2(rd), context.UnpackDouble2x32High(value)); + } + else + { + context.Copy(GetDest(rd), value); + } + } + public static int Imm16ToSInt(int imm16) { return (short)imm16; diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMultifunction.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMultifunction.cs index 465024eb..1ea7d321 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMultifunction.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMultifunction.cs @@ -61,11 +61,23 @@ namespace Ryujinx.Graphics.Shader.Instructions res = context.FPReciprocalSquareRoot(res); break; + case MufuOp.Rcp64h: + res = context.PackDouble2x32(OperandHelper.Const(0), res); + res = context.UnpackDouble2x32High(context.FPReciprocal(res, Instruction.FP64)); + break; + + case MufuOp.Rsq64h: + res = context.PackDouble2x32(OperandHelper.Const(0), res); + res = context.UnpackDouble2x32High(context.FPReciprocalSquareRoot(res, Instruction.FP64)); + break; + case MufuOp.Sqrt: res = context.FPSquareRoot(res); break; - default: /* TODO */ break; + default: + context.Config.GpuAccessor.Log($"Invalid MUFU operation \"{op.MufuOp}\"."); + break; } context.Copy(GetDest(op.Dest), context.FPSaturate(res, op.Sat)); |
