From 98d0240ce66f682e10efc3f826a61fc22b633183 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 27 Jan 2021 05:19:30 -0300 Subject: [PATCH 1/7] Support shader F32 to Bool reinterpretation (#1969) --- Ryujinx.Graphics.Shader/CodeGen/Glsl/TypeConversion.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/TypeConversion.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/TypeConversion.cs index 7adc5ad33..b13a74f45 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/TypeConversion.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/TypeConversion.cs @@ -37,8 +37,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl { switch (dstType) { - case VariableType.S32: return $"floatBitsToInt({expr})"; - case VariableType.U32: return $"floatBitsToUint({expr})"; + case VariableType.Bool: return $"(floatBitsToInt({expr}) != 0)"; + case VariableType.S32: return $"floatBitsToInt({expr})"; + case VariableType.U32: return $"floatBitsToUint({expr})"; } } else if (dstType == VariableType.F32) From dcce4070719a3798bb96d3aa02b9ba02a7fecc16 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 27 Jan 2021 20:23:00 -0300 Subject: [PATCH 2/7] Lower precision of estimate instruction results to match Arm behavior (#1943) * Lower precision of estimate instruction results to match Arm behavior * PTC version update * Nits --- .../Instructions/InstEmitSimdArithmetic.cs | 83 +++++++++++++++---- ARMeilleure/Translation/PTC/Ptc.cs | 2 +- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs index f18b91cfc..deaa6f5ac 100644 --- a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs +++ b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs @@ -1475,9 +1475,11 @@ namespace ARMeilleure.Instructions int sizeF = op.Size & 1; - if (Optimizations.FastFP && Optimizations.UseSse && sizeF == 0) + if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0) { - EmitScalarUnaryOpF(context, Intrinsic.X86Rcpss, 0); + Operand res = EmitSse41FP32RoundExp8(context, context.AddIntrinsic(Intrinsic.X86Rcpss, GetVec(op.Rn)), scalar: true); + + context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res)); } else { @@ -1494,9 +1496,16 @@ namespace ARMeilleure.Instructions int sizeF = op.Size & 1; - if (Optimizations.FastFP && Optimizations.UseSse && sizeF == 0) + if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0) { - EmitVectorUnaryOpF(context, Intrinsic.X86Rcpps, 0); + Operand res = EmitSse41FP32RoundExp8(context, context.AddIntrinsic(Intrinsic.X86Rcpps, GetVec(op.Rn)), scalar: false); + + if (op.RegisterSize == RegisterSize.Simd64) + { + res = context.VectorZeroUpper64(res); + } + + context.Copy(GetVec(op.Rd), res); } else { @@ -1652,7 +1661,7 @@ namespace ARMeilleure.Instructions { if (Optimizations.UseSse41) { - EmitScalarRoundOpF(context, FPRoundingMode.TowardsMinusInfinity); + EmitSse41ScalarRoundOpF(context, FPRoundingMode.TowardsMinusInfinity); } else { @@ -1667,7 +1676,7 @@ namespace ARMeilleure.Instructions { if (Optimizations.UseSse41) { - EmitVectorRoundOpF(context, FPRoundingMode.TowardsMinusInfinity); + EmitSse41VectorRoundOpF(context, FPRoundingMode.TowardsMinusInfinity); } else { @@ -1682,7 +1691,7 @@ namespace ARMeilleure.Instructions { if (Optimizations.UseSse41) { - EmitScalarRoundOpF(context, FPRoundingMode.ToNearest); + EmitSse41ScalarRoundOpF(context, FPRoundingMode.ToNearest); } else { @@ -1697,7 +1706,7 @@ namespace ARMeilleure.Instructions { if (Optimizations.UseSse41) { - EmitVectorRoundOpF(context, FPRoundingMode.ToNearest); + EmitSse41VectorRoundOpF(context, FPRoundingMode.ToNearest); } else { @@ -1712,7 +1721,7 @@ namespace ARMeilleure.Instructions { if (Optimizations.UseSse41) { - EmitScalarRoundOpF(context, FPRoundingMode.TowardsPlusInfinity); + EmitSse41ScalarRoundOpF(context, FPRoundingMode.TowardsPlusInfinity); } else { @@ -1727,7 +1736,7 @@ namespace ARMeilleure.Instructions { if (Optimizations.UseSse41) { - EmitVectorRoundOpF(context, FPRoundingMode.TowardsPlusInfinity); + EmitSse41VectorRoundOpF(context, FPRoundingMode.TowardsPlusInfinity); } else { @@ -1778,7 +1787,7 @@ namespace ARMeilleure.Instructions { if (Optimizations.UseSse41) { - EmitScalarRoundOpF(context, FPRoundingMode.TowardsZero); + EmitSse41ScalarRoundOpF(context, FPRoundingMode.TowardsZero); } else { @@ -1793,7 +1802,7 @@ namespace ARMeilleure.Instructions { if (Optimizations.UseSse41) { - EmitVectorRoundOpF(context, FPRoundingMode.TowardsZero); + EmitSse41VectorRoundOpF(context, FPRoundingMode.TowardsZero); } else { @@ -1810,9 +1819,11 @@ namespace ARMeilleure.Instructions int sizeF = op.Size & 1; - if (Optimizations.FastFP && Optimizations.UseSse && sizeF == 0) + if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0) { - EmitScalarUnaryOpF(context, Intrinsic.X86Rsqrtss, 0); + Operand res = EmitSse41FP32RoundExp8(context, context.AddIntrinsic(Intrinsic.X86Rsqrtss, GetVec(op.Rn)), scalar: true); + + context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res)); } else { @@ -1829,9 +1840,16 @@ namespace ARMeilleure.Instructions int sizeF = op.Size & 1; - if (Optimizations.FastFP && Optimizations.UseSse && sizeF == 0) + if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0) { - EmitVectorUnaryOpF(context, Intrinsic.X86Rsqrtps, 0); + Operand res = EmitSse41FP32RoundExp8(context, context.AddIntrinsic(Intrinsic.X86Rsqrtps, GetVec(op.Rn)), scalar: false); + + if (op.RegisterSize == RegisterSize.Simd64) + { + res = context.VectorZeroUpper64(res); + } + + context.Copy(GetVec(op.Rd), res); } else { @@ -3498,7 +3516,7 @@ namespace ARMeilleure.Instructions return context.ConditionalSelect(cmp, op1, op2); } - private static void EmitScalarRoundOpF(ArmEmitterContext context, FPRoundingMode roundMode) + private static void EmitSse41ScalarRoundOpF(ArmEmitterContext context, FPRoundingMode roundMode) { OpCodeSimd op = (OpCodeSimd)context.CurrOp; @@ -3520,7 +3538,7 @@ namespace ARMeilleure.Instructions context.Copy(GetVec(op.Rd), res); } - private static void EmitVectorRoundOpF(ArmEmitterContext context, FPRoundingMode roundMode) + private static void EmitSse41VectorRoundOpF(ArmEmitterContext context, FPRoundingMode roundMode) { OpCodeSimd op = (OpCodeSimd)context.CurrOp; @@ -3538,6 +3556,35 @@ namespace ARMeilleure.Instructions context.Copy(GetVec(op.Rd), res); } + private static Operand EmitSse41FP32RoundExp8(ArmEmitterContext context, Operand value, bool scalar) + { + Operand roundMask; + Operand truncMask; + Operand expMask; + + if (scalar) + { + roundMask = X86GetScalar(context, 0x4000); + truncMask = X86GetScalar(context, unchecked((int)0xFFFF8000)); + expMask = X86GetScalar(context, 0x7F800000); + } + else + { + roundMask = X86GetAllElements(context, 0x4000); + truncMask = X86GetAllElements(context, unchecked((int)0xFFFF8000)); + expMask = X86GetAllElements(context, 0x7F800000); + } + + Operand oValue = value; + Operand masked = context.AddIntrinsic(Intrinsic.X86Pand, value, expMask); + Operand isNaNInf = context.AddIntrinsic(Intrinsic.X86Pcmpeqw, masked, expMask); + + value = context.AddIntrinsic(Intrinsic.X86Paddw, value, roundMask); + value = context.AddIntrinsic(Intrinsic.X86Pand, value, truncMask); + + return context.AddIntrinsic(Intrinsic.X86Blendvps, value, oValue, isNaNInf); + } + public static void EmitSse2VectorIsNaNOpF( ArmEmitterContext context, Operand opF, diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs index 75a801e5f..fd69077b0 100644 --- a/ARMeilleure/Translation/PTC/Ptc.cs +++ b/ARMeilleure/Translation/PTC/Ptc.cs @@ -22,7 +22,7 @@ namespace ARMeilleure.Translation.PTC { private const string HeaderMagic = "PTChd"; - private const int InternalVersion = 1956; //! To be incremented manually for each change to the ARMeilleure project. + private const int InternalVersion = 1943; //! To be incremented manually for each change to the ARMeilleure project. private const string ActualDir = "0"; private const string BackupDir = "1"; From 4b7c7dab9e33faaf4eb58342f1f7ad8ada354591 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 27 Jan 2021 20:59:47 -0300 Subject: [PATCH 3/7] Support multiple destination operands on shader IR and shuffle predicates (#1964) * Support multiple destination operands on shader IR and shuffle predicates * Cache version change --- Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | 2 +- .../CodeGen/Glsl/HelperFunctions/Shuffle.glsl | 5 +- .../Glsl/HelperFunctions/ShuffleDown.glsl | 5 +- .../Glsl/HelperFunctions/ShuffleUp.glsl | 5 +- .../Glsl/HelperFunctions/ShuffleXor.glsl | 5 +- .../Glsl/Instructions/InstGenHelper.cs | 14 +-- .../Instructions/InstEmitMove.cs | 24 ++--- .../IntermediateRepresentation/INode.cs | 2 + .../IntermediateRepresentation/Operation.cs | 98 +++++++++++++++---- .../IntermediateRepresentation/PhiNode.cs | 13 +++ .../StructuredIr/InstructionInfo.cs | 14 +-- .../StructuredIr/StructuredProgram.cs | 12 ++- .../Translation/EmitterContext.cs | 11 +++ .../Translation/EmitterContextInsts.cs | 16 +-- .../Translation/Optimizations/Optimizer.cs | 33 ++++++- Ryujinx.Graphics.Shader/Translation/Ssa.cs | 19 ++-- 16 files changed, 199 insertions(+), 79 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index f3e4679b8..f4fef1451 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Version of the codegen (to be changed when codegen or guest format change). /// - private const ulong ShaderCodeGenVersion = 1790; + private const ulong ShaderCodeGenVersion = 1964; /// /// Creates a new instance of the shader cache. diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl index 380bc581f..356bdd793 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl @@ -1,9 +1,10 @@ -float Helper_Shuffle(float x, uint index, uint mask) +float Helper_Shuffle(float x, uint index, uint mask, out bool valid) { uint clamp = mask & 0x1fu; uint segMask = (mask >> 8) & 0x1fu; uint minThreadId = gl_SubGroupInvocationARB & segMask; uint maxThreadId = minThreadId | (clamp & ~segMask); uint srcThreadId = (index & ~segMask) | minThreadId; - return (srcThreadId <= maxThreadId) ? readInvocationARB(x, srcThreadId) : x; + valid = srcThreadId <= maxThreadId; + return valid ? readInvocationARB(x, srcThreadId) : x; } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl index 46750f20d..a79b90e20 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl @@ -1,9 +1,10 @@ -float Helper_ShuffleDown(float x, uint index, uint mask) +float Helper_ShuffleDown(float x, uint index, uint mask, out bool valid) { uint clamp = mask & 0x1fu; uint segMask = (mask >> 8) & 0x1fu; uint minThreadId = gl_SubGroupInvocationARB & segMask; uint maxThreadId = minThreadId | (clamp & ~segMask); uint srcThreadId = gl_SubGroupInvocationARB + index; - return (srcThreadId <= maxThreadId) ? readInvocationARB(x, srcThreadId) : x; + valid = srcThreadId <= maxThreadId; + return valid ? readInvocationARB(x, srcThreadId) : x; } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl index 2bc834697..4e74f217f 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl @@ -1,8 +1,9 @@ -float Helper_ShuffleUp(float x, uint index, uint mask) +float Helper_ShuffleUp(float x, uint index, uint mask, out bool valid) { uint clamp = mask & 0x1fu; uint segMask = (mask >> 8) & 0x1fu; uint minThreadId = gl_SubGroupInvocationARB & segMask; uint srcThreadId = gl_SubGroupInvocationARB - index; - return (srcThreadId >= minThreadId) ? readInvocationARB(x, srcThreadId) : x; + valid = srcThreadId >= minThreadId; + return valid ? readInvocationARB(x, srcThreadId) : x; } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl index 1049e181f..0631472be 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl @@ -1,9 +1,10 @@ -float Helper_ShuffleXor(float x, uint index, uint mask) +float Helper_ShuffleXor(float x, uint index, uint mask, out bool valid) { uint clamp = mask & 0x1fu; uint segMask = (mask >> 8) & 0x1fu; uint minThreadId = gl_SubGroupInvocationARB & segMask; uint maxThreadId = minThreadId | (clamp & ~segMask); uint srcThreadId = gl_SubGroupInvocationARB ^ index; - return (srcThreadId <= maxThreadId) ? readInvocationARB(x, srcThreadId) : x; + valid = srcThreadId <= maxThreadId; + return valid ? readInvocationARB(x, srcThreadId) : x; } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs index 5f5574c31..f3774a60d 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs @@ -88,13 +88,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions Add(Instruction.LoopContinue, InstType.OpNullary, "continue"); Add(Instruction.PackDouble2x32, InstType.Special); Add(Instruction.PackHalf2x16, InstType.Special); - Add(Instruction.ShiftLeft, InstType.OpBinary, "<<", 3); - Add(Instruction.ShiftRightS32, InstType.OpBinary, ">>", 3); - Add(Instruction.ShiftRightU32, InstType.OpBinary, ">>", 3); - Add(Instruction.Shuffle, InstType.CallTernary, HelperFunctionNames.Shuffle); - Add(Instruction.ShuffleDown, InstType.CallTernary, HelperFunctionNames.ShuffleDown); - Add(Instruction.ShuffleUp, InstType.CallTernary, HelperFunctionNames.ShuffleUp); - Add(Instruction.ShuffleXor, InstType.CallTernary, HelperFunctionNames.ShuffleXor); Add(Instruction.Maximum, InstType.CallBinary, "max"); Add(Instruction.MaximumU32, InstType.CallBinary, "max"); Add(Instruction.MemoryBarrier, InstType.CallNullary, "memoryBarrier"); @@ -107,6 +100,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions Add(Instruction.ReciprocalSquareRoot, InstType.CallUnary, "inversesqrt"); Add(Instruction.Return, InstType.OpNullary, "return"); Add(Instruction.Round, InstType.CallUnary, "roundEven"); + Add(Instruction.ShiftLeft, InstType.OpBinary, "<<", 3); + Add(Instruction.ShiftRightS32, InstType.OpBinary, ">>", 3); + Add(Instruction.ShiftRightU32, InstType.OpBinary, ">>", 3); + Add(Instruction.Shuffle, InstType.CallQuaternary, HelperFunctionNames.Shuffle); + Add(Instruction.ShuffleDown, InstType.CallQuaternary, HelperFunctionNames.ShuffleDown); + Add(Instruction.ShuffleUp, InstType.CallQuaternary, HelperFunctionNames.ShuffleUp); + Add(Instruction.ShuffleXor, InstType.CallQuaternary, HelperFunctionNames.ShuffleXor); Add(Instruction.Sine, InstType.CallUnary, "sin"); Add(Instruction.SquareRoot, InstType.CallUnary, "sqrt"); Add(Instruction.StoreLocal, InstType.Special); diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs index 264c732df..085325eef 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs @@ -118,25 +118,17 @@ namespace Ryujinx.Graphics.Shader.Instructions Operand srcB = op.IsBImmediate ? Const(op.ImmediateB) : Register(op.Rb); Operand srcC = op.IsCImmediate ? Const(op.ImmediateC) : Register(op.Rc); - Operand res = null; - - switch (op.ShuffleType) + (Operand res, Operand valid) = op.ShuffleType switch { - case ShuffleType.Indexed: - res = context.Shuffle(srcA, srcB, srcC); - break; - case ShuffleType.Up: - res = context.ShuffleUp(srcA, srcB, srcC); - break; - case ShuffleType.Down: - res = context.ShuffleDown(srcA, srcB, srcC); - break; - case ShuffleType.Butterfly: - res = context.ShuffleXor(srcA, srcB, srcC); - break; - } + ShuffleType.Indexed => context.Shuffle(srcA, srcB, srcC), + ShuffleType.Up => context.ShuffleUp(srcA, srcB, srcC), + ShuffleType.Down => context.ShuffleDown(srcA, srcB, srcC), + ShuffleType.Butterfly => context.ShuffleXor(srcA, srcB, srcC), + _ => (null, null) + }; context.Copy(GetDest(context), res); + context.Copy(pred, valid); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/INode.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/INode.cs index 48dda24b1..0f545e56f 100644 --- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/INode.cs +++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/INode.cs @@ -4,8 +4,10 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation { Operand Dest { get; set; } + int DestsCount { get; } int SourcesCount { get; } + Operand GetDest(int index); Operand GetSource(int index); void SetSource(int index, Operand operand); diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs index a86a278a7..4f0801b7b 100644 --- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs +++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs @@ -6,25 +6,42 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation { public Instruction Inst { get; private set; } - private Operand _dest; + private Operand[] _dests; public Operand Dest { - get => _dest; - set => _dest = AssignDest(value); + get + { + return _dests.Length != 0 ? _dests[0] : null; + } + set + { + if (value != null && value.Type == OperandType.LocalVariable) + { + value.AsgOp = this; + } + + if (value != null) + { + _dests = new[] { value }; + } + else + { + _dests = Array.Empty(); + } + } } + public int DestsCount => _dests.Length; + private Operand[] _sources; public int SourcesCount => _sources.Length; public int Index { get; } - public Operation(Instruction inst, Operand dest, params Operand[] sources) + private Operation(Operand[] sources) { - Inst = inst; - Dest = dest; - // The array may be modified externally, so we store a copy. _sources = (Operand[])sources.Clone(); @@ -39,11 +56,42 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation } } - public Operation( - Instruction inst, - int index, - Operand dest, - params Operand[] sources) : this(inst, dest, sources) + public Operation(Instruction inst, int index, Operand[] dests, Operand[] sources) : this(sources) + { + Inst = inst; + Index = index; + + // The array may be modified externally, so we store a copy. + _dests = (Operand[])dests.Clone(); + + for (int dstIndex = 0; dstIndex < dests.Length; dstIndex++) + { + Operand dest = dests[dstIndex]; + + if (dest != null && dest.Type == OperandType.LocalVariable) + { + dest.AsgOp = this; + } + } + } + + public Operation(Instruction inst, Operand dest, params Operand[] sources) : this(sources) + { + Inst = inst; + + if (dest != null) + { + dest.AsgOp = this; + + _dests = new[] { dest }; + } + else + { + _dests = Array.Empty(); + } + } + + public Operation(Instruction inst, int index, Operand dest, params Operand[] sources) : this(inst, dest, sources) { Index = index; } @@ -67,14 +115,9 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation } } - private Operand AssignDest(Operand dest) + public Operand GetDest(int index) { - if (dest != null && dest.Type == OperandType.LocalVariable) - { - dest.AsgOp = this; - } - - return dest; + return _dests[index]; } public Operand GetSource(int index) @@ -82,6 +125,23 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation return _sources[index]; } + public void SetDest(int index, Operand dest) + { + Operand oldDest = _dests[index]; + + if (oldDest != null && oldDest.Type == OperandType.LocalVariable) + { + oldDest.AsgOp = null; + } + + if (dest != null && dest.Type == OperandType.LocalVariable) + { + dest.AsgOp = this; + } + + _dests[index] = dest; + } + public void SetSource(int index, Operand source) { Operand oldSrc = _sources[index]; diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/PhiNode.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/PhiNode.cs index 13ff41bd1..8fa25ae9b 100644 --- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/PhiNode.cs +++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/PhiNode.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; namespace Ryujinx.Graphics.Shader.IntermediateRepresentation @@ -12,6 +13,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation set => _dest = AssignDest(value); } + public int DestsCount => _dest != null ? 1 : 0; + private HashSet _blocks; private class PhiSource @@ -64,6 +67,16 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation } } + public Operand GetDest(int index) + { + if (index != 0) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + return _dest; + } + public Operand GetSource(int index) { return _sources[index].Operand; diff --git a/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs b/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs index fcf39cc05..88cfe7299 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs @@ -94,13 +94,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr Add(Instruction.LogicalExclusiveOr, VariableType.Bool, VariableType.Bool, VariableType.Bool); Add(Instruction.LogicalNot, VariableType.Bool, VariableType.Bool); Add(Instruction.LogicalOr, VariableType.Bool, VariableType.Bool, VariableType.Bool); - Add(Instruction.ShiftLeft, VariableType.Int, VariableType.Int, VariableType.Int); - Add(Instruction.ShiftRightS32, VariableType.S32, VariableType.S32, VariableType.Int); - Add(Instruction.ShiftRightU32, VariableType.U32, VariableType.U32, VariableType.Int); - Add(Instruction.Shuffle, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32); - Add(Instruction.ShuffleDown, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32); - Add(Instruction.ShuffleUp, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32); - Add(Instruction.ShuffleXor, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32); Add(Instruction.Maximum, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar); Add(Instruction.MaximumU32, VariableType.U32, VariableType.U32, VariableType.U32); Add(Instruction.Minimum, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar); @@ -113,6 +106,13 @@ namespace Ryujinx.Graphics.Shader.StructuredIr Add(Instruction.PackHalf2x16, VariableType.U32, VariableType.F32, VariableType.F32); Add(Instruction.ReciprocalSquareRoot, VariableType.Scalar, VariableType.Scalar); Add(Instruction.Round, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.ShiftLeft, VariableType.Int, VariableType.Int, VariableType.Int); + Add(Instruction.ShiftRightS32, VariableType.S32, VariableType.S32, VariableType.Int); + Add(Instruction.ShiftRightU32, VariableType.U32, VariableType.U32, VariableType.Int); + Add(Instruction.Shuffle, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32, VariableType.Bool); + Add(Instruction.ShuffleDown, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32, VariableType.Bool); + Add(Instruction.ShuffleUp, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32, VariableType.Bool); + Add(Instruction.ShuffleXor, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32, VariableType.Bool); Add(Instruction.Sine, VariableType.Scalar, VariableType.Scalar); Add(Instruction.SquareRoot, VariableType.Scalar, VariableType.Scalar); Add(Instruction.StoreGlobal, VariableType.None, VariableType.S32, VariableType.S32, VariableType.U32); diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs index 8c73e698e..497cffc88 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs @@ -77,6 +77,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr bool isCall = inst == Instruction.Call; int sourcesCount = operation.SourcesCount; + int outDestsCount = operation.DestsCount != 0 ? operation.DestsCount - 1 : 0; List callOutOperands = new List(); @@ -93,7 +94,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr sourcesCount += callOutOperands.Count; } - IAstNode[] sources = new IAstNode[sourcesCount]; + IAstNode[] sources = new IAstNode[sourcesCount + outDestsCount]; for (int index = 0; index < operation.SourcesCount; index++) { @@ -110,6 +111,15 @@ namespace Ryujinx.Graphics.Shader.StructuredIr callOutOperands.Clear(); } + for (int index = 0; index < outDestsCount; index++) + { + AstOperand oper = context.GetOperandDef(operation.GetDest(1 + index)); + + oper.VarType = InstructionInfo.GetSrcVarType(inst, sourcesCount + index); + + sources[sourcesCount + index] = oper; + } + AstTextureOperation GetAstTextureOperation(TextureOperation texOp) { return new AstTextureOperation( diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs index d5d30f12e..df6b0839a 100644 --- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs +++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs @@ -37,6 +37,17 @@ namespace Ryujinx.Graphics.Shader.Translation return dest; } + public (Operand, Operand) Add(Instruction inst, (Operand, Operand) dest, params Operand[] sources) + { + Operand[] dests = new[] { dest.Item1, dest.Item2 }; + + Operation operation = new Operation(inst, 0, dests, sources); + + Add(operation); + + return dest; + } + public void Add(Operation operation) { _operations.Add(operation); diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs index b2418c2e1..dcefb5913 100644 --- a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs +++ b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs @@ -588,24 +588,24 @@ namespace Ryujinx.Graphics.Shader.Translation return context.Add(Instruction.ShiftRightU32, Local(), a, b); } - public static Operand Shuffle(this EmitterContext context, Operand a, Operand b, Operand c) + public static (Operand, Operand) Shuffle(this EmitterContext context, Operand a, Operand b, Operand c) { - return context.Add(Instruction.Shuffle, Local(), a, b, c); + return context.Add(Instruction.Shuffle, (Local(), Local()), a, b, c); } - public static Operand ShuffleDown(this EmitterContext context, Operand a, Operand b, Operand c) + public static (Operand, Operand) ShuffleDown(this EmitterContext context, Operand a, Operand b, Operand c) { - return context.Add(Instruction.ShuffleDown, Local(), a, b, c); + return context.Add(Instruction.ShuffleDown, (Local(), Local()), a, b, c); } - public static Operand ShuffleUp(this EmitterContext context, Operand a, Operand b, Operand c) + public static (Operand, Operand) ShuffleUp(this EmitterContext context, Operand a, Operand b, Operand c) { - return context.Add(Instruction.ShuffleUp, Local(), a, b, c); + return context.Add(Instruction.ShuffleUp, (Local(), Local()), a, b, c); } - public static Operand ShuffleXor(this EmitterContext context, Operand a, Operand b, Operand c) + public static (Operand, Operand) ShuffleXor(this EmitterContext context, Operand a, Operand b, Operand c) { - return context.Add(Instruction.ShuffleXor, Local(), a, b, c); + return context.Add(Instruction.ShuffleXor, (Local(), Local()), a, b, c); } public static Operand StoreGlobal(this EmitterContext context, Operand a, Operand b, Operand c) diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs index 32c7d2f0d..9a0815c3a 100644 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs +++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs @@ -64,7 +64,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations else if ((operation.Inst == Instruction.PackHalf2x16 && PropagatePack(operation)) || (operation.Inst == Instruction.ShuffleXor && MatchDdxOrDdy(operation))) { - if (operation.Dest.UseOps.Count == 0) + if (DestHasNoUses(operation)) { RemoveNode(block, node); } @@ -260,6 +260,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations if (src.UseOps.Remove(node) && src.UseOps.Count == 0) { + Debug.Assert(src.AsgOp != null); nodes.Enqueue(src.AsgOp); } } @@ -268,7 +269,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations private static bool IsUnused(INode node) { - return !HasSideEffects(node) && DestIsLocalVar(node) && node.Dest.UseOps.Count == 0; + return !HasSideEffects(node) && DestIsLocalVar(node) && DestHasNoUses(node); } private static bool HasSideEffects(INode node) @@ -298,7 +299,33 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations private static bool DestIsLocalVar(INode node) { - return node.Dest != null && node.Dest.Type == OperandType.LocalVariable; + if (node.DestsCount == 0) + { + return false; + } + + for (int index = 0; index < node.DestsCount; index++) + { + if (node.GetDest(index).Type != OperandType.LocalVariable) + { + return false; + } + } + + return true; + } + + private static bool DestHasNoUses(INode node) + { + for (int index = 0; index < node.DestsCount; index++) + { + if (node.GetDest(index).UseOps.Count != 0) + { + return false; + } + } + + return true; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/Ssa.cs b/Ryujinx.Graphics.Shader/Translation/Ssa.cs index a4d763be7..ff812e646 100644 --- a/Ryujinx.Graphics.Shader/Translation/Ssa.cs +++ b/Ryujinx.Graphics.Shader/Translation/Ssa.cs @@ -116,13 +116,18 @@ namespace Ryujinx.Graphics.Shader.Translation operation.SetSource(index, RenameLocal(operation.GetSource(index))); } - if (operation.Dest != null && operation.Dest.Type == OperandType.Register) + for (int index = 0; index < operation.DestsCount; index++) { - Operand local = Local(); + Operand dest = operation.GetDest(index); - localDefs[GetKeyFromRegister(operation.Dest.GetRegister())] = local; + if (dest.Type == OperandType.Register) + { + Operand local = Local(); - operation.Dest = local; + localDefs[GetKeyFromRegister(dest.GetRegister())] = local; + + operation.SetDest(index, local); + } } } @@ -185,9 +190,7 @@ namespace Ryujinx.Graphics.Shader.Translation return operand; } - LinkedListNode node = block.Operations.First; - - while (node != null) + for (LinkedListNode node = block.Operations.First; node != null; node = node.Next) { if (node.Value is Operation operation) { @@ -196,8 +199,6 @@ namespace Ryujinx.Graphics.Shader.Translation operation.SetSource(index, RenameGlobal(operation.GetSource(index))); } } - - node = node.Next; } } } From 9eb0ab05c6e820e113b3c61cbacd9b085b2819c4 Mon Sep 17 00:00:00 2001 From: ShahilSharma <67567036+ShahilSharma@users.noreply.github.com> Date: Wed, 27 Jan 2021 18:55:01 -0800 Subject: [PATCH 4/7] Enable Docked Mode by Default (#1953) Enables Docked Mode by default, since I see no reason to keep it off by Default. --- Ryujinx.Common/Configuration/ConfigurationState.cs | 2 +- Ryujinx/Config.json | 2 +- Ryujinx/_schema.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Ryujinx.Common/Configuration/ConfigurationState.cs b/Ryujinx.Common/Configuration/ConfigurationState.cs index a0fef1b22..61cc8f899 100644 --- a/Ryujinx.Common/Configuration/ConfigurationState.cs +++ b/Ryujinx.Common/Configuration/ConfigurationState.cs @@ -479,7 +479,7 @@ namespace Ryujinx.Configuration System.Region.Value = Region.USA; System.TimeZone.Value = "UTC"; System.SystemTimeOffset.Value = 0; - System.EnableDockedMode.Value = false; + System.EnableDockedMode.Value = true; EnableDiscordIntegration.Value = true; CheckUpdatesOnStart.Value = true; ShowConfirmExit.Value = true; diff --git a/Ryujinx/Config.json b/Ryujinx/Config.json index dac28ef3c..76c0a139a 100644 --- a/Ryujinx/Config.json +++ b/Ryujinx/Config.json @@ -18,7 +18,7 @@ "system_region": "USA", "system_time_zone": "UTC", "system_time_offset": 0, - "docked_mode": false, + "docked_mode": true, "enable_discord_integration": true, "check_updates_on_start": true, "show_confirm_exit": true, diff --git a/Ryujinx/_schema.json b/Ryujinx/_schema.json index 549611af8..eff1f9d4c 100644 --- a/Ryujinx/_schema.json +++ b/Ryujinx/_schema.json @@ -1171,7 +1171,7 @@ "type": "boolean", "title": "Enable Docked Mode", "description": "Enables or disables Docked Mode", - "default": false, + "default": true, "examples": [ true, false From c30504e3b3bb64c44d993d6339f15ec6703a3c55 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Fri, 29 Jan 2021 03:19:06 +0000 Subject: [PATCH 5/7] Use a descriptor cache for faster pool invalidation. (#1977) * Use a descriptor cache for faster pool invalidation. * Speed up comparison by casting to Vector256 Now we never need to worry about this ever again --- Ryujinx.Graphics.Gpu/Image/Pool.cs | 26 ++++++++++++++----- .../Image/SamplerDescriptor.cs | 12 +++++++++ Ryujinx.Graphics.Gpu/Image/SamplerPool.cs | 14 ++++++++-- .../Image/TextureDescriptor.cs | 12 +++++++++ Ryujinx.Graphics.Gpu/Image/TexturePool.cs | 18 +++---------- 5 files changed, 60 insertions(+), 22 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/Image/Pool.cs b/Ryujinx.Graphics.Gpu/Image/Pool.cs index c2c1a9a19..c5aef77f6 100644 --- a/Ryujinx.Graphics.Gpu/Image/Pool.cs +++ b/Ryujinx.Graphics.Gpu/Image/Pool.cs @@ -8,14 +8,16 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Represents a pool of GPU resources, such as samplers or textures. /// - /// Type of the GPU resource - abstract class Pool : IDisposable + /// Type of the GPU resource + /// Type of the descriptor + abstract class Pool : IDisposable where T2 : unmanaged { protected const int DescriptorSize = 0x20; protected GpuContext Context; - protected T[] Items; + protected T1[] Items; + protected T2[] DescriptorCache; /// /// The maximum ID value of resources on the pool (inclusive). @@ -47,7 +49,8 @@ namespace Ryujinx.Graphics.Gpu.Image ulong size = (ulong)(uint)count * DescriptorSize; - Items = new T[count]; + Items = new T1[count]; + DescriptorCache = new T2[count]; Address = address; Size = size; @@ -56,12 +59,23 @@ namespace Ryujinx.Graphics.Gpu.Image _modifiedDelegate = RegionModified; } + + /// + /// Gets the descriptor for a given ID. + /// + /// ID of the descriptor. This is effectively a zero-based index + /// The descriptor + public T2 GetDescriptor(int id) + { + return Context.PhysicalMemory.Read(Address + (ulong)id * DescriptorSize); + } + /// /// Gets the GPU resource with the given ID. /// /// ID of the resource. This is effectively a zero-based index /// The GPU resource with the given ID - public abstract T Get(int id); + public abstract T1 Get(int id); /// /// Synchronizes host memory with guest memory. @@ -97,7 +111,7 @@ namespace Ryujinx.Graphics.Gpu.Image protected abstract void InvalidateRangeImpl(ulong address, ulong size); - protected abstract void Delete(T item); + protected abstract void Delete(T1 item); /// /// Performs the disposal of all resources stored on the pool. diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs b/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs index 2c28b743f..64a146fb3 100644 --- a/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs +++ b/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs @@ -1,4 +1,6 @@ using Ryujinx.Graphics.GAL; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; namespace Ryujinx.Graphics.Gpu.Image { @@ -244,5 +246,15 @@ namespace Ryujinx.Graphics.Gpu.Image { return ((Word2 >> 12) & 0xfff) * Frac8ToF32; } + + /// + /// Check if two descriptors are equal. + /// + /// The descriptor to compare against + /// True if they are equal, false otherwise + public bool Equals(ref SamplerDescriptor other) + { + return Unsafe.As>(ref this).Equals(Unsafe.As>(ref other)); + } } } diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs index ca13a7d6f..1395aea22 100644 --- a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs +++ b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs @@ -3,7 +3,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Sampler pool. /// - class SamplerPool : Pool + class SamplerPool : Pool { private int _sequenceNumber; @@ -38,11 +38,13 @@ namespace Ryujinx.Graphics.Gpu.Image if (sampler == null) { - SamplerDescriptor descriptor = Context.PhysicalMemory.Read(Address + (ulong)id * DescriptorSize); + SamplerDescriptor descriptor = GetDescriptor(id); sampler = new Sampler(Context, descriptor); Items[id] = sampler; + + DescriptorCache[id] = descriptor; } return sampler; @@ -65,6 +67,14 @@ namespace Ryujinx.Graphics.Gpu.Image if (sampler != null) { + SamplerDescriptor descriptor = GetDescriptor(id); + + // If the descriptors are the same, the sampler is still valid. + if (descriptor.Equals(ref DescriptorCache[id])) + { + continue; + } + sampler.Dispose(); Items[id] = null; diff --git a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs index 76d97bf8c..e85df136b 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs @@ -1,4 +1,6 @@ using Ryujinx.Graphics.Gpu.Shader.Cache.Definition; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; namespace Ryujinx.Graphics.Gpu.Image { @@ -248,5 +250,15 @@ namespace Ryujinx.Graphics.Gpu.Image return result; } + + /// + /// Check if two descriptors are equal. + /// + /// The descriptor to compare against + /// True if they are equal, false otherwise + public bool Equals(ref TextureDescriptor other) + { + return Unsafe.As>(ref this).Equals(Unsafe.As>(ref other)); + } } } diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs index dfcd8a528..58e881ca7 100644 --- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs +++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs @@ -1,6 +1,5 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; -using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Texture; using System; using System.Collections.Generic; @@ -10,7 +9,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Texture pool. /// - class TexturePool : Pool + class TexturePool : Pool { private int _sequenceNumber; @@ -65,6 +64,8 @@ namespace Ryujinx.Graphics.Gpu.Image texture.IncrementReferenceCount(); Items[id] = texture; + + DescriptorCache[id] = descriptor; } else { @@ -91,16 +92,6 @@ namespace Ryujinx.Graphics.Gpu.Image return texture; } - /// - /// Gets the texture descriptor from a given texture ID. - /// - /// ID of the texture. This is effectively a zero-based index - /// The texture descriptor - public TextureDescriptor GetDescriptor(int id) - { - return Context.PhysicalMemory.Read(Address + (ulong)id * DescriptorSize); - } - /// /// Implementation of the texture pool range invalidation. /// @@ -122,8 +113,7 @@ namespace Ryujinx.Graphics.Gpu.Image // If the descriptors are the same, the texture is the same, // we don't need to remove as it was not modified. Just continue. - if (texture.Info.GpuAddress == descriptor.UnpackAddress() && - texture.IsExactMatch(GetInfo(descriptor, out _), TextureSearchFlags.Strict) != TextureMatchQuality.NoMatch) + if (descriptor.Equals(ref DescriptorCache[id])) { continue; } From 9c2f851d3946a2b789e8c00432c60c8d690299a7 Mon Sep 17 00:00:00 2001 From: EmulationFanatic <62343878+EmulationFanatic@users.noreply.github.com> Date: Thu, 28 Jan 2021 20:20:02 -0700 Subject: [PATCH 6/7] Add PPTC acronym to settings page (#1974) --- Ryujinx/Ui/Windows/SettingsWindow.glade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ryujinx/Ui/Windows/SettingsWindow.glade b/Ryujinx/Ui/Windows/SettingsWindow.glade index 6457ecfeb..5ead8dd82 100644 --- a/Ryujinx/Ui/Windows/SettingsWindow.glade +++ b/Ryujinx/Ui/Windows/SettingsWindow.glade @@ -1458,7 +1458,7 @@ - Enable Profiled Persistent Translation Cache + Enable PPTC (Profiled Persistent Translation Cache) True True False From f93089a64f9586863e8a261af932d125e78230df Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 29 Jan 2021 00:38:51 -0300 Subject: [PATCH 7/7] Implement geometry shader passthrough (#1961) * Implement geometry shader passthrough * Cache version change --- Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | 2 +- .../CodeGen/Glsl/Declarations.cs | 52 +++++++++++++------ .../CodeGen/Glsl/GlslGenerator.cs | 3 +- .../Translation/ShaderConfig.cs | 4 ++ .../Translation/ShaderHeader.cs | 4 ++ 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index f4fef1451..f266bbb44 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Version of the codegen (to be changed when codegen or guest format change). /// - private const ulong ShaderCodeGenVersion = 1964; + private const ulong ShaderCodeGenVersion = 1961; /// /// Creates a new instance of the shader cache. diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs index a6109a959..dd3c8196b 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs @@ -26,6 +26,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl context.AppendLine("#extension GL_ARB_compute_shader : enable"); } + if (context.Config.GpPassthrough) + { + context.AppendLine("#extension GL_NV_geometry_shader_passthrough : enable"); + } + context.AppendLine("#pragma optionNV(fastmath off)"); context.AppendLine(); @@ -33,20 +38,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl context.AppendLine($"const int {DefaultNames.UndefinedName} = 0;"); context.AppendLine(); - if (context.Config.Stage == ShaderStage.Geometry) - { - string inPrimitive = context.Config.GpuAccessor.QueryPrimitiveTopology().ToGlslString(); - - context.AppendLine($"layout ({inPrimitive}) in;"); - - string outPrimitive = context.Config.OutputTopology.ToGlslString(); - - int maxOutputVertices = context.Config.MaxOutputVertices; - - context.AppendLine($"layout ({outPrimitive}, max_vertices = {maxOutputVertices}) out;"); - context.AppendLine(); - } - if (context.Config.Stage == ShaderStage.Compute) { int localMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeLocalMemorySize(), 4); @@ -109,6 +100,33 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl if (context.Config.Stage != ShaderStage.Compute) { + if (context.Config.Stage == ShaderStage.Geometry) + { + string inPrimitive = context.Config.GpuAccessor.QueryPrimitiveTopology().ToGlslString(); + + context.AppendLine($"layout ({inPrimitive}) in;"); + + if (context.Config.GpPassthrough) + { + context.AppendLine($"layout (passthrough) in gl_PerVertex"); + context.EnterScope(); + context.AppendLine("vec4 gl_Position;"); + context.AppendLine("float gl_PointSize;"); + context.AppendLine("float gl_ClipDistance[];"); + context.LeaveScope(";"); + } + else + { + string outPrimitive = context.Config.OutputTopology.ToGlslString(); + + int maxOutputVertices = context.Config.MaxOutputVertices; + + context.AppendLine($"layout ({outPrimitive}, max_vertices = {maxOutputVertices}) out;"); + } + + context.AppendLine(); + } + if (info.IAttributes.Count != 0) { DeclareInputAttributes(context, info); @@ -432,6 +450,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl }; } + string pass = context.Config.GpPassthrough ? "passthrough, " : string.Empty; + string name = $"{DefaultNames.IAttributePrefix}{attr}"; if ((context.Config.Flags & TranslationFlags.Feedback) != 0) @@ -440,12 +460,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl { char swzMask = "xyzw"[c]; - context.AppendLine($"layout (location = {attr}, component = {c}) {iq}in float {name}_{swzMask}{suffix};"); + context.AppendLine($"layout ({pass}location = {attr}, component = {c}) {iq}in float {name}_{swzMask}{suffix};"); } } else { - context.AppendLine($"layout (location = {attr}) {iq}in vec4 {name}{suffix};"); + context.AppendLine($"layout ({pass}location = {attr}) {iq}in vec4 {name}{suffix};"); } } } diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs index 276544fca..37a1cd89c 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs @@ -69,7 +69,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl // compiler may eliminate them. // (Not needed for fragment shader as it is the last stage). if (context.Config.Stage != ShaderStage.Compute && - context.Config.Stage != ShaderStage.Fragment) + context.Config.Stage != ShaderStage.Fragment && + !context.Config.GpPassthrough) { for (int attr = 0; attr < Declarations.MaxAttributes; attr++) { diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs index 637ce8fe0..b1fd6470e 100644 --- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs +++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs @@ -6,6 +6,8 @@ namespace Ryujinx.Graphics.Shader.Translation { public ShaderStage Stage { get; } + public bool GpPassthrough { get; } + public OutputTopology OutputTopology { get; } public int MaxOutputVertices { get; } @@ -33,6 +35,7 @@ namespace Ryujinx.Graphics.Shader.Translation public ShaderConfig(IGpuAccessor gpuAccessor, TranslationFlags flags, TranslationCounts counts) { Stage = ShaderStage.Compute; + GpPassthrough = false; OutputTopology = OutputTopology.PointList; MaxOutputVertices = 0; LocalMemorySize = 0; @@ -51,6 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationFlags flags, TranslationCounts counts) { Stage = header.Stage; + GpPassthrough = header.Stage == ShaderStage.Geometry && header.GpPassthrough; OutputTopology = header.OutputTopology; MaxOutputVertices = header.MaxOutputVertexCount; LocalMemorySize = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize; diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs index 1218d591b..ff5932e15 100644 --- a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs +++ b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs @@ -81,6 +81,8 @@ namespace Ryujinx.Graphics.Shader.Translation public int SassVersion { get; } + public bool GpPassthrough { get; } + public bool DoesLoadOrStore { get; } public bool DoesFp64 { get; } @@ -136,6 +138,8 @@ namespace Ryujinx.Graphics.Shader.Translation SassVersion = commonWord0.Extract(17, 4); + GpPassthrough = commonWord0.Extract(24); + DoesLoadOrStore = commonWord0.Extract(26); DoesFp64 = commonWord0.Extract(27);