From 6adf15e479b684cad7a783e7a1a056be087fdc02 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sat, 21 Jan 2023 12:18:05 -0300 Subject: [PATCH] Implement CSET and CSETP shader instructions (#4318) * Implement CSET and CSETP shader instructions * Shader cache version bump * Fix CC.HI --- .../Shader/DiskCache/DiskCacheHostStorage.cs | 2 +- .../Decoders/InstDecoders.cs | 1 + .../Instructions/InstEmit.cs | 7 -- .../Instructions/InstEmitConditionCode.cs | 87 +++++++++++++++++++ .../Instructions/InstEmitFlowControl.cs | 18 +--- .../Instructions/InstEmitIntegerComparison.cs | 17 ---- 6 files changed, 90 insertions(+), 42 deletions(-) create mode 100644 Ryujinx.Graphics.Shader/Instructions/InstEmitConditionCode.cs diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs index 2622ea3e8f..9f436502f1 100644 --- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs +++ b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMinor = 2; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; - private const uint CodeGenVersion = 3939; + private const uint CodeGenVersion = 4318; private const string SharedTocFileName = "shared.toc"; private const string SharedDataFileName = "shared.data"; diff --git a/Ryujinx.Graphics.Shader/Decoders/InstDecoders.cs b/Ryujinx.Graphics.Shader/Decoders/InstDecoders.cs index 98a4364070..0c22ddc051 100644 --- a/Ryujinx.Graphics.Shader/Decoders/InstDecoders.cs +++ b/Ryujinx.Graphics.Shader/Decoders/InstDecoders.cs @@ -91,6 +91,7 @@ namespace Ryujinx.Graphics.Shader.Decoders Neu = 13, Geu = 14, T = 15, + Off = 16, Lo = 17, Sff = 18, Ls = 19, diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs index c242963a6d..3a9e658aa8 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs @@ -54,13 +54,6 @@ namespace Ryujinx.Graphics.Shader.Instructions context.Config.GpuAccessor.Log("Shader instruction Cctlt is not implemented."); } - public static void Cset(EmitterContext context) - { - InstCset op = context.GetOp(); - - context.Config.GpuAccessor.Log("Shader instruction Cset is not implemented."); - } - public static void Cs2r(EmitterContext context) { InstCs2r op = context.GetOp(); diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitConditionCode.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitConditionCode.cs new file mode 100644 index 0000000000..74ac760298 --- /dev/null +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitConditionCode.cs @@ -0,0 +1,87 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Translation; + +using static Ryujinx.Graphics.Shader.Instructions.InstEmitAluHelper; +using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper; +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + static partial class InstEmit + { + public static void Cset(EmitterContext context) + { + InstCset op = context.GetOp(); + + Operand res = GetCondition(context, op.Ccc); + Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv); + + res = GetPredLogicalOp(context, op.Bop, res, srcPred); + + Operand dest = GetDest(op.Dest); + + if (op.BVal) + { + context.Copy(dest, context.ConditionalSelect(res, ConstF(1), Const(0))); + } + else + { + context.Copy(dest, res); + } + + // TODO: CC. + } + + public static void Csetp(EmitterContext context) + { + InstCsetp op = context.GetOp(); + + Operand p0Res = GetCondition(context, op.Ccc); + Operand p1Res = context.BitwiseNot(p0Res); + Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv); + + p0Res = GetPredLogicalOp(context, op.Bop, p0Res, srcPred); + p1Res = GetPredLogicalOp(context, op.Bop, p1Res, srcPred); + + context.Copy(Register(op.DestPred, RegisterType.Predicate), p0Res); + context.Copy(Register(op.DestPredInv, RegisterType.Predicate), p1Res); + + // TODO: CC. + } + + private static Operand GetCondition(EmitterContext context, Ccc cond, int defaultCond = IrConsts.True) + { + return cond switch + { + Ccc.F => Const(IrConsts.False), + Ccc.Lt => context.BitwiseExclusiveOr(context.BitwiseAnd(GetNF(), context.BitwiseNot(GetZF())), GetVF()), + Ccc.Eq => context.BitwiseAnd(context.BitwiseNot(GetNF()), GetZF()), + Ccc.Le => context.BitwiseExclusiveOr(GetNF(), context.BitwiseOr(GetZF(), GetVF())), + Ccc.Gt => context.BitwiseNot(context.BitwiseOr(context.BitwiseExclusiveOr(GetNF(), GetVF()), GetZF())), + Ccc.Ne => context.BitwiseNot(GetZF()), + Ccc.Ge => context.BitwiseNot(context.BitwiseExclusiveOr(GetNF(), GetVF())), + Ccc.Num => context.BitwiseNot(context.BitwiseAnd(GetNF(), GetZF())), + Ccc.Nan => context.BitwiseAnd(GetNF(), GetZF()), + Ccc.Ltu => context.BitwiseExclusiveOr(GetNF(), GetVF()), + Ccc.Equ => GetZF(), + Ccc.Leu => context.BitwiseOr(context.BitwiseExclusiveOr(GetNF(), GetVF()), GetZF()), + Ccc.Gtu => context.BitwiseExclusiveOr(context.BitwiseNot(GetNF()), context.BitwiseOr(GetVF(), GetZF())), + Ccc.Neu => context.BitwiseOr(GetNF(), context.BitwiseNot(GetZF())), + Ccc.Geu => context.BitwiseExclusiveOr(context.BitwiseOr(context.BitwiseNot(GetNF()), GetZF()), GetVF()), + Ccc.T => Const(IrConsts.True), + Ccc.Off => context.BitwiseNot(GetVF()), + Ccc.Lo => context.BitwiseNot(GetCF()), + Ccc.Sff => context.BitwiseNot(GetNF()), + Ccc.Ls => context.BitwiseOr(GetZF(), context.BitwiseNot(GetCF())), + Ccc.Hi => context.BitwiseAnd(GetCF(), context.BitwiseNot(GetZF())), + Ccc.Sft => GetNF(), + Ccc.Hs => GetCF(), + Ccc.Oft => GetVF(), + Ccc.Rle => context.BitwiseOr(GetNF(), GetZF()), + Ccc.Rgt => context.BitwiseNot(context.BitwiseOr(GetNF(), GetZF())), + _ => Const(defaultCond) + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitFlowControl.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitFlowControl.cs index f1dd279c87..91c2323037 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitFlowControl.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitFlowControl.cs @@ -257,7 +257,7 @@ namespace Ryujinx.Graphics.Shader.Instructions } else { - // TODO: Support CC here aswell (condition). + // TODO: Support CC here as well (condition). foreach (SyncTarget target in targets.Values) { PushOpInfo pushOpInfo = target.PushOpInfo; @@ -318,21 +318,5 @@ namespace Ryujinx.Graphics.Shader.Instructions context.BranchIfTrue(label, pred); } } - - private static Operand GetCondition(EmitterContext context, Ccc cond, int defaultCond = IrConsts.True) - { - // TODO: More condition codes, figure out how they work. - switch (cond) - { - case Ccc.Eq: - case Ccc.Equ: - return GetZF(); - case Ccc.Ne: - case Ccc.Neu: - return context.BitwiseNot(GetZF()); - } - - return Const(defaultCond); - } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitIntegerComparison.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitIntegerComparison.cs index ddd90f8e81..dcdb189fbc 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitIntegerComparison.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitIntegerComparison.cs @@ -11,23 +11,6 @@ namespace Ryujinx.Graphics.Shader.Instructions { static partial class InstEmit { - public static void Csetp(EmitterContext context) - { - InstCsetp op = context.GetOp(); - - // TODO: Implement that properly. - - Operand p0Res = Const(IrConsts.True); - Operand p1Res = context.BitwiseNot(p0Res); - Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv); - - p0Res = GetPredLogicalOp(context, op.Bop, p0Res, srcPred); - p1Res = GetPredLogicalOp(context, op.Bop, p1Res, srcPred); - - context.Copy(Register(op.DestPred, RegisterType.Predicate), p0Res); - context.Copy(Register(op.DestPredInv, RegisterType.Predicate), p1Res); - } - public static void IcmpR(EmitterContext context) { InstIcmpR op = context.GetOp();