diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index 12b7c2f0d0..e69e7dcbe9 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Version of the codegen (to be changed when codegen or guest format change). /// - private const ulong ShaderCodeGenVersion = 2697; + private const ulong ShaderCodeGenVersion = 2702; // Progress reporting helpers private volatile int _shaderCount; diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs index 8214c9f4b3..9cc591ca88 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs @@ -418,34 +418,6 @@ namespace Ryujinx.Graphics.Shader.Instructions context.Config.GpuAccessor.Log("Shader instruction Setlmembase is not implemented."); } - public static void ShfLR(EmitterContext context) - { - InstShfLR op = context.GetOp(); - - context.Config.GpuAccessor.Log("Shader instruction ShfLR is not implemented."); - } - - public static void ShfRR(EmitterContext context) - { - InstShfRR op = context.GetOp(); - - context.Config.GpuAccessor.Log("Shader instruction ShfRR is not implemented."); - } - - public static void ShfLI(EmitterContext context) - { - InstShfLI op = context.GetOp(); - - context.Config.GpuAccessor.Log("Shader instruction ShfLI is not implemented."); - } - - public static void ShfRI(EmitterContext context) - { - InstShfRI op = context.GetOp(); - - context.Config.GpuAccessor.Log("Shader instruction ShfRI is not implemented."); - } - public static void St(EmitterContext context) { InstSt op = context.GetOp(); diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitShift.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitShift.cs index ca053ab64a..2873cad889 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitShift.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitShift.cs @@ -9,6 +9,50 @@ namespace Ryujinx.Graphics.Shader.Instructions { static partial class InstEmit { + public static void ShfLR(EmitterContext context) + { + InstShfLR op = context.GetOp(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = GetSrcReg(context, op.SrcB); + var srcC = GetSrcReg(context, op.SrcC); + + EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: true, op.WriteCC); + } + + public static void ShfRR(EmitterContext context) + { + InstShfRR op = context.GetOp(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = GetSrcReg(context, op.SrcB); + var srcC = GetSrcReg(context, op.SrcC); + + EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: false, op.WriteCC); + } + + public static void ShfLI(EmitterContext context) + { + InstShfLI op = context.GetOp(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = Const(op.Imm6); + var srcC = GetSrcReg(context, op.SrcC); + + EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: true, op.WriteCC); + } + + public static void ShfRI(EmitterContext context) + { + InstShfRI op = context.GetOp(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = Const(op.Imm6); + var srcC = GetSrcReg(context, op.SrcC); + + EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: false, op.WriteCC); + } + public static void ShlR(EmitterContext context) { InstShlR op = context.GetOp(); @@ -60,6 +104,79 @@ namespace Ryujinx.Graphics.Shader.Instructions EmitShr(context, srcA, srcB, op.Dest, op.M, op.Brev, op.Signed); } + private static void EmitShf( + EmitterContext context, + MaxShift maxShift, + Operand srcA, + Operand srcB, + Operand srcC, + int rd, + bool mask, + bool left, + bool writeCC) + { + bool isLongShift = maxShift == MaxShift.U64 || maxShift == MaxShift.S64; + bool signedShift = maxShift == MaxShift.S64; + int maxShiftConst = isLongShift ? 64 : 32; + + if (mask) + { + srcB = context.BitwiseAnd(srcB, Const(maxShiftConst - 1)); + } + + Operand res; + + if (left) + { + // res = (C << B) | (A >> (32 - B)) + res = context.ShiftLeft(srcC, srcB); + res = context.BitwiseOr(res, context.ShiftRightU32(srcA, context.ISubtract(Const(32), srcB))); + + if (isLongShift) + { + // res = B >= 32 ? A << (B - 32) : res + Operand lowerShift = context.ShiftLeft(srcA, context.ISubtract(srcB, Const(32))); + + Operand shiftGreaterThan31 = context.ICompareGreaterOrEqualUnsigned(srcB, Const(32)); + res = context.ConditionalSelect(shiftGreaterThan31, lowerShift, res); + } + } + else + { + // res = (A >> B) | (C << (32 - B)) + res = context.ShiftRightU32(srcA, srcB); + res = context.BitwiseOr(res, context.ShiftLeft(srcC, context.ISubtract(Const(32), srcB))); + + if (isLongShift) + { + // res = B >= 32 ? C >> (B - 32) : res + Operand upperShift = signedShift + ? context.ShiftRightS32(srcC, context.ISubtract(srcB, Const(32))) + : context.ShiftRightU32(srcC, context.ISubtract(srcB, Const(32))); + + Operand shiftGreaterThan31 = context.ICompareGreaterOrEqualUnsigned(srcB, Const(32)); + res = context.ConditionalSelect(shiftGreaterThan31, upperShift, res); + } + } + + if (!mask) + { + // Clamped shift value. + Operand isLessThanMax = context.ICompareLessUnsigned(srcB, Const(maxShiftConst)); + + res = context.ConditionalSelect(isLessThanMax, res, Const(0)); + } + + context.Copy(GetDest(rd), res); + + if (writeCC) + { + InstEmitAluHelper.SetZnFlags(context, res, writeCC); + } + + // TODO: X. + } + private static void EmitShl(EmitterContext context, Operand srcA, Operand srcB, int rd, bool mask) { if (mask)