Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a64fee29dc | ||
|
9ef94c8292 | ||
|
915d6d044c | ||
|
a4780ab33b |
@@ -33,8 +33,8 @@ namespace ARMeilleure.Instructions
|
|||||||
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
|
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
|
||||||
case 0b11_011_0100_0100_000: EmitGetFpcr(context); return;
|
case 0b11_011_0100_0100_000: EmitGetFpcr(context); return;
|
||||||
case 0b11_011_0100_0100_001: EmitGetFpsr(context); return;
|
case 0b11_011_0100_0100_001: EmitGetFpsr(context); return;
|
||||||
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
|
case 0b11_011_1101_0000_010: EmitGetTpidrEl0(context); return;
|
||||||
case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break;
|
case 0b11_011_1101_0000_011: EmitGetTpidrroEl0(context); return;
|
||||||
case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
|
case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
|
||||||
case 0b11_011_1110_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break;
|
case 0b11_011_1110_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break;
|
||||||
case 0b11_011_1110_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)); break;
|
case 0b11_011_1110_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)); break;
|
||||||
@@ -49,19 +49,15 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||||
|
|
||||||
MethodInfo info;
|
|
||||||
|
|
||||||
switch (GetPackedId(op))
|
switch (GetPackedId(op))
|
||||||
{
|
{
|
||||||
case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
|
case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
|
||||||
case 0b11_011_0100_0100_000: EmitSetFpcr(context); return;
|
case 0b11_011_0100_0100_000: EmitSetFpcr(context); return;
|
||||||
case 0b11_011_0100_0100_001: EmitSetFpsr(context); return;
|
case 0b11_011_0100_0100_001: EmitSetFpsr(context); return;
|
||||||
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)); break;
|
case 0b11_011_1101_0000_010: EmitSetTpidrEl0(context); return;
|
||||||
|
|
||||||
default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
|
default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Call(info, GetIntOrZR(context, op.Rt));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Nop(ArmEmitterContext context)
|
public static void Nop(ArmEmitterContext context)
|
||||||
@@ -165,6 +161,28 @@ namespace ARMeilleure.Instructions
|
|||||||
SetIntOrZR(context, op.Rt, fpsr);
|
SetIntOrZR(context, op.Rt, fpsr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EmitGetTpidrEl0(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||||
|
|
||||||
|
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||||
|
|
||||||
|
Operand result = context.Load(OperandType.I64, context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrEl0Offset())));
|
||||||
|
|
||||||
|
SetIntOrZR(context, op.Rt, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitGetTpidrroEl0(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||||
|
|
||||||
|
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||||
|
|
||||||
|
Operand result = context.Load(OperandType.I64, context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrroEl0Offset())));
|
||||||
|
|
||||||
|
SetIntOrZR(context, op.Rt, result);
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitSetNzcv(ArmEmitterContext context)
|
private static void EmitSetNzcv(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||||
@@ -215,5 +233,16 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.UpdateArmFpMode();
|
context.UpdateArmFpMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EmitSetTpidrEl0(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||||
|
|
||||||
|
Operand value = GetIntOrZR(context, op.Rt);
|
||||||
|
|
||||||
|
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||||
|
|
||||||
|
context.Store(context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrEl0Offset())), value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,8 +23,6 @@ namespace ARMeilleure.Instructions
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodInfo info;
|
|
||||||
|
|
||||||
switch (op.CRn)
|
switch (op.CRn)
|
||||||
{
|
{
|
||||||
case 13: // Process and Thread Info.
|
case 13: // Process and Thread Info.
|
||||||
@@ -36,14 +34,12 @@ namespace ARMeilleure.Instructions
|
|||||||
switch (op.Opc2)
|
switch (op.Opc2)
|
||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032)); break;
|
EmitSetTpidrEl0(context); return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X} at 0x{op.Address:X} (0x{op.RawOpCode:X}).");
|
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X} at 0x{op.Address:X} (0x{op.RawOpCode:X}).");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 7:
|
case 7:
|
||||||
switch (op.CRm) // Cache and Memory barrier.
|
switch (op.CRm) // Cache and Memory barrier.
|
||||||
{
|
{
|
||||||
@@ -64,8 +60,6 @@ namespace ARMeilleure.Instructions
|
|||||||
default:
|
default:
|
||||||
throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
|
throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Call(info, GetIntA32(context, op.Rt));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mrc(ArmEmitterContext context)
|
public static void Mrc(ArmEmitterContext context)
|
||||||
@@ -79,7 +73,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodInfo info;
|
Operand result;
|
||||||
|
|
||||||
switch (op.CRn)
|
switch (op.CRn)
|
||||||
{
|
{
|
||||||
@@ -92,10 +86,10 @@ namespace ARMeilleure.Instructions
|
|||||||
switch (op.Opc2)
|
switch (op.Opc2)
|
||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl032)); break;
|
result = EmitGetTpidrEl0(context); break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32)); break;
|
result = EmitGetTpidrroEl0(context); break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X} at 0x{op.Address:X} (0x{op.RawOpCode:X}).");
|
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X} at 0x{op.Address:X} (0x{op.RawOpCode:X}).");
|
||||||
@@ -110,13 +104,13 @@ namespace ARMeilleure.Instructions
|
|||||||
if (op.Rt == RegisterAlias.Aarch32Pc)
|
if (op.Rt == RegisterAlias.Aarch32Pc)
|
||||||
{
|
{
|
||||||
// Special behavior: copy NZCV flags into APSR.
|
// Special behavior: copy NZCV flags into APSR.
|
||||||
EmitSetNzcv(context, context.Call(info));
|
EmitSetNzcv(context, result);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SetIntA32(context, op.Rt, context.Call(info));
|
SetIntA32(context, op.Rt, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,5 +318,34 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.UpdateArmFpMode();
|
context.UpdateArmFpMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Operand EmitGetTpidrEl0(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCode32System op = (OpCode32System)context.CurrOp;
|
||||||
|
|
||||||
|
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||||
|
|
||||||
|
return context.Load(OperandType.I64, context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrEl0Offset())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand EmitGetTpidrroEl0(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCode32System op = (OpCode32System)context.CurrOp;
|
||||||
|
|
||||||
|
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||||
|
|
||||||
|
return context.Load(OperandType.I64, context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrroEl0Offset())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitSetTpidrEl0(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCode32System op = (OpCode32System)context.CurrOp;
|
||||||
|
|
||||||
|
Operand value = GetIntA32(context, op.Rt);
|
||||||
|
|
||||||
|
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||||
|
|
||||||
|
context.Store(context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrEl0Offset())), context.ZeroExtend32(OperandType.I64, value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -72,26 +72,6 @@ namespace ARMeilleure.Instructions
|
|||||||
return (ulong)GetContext().DczidEl0;
|
return (ulong)GetContext().DczidEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ulong GetTpidrEl0()
|
|
||||||
{
|
|
||||||
return (ulong)GetContext().TpidrEl0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static uint GetTpidrEl032()
|
|
||||||
{
|
|
||||||
return (uint)GetContext().TpidrEl0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ulong GetTpidrroEl0()
|
|
||||||
{
|
|
||||||
return (ulong)GetContext().TpidrroEl0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static uint GetTpidr32()
|
|
||||||
{
|
|
||||||
return (uint)GetContext().TpidrroEl0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ulong GetCntfrqEl0()
|
public static ulong GetCntfrqEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CntfrqEl0;
|
return GetContext().CntfrqEl0;
|
||||||
@@ -106,16 +86,6 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
return GetContext().CntvctEl0;
|
return GetContext().CntvctEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetTpidrEl0(ulong value)
|
|
||||||
{
|
|
||||||
GetContext().TpidrEl0 = (long)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetTpidrEl032(uint value)
|
|
||||||
{
|
|
||||||
GetContext().TpidrEl0 = (long)value;
|
|
||||||
}
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Read"
|
#region "Read"
|
||||||
|
@@ -27,8 +27,17 @@ namespace ARMeilleure.State
|
|||||||
// Since EL2 isn't implemented, CNTVOFF_EL2 = 0
|
// Since EL2 isn't implemented, CNTVOFF_EL2 = 0
|
||||||
public ulong CntvctEl0 => CntpctEl0;
|
public ulong CntvctEl0 => CntpctEl0;
|
||||||
|
|
||||||
public long TpidrEl0 { get; set; }
|
public long TpidrEl0
|
||||||
public long TpidrroEl0 { get; set; }
|
{
|
||||||
|
get => _nativeContext.GetTpidrEl0();
|
||||||
|
set => _nativeContext.SetTpidrEl0(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long TpidrroEl0
|
||||||
|
{
|
||||||
|
get => _nativeContext.GetTpidrroEl0();
|
||||||
|
set => _nativeContext.SetTpidrroEl0(value);
|
||||||
|
}
|
||||||
|
|
||||||
public uint Pstate
|
public uint Pstate
|
||||||
{
|
{
|
||||||
|
@@ -13,6 +13,8 @@ namespace ARMeilleure.State
|
|||||||
public fixed ulong V[RegisterConsts.VecRegsCount * 2];
|
public fixed ulong V[RegisterConsts.VecRegsCount * 2];
|
||||||
public fixed uint Flags[RegisterConsts.FlagsCount];
|
public fixed uint Flags[RegisterConsts.FlagsCount];
|
||||||
public fixed uint FpFlags[RegisterConsts.FpFlagsCount];
|
public fixed uint FpFlags[RegisterConsts.FpFlagsCount];
|
||||||
|
public long TpidrEl0;
|
||||||
|
public long TpidrroEl0;
|
||||||
public int Counter;
|
public int Counter;
|
||||||
public ulong DispatchAddress;
|
public ulong DispatchAddress;
|
||||||
public ulong ExclusiveAddress;
|
public ulong ExclusiveAddress;
|
||||||
@@ -168,6 +170,12 @@ namespace ARMeilleure.State
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long GetTpidrEl0() => GetStorage().TpidrEl0;
|
||||||
|
public void SetTpidrEl0(long value) => GetStorage().TpidrEl0 = value;
|
||||||
|
|
||||||
|
public long GetTpidrroEl0() => GetStorage().TpidrroEl0;
|
||||||
|
public void SetTpidrroEl0(long value) => GetStorage().TpidrroEl0 = value;
|
||||||
|
|
||||||
public int GetCounter() => GetStorage().Counter;
|
public int GetCounter() => GetStorage().Counter;
|
||||||
public void SetCounter(int value) => GetStorage().Counter = value;
|
public void SetCounter(int value) => GetStorage().Counter = value;
|
||||||
|
|
||||||
@@ -214,6 +222,16 @@ namespace ARMeilleure.State
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int GetTpidrEl0Offset()
|
||||||
|
{
|
||||||
|
return StorageOffset(ref _dummyStorage, ref _dummyStorage.TpidrEl0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetTpidrroEl0Offset()
|
||||||
|
{
|
||||||
|
return StorageOffset(ref _dummyStorage, ref _dummyStorage.TpidrroEl0);
|
||||||
|
}
|
||||||
|
|
||||||
public static int GetCounterOffset()
|
public static int GetCounterOffset()
|
||||||
{
|
{
|
||||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Counter);
|
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Counter);
|
||||||
|
@@ -105,17 +105,11 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)));
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32))); // A32 only.
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)));
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl032))); // A32 only.
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)));
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only.
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SupervisorCall)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SupervisorCall)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)));
|
||||||
|
@@ -30,7 +30,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 4626; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 4661; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
@@ -53,6 +53,8 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
|
|
||||||
bool opened = false;
|
bool opened = false;
|
||||||
|
|
||||||
|
_parent.Activate();
|
||||||
|
|
||||||
UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent,
|
UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent,
|
||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
|
@@ -226,6 +226,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
// Set clip control, viewport and the framebuffer to the output to placate overlays and OBS capture.
|
// Set clip control, viewport and the framebuffer to the output to placate overlays and OBS capture.
|
||||||
GL.ClipControl(ClipOrigin.LowerLeft, ClipDepthMode.NegativeOneToOne);
|
GL.ClipControl(ClipOrigin.LowerLeft, ClipDepthMode.NegativeOneToOne);
|
||||||
GL.Viewport(0, 0, _width, _height);
|
GL.Viewport(0, 0, _width, _height);
|
||||||
|
GL.BindFramebuffer(FramebufferTarget.Framebuffer, drawFramebuffer);
|
||||||
|
|
||||||
swapBuffersCallback();
|
swapBuffersCallback();
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using Ryujinx.Common.Logging;
|
||||||
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@@ -7,12 +8,26 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
internal class AutoFlushCounter
|
internal class AutoFlushCounter
|
||||||
{
|
{
|
||||||
// How often to flush on framebuffer change.
|
// How often to flush on framebuffer change.
|
||||||
private readonly static long FramebufferFlushTimer = Stopwatch.Frequency / 1000;
|
private readonly static long FramebufferFlushTimer = Stopwatch.Frequency / 1000; // (1ms)
|
||||||
|
|
||||||
|
// How often to flush on draw when fast flush mode is enabled.
|
||||||
|
private readonly static long DrawFlushTimer = Stopwatch.Frequency / 666; // (1.5ms)
|
||||||
|
|
||||||
|
// Average wait time that triggers fast flush mode to be entered.
|
||||||
|
private readonly static long FastFlushEnterThreshold = Stopwatch.Frequency / 666; // (1.5ms)
|
||||||
|
|
||||||
|
// Average wait time that triggers fast flush mode to be exited.
|
||||||
|
private readonly static long FastFlushExitThreshold = Stopwatch.Frequency / 10000; // (0.1ms)
|
||||||
|
|
||||||
|
// Number of frames to average waiting times over.
|
||||||
|
private const int SyncWaitAverageCount = 20;
|
||||||
|
|
||||||
private const int MinDrawCountForFlush = 10;
|
private const int MinDrawCountForFlush = 10;
|
||||||
private const int MinConsecutiveQueryForFlush = 10;
|
private const int MinConsecutiveQueryForFlush = 10;
|
||||||
private const int InitialQueryCountForFlush = 32;
|
private const int InitialQueryCountForFlush = 32;
|
||||||
|
|
||||||
|
private readonly VulkanRenderer _gd;
|
||||||
|
|
||||||
private long _lastFlush;
|
private long _lastFlush;
|
||||||
private ulong _lastDrawCount;
|
private ulong _lastDrawCount;
|
||||||
private bool _hasPendingQuery;
|
private bool _hasPendingQuery;
|
||||||
@@ -23,6 +38,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private int _queryCountHistoryIndex;
|
private int _queryCountHistoryIndex;
|
||||||
private int _remainingQueries;
|
private int _remainingQueries;
|
||||||
|
|
||||||
|
private long[] _syncWaitHistory = new long[SyncWaitAverageCount];
|
||||||
|
private int _syncWaitHistoryIndex;
|
||||||
|
|
||||||
|
private bool _fastFlushMode;
|
||||||
|
|
||||||
|
public AutoFlushCounter(VulkanRenderer gd)
|
||||||
|
{
|
||||||
|
_gd = gd;
|
||||||
|
}
|
||||||
|
|
||||||
public void RegisterFlush(ulong drawCount)
|
public void RegisterFlush(ulong drawCount)
|
||||||
{
|
{
|
||||||
_lastFlush = Stopwatch.GetTimestamp();
|
_lastFlush = Stopwatch.GetTimestamp();
|
||||||
@@ -69,6 +94,32 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return _hasPendingQuery;
|
return _hasPendingQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool ShouldFlushDraw(ulong drawCount)
|
||||||
|
{
|
||||||
|
if (_fastFlushMode)
|
||||||
|
{
|
||||||
|
long draws = (long)(drawCount - _lastDrawCount);
|
||||||
|
|
||||||
|
if (draws < MinDrawCountForFlush)
|
||||||
|
{
|
||||||
|
if (draws == 0)
|
||||||
|
{
|
||||||
|
_lastFlush = Stopwatch.GetTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
long flushTimeout = DrawFlushTimer;
|
||||||
|
|
||||||
|
long now = Stopwatch.GetTimestamp();
|
||||||
|
|
||||||
|
return now > _lastFlush + flushTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public bool ShouldFlushAttachmentChange(ulong drawCount)
|
public bool ShouldFlushAttachmentChange(ulong drawCount)
|
||||||
{
|
{
|
||||||
_queryCount = 0;
|
_queryCount = 0;
|
||||||
@@ -102,11 +153,27 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public void Present()
|
public void Present()
|
||||||
{
|
{
|
||||||
|
// Query flush prediction.
|
||||||
|
|
||||||
_queryCountHistoryIndex = (_queryCountHistoryIndex + 1) % 3;
|
_queryCountHistoryIndex = (_queryCountHistoryIndex + 1) % 3;
|
||||||
|
|
||||||
_remainingQueries = _queryCountHistory.Max() + 10;
|
_remainingQueries = _queryCountHistory.Max() + 10;
|
||||||
|
|
||||||
_queryCountHistory[_queryCountHistoryIndex] = 0;
|
_queryCountHistory[_queryCountHistoryIndex] = 0;
|
||||||
|
|
||||||
|
// Fast flush mode toggle.
|
||||||
|
|
||||||
|
_syncWaitHistory[_syncWaitHistoryIndex] = _gd.SyncManager.GetAndResetWaitTicks();
|
||||||
|
|
||||||
|
_syncWaitHistoryIndex = (_syncWaitHistoryIndex + 1) % SyncWaitAverageCount;
|
||||||
|
|
||||||
|
long averageWait = (long)_syncWaitHistory.Average();
|
||||||
|
|
||||||
|
if (_fastFlushMode ? averageWait < FastFlushExitThreshold : averageWait > FastFlushEnterThreshold)
|
||||||
|
{
|
||||||
|
_fastFlushMode = !_fastFlushMode;
|
||||||
|
Logger.Debug?.PrintMsg(LogClass.Gpu, $"Switched fast flush mode: ({_fastFlushMode})");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -86,7 +86,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Gd = gd;
|
Gd = gd;
|
||||||
Device = device;
|
Device = device;
|
||||||
|
|
||||||
AutoFlush = new AutoFlushCounter();
|
AutoFlush = new AutoFlushCounter(gd);
|
||||||
|
|
||||||
var pipelineCacheCreateInfo = new PipelineCacheCreateInfo()
|
var pipelineCacheCreateInfo = new PipelineCacheCreateInfo()
|
||||||
{
|
{
|
||||||
@@ -1562,6 +1562,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private void RecreatePipelineIfNeeded(PipelineBindPoint pbp)
|
private void RecreatePipelineIfNeeded(PipelineBindPoint pbp)
|
||||||
{
|
{
|
||||||
|
if (AutoFlush.ShouldFlushDraw(DrawCount))
|
||||||
|
{
|
||||||
|
Gd.FlushAllCommands();
|
||||||
|
}
|
||||||
|
|
||||||
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
||||||
|
|
||||||
// Commit changes to the support buffer before drawing.
|
// Commit changes to the support buffer before drawing.
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
@@ -26,6 +27,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private readonly Device _device;
|
private readonly Device _device;
|
||||||
private List<SyncHandle> _handles;
|
private List<SyncHandle> _handles;
|
||||||
private ulong FlushId;
|
private ulong FlushId;
|
||||||
|
private long WaitTicks;
|
||||||
|
|
||||||
public SyncManager(VulkanRenderer gd, Device device)
|
public SyncManager(VulkanRenderer gd, Device device)
|
||||||
{
|
{
|
||||||
@@ -130,6 +132,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long beforeTicks = Stopwatch.GetTimestamp();
|
||||||
|
|
||||||
if (result.NeedsFlush(FlushId))
|
if (result.NeedsFlush(FlushId))
|
||||||
{
|
{
|
||||||
_gd.InterruptAction(() =>
|
_gd.InterruptAction(() =>
|
||||||
@@ -142,12 +146,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool signaled = result.Signalled || result.Waitable.WaitForFences(_gd.Api, _device, 1000000000);
|
bool signaled = result.Signalled || result.Waitable.WaitForFences(_gd.Api, _device, 1000000000);
|
||||||
|
|
||||||
if (!signaled)
|
if (!signaled)
|
||||||
{
|
{
|
||||||
Logger.Error?.PrintMsg(LogClass.Gpu, $"VK Sync Object {result.ID} failed to signal within 1000ms. Continuing...");
|
Logger.Error?.PrintMsg(LogClass.Gpu, $"VK Sync Object {result.ID} failed to signal within 1000ms. Continuing...");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
WaitTicks += Stopwatch.GetTimestamp() - beforeTicks;
|
||||||
result.Signalled = true;
|
result.Signalled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,5 +194,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long GetAndResetWaitTicks()
|
||||||
|
{
|
||||||
|
long result = WaitTicks;
|
||||||
|
WaitTicks = 0;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -49,6 +49,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
internal PipelineLayoutCache PipelineLayoutCache { get; private set; }
|
internal PipelineLayoutCache PipelineLayoutCache { get; private set; }
|
||||||
internal BackgroundResources BackgroundResources { get; private set; }
|
internal BackgroundResources BackgroundResources { get; private set; }
|
||||||
internal Action<Action> InterruptAction { get; private set; }
|
internal Action<Action> InterruptAction { get; private set; }
|
||||||
|
internal SyncManager SyncManager { get; private set; }
|
||||||
|
|
||||||
internal BufferManager BufferManager { get; private set; }
|
internal BufferManager BufferManager { get; private set; }
|
||||||
|
|
||||||
@@ -58,7 +59,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private VulkanDebugMessenger _debugMessenger;
|
private VulkanDebugMessenger _debugMessenger;
|
||||||
private Counters _counters;
|
private Counters _counters;
|
||||||
private SyncManager _syncManager;
|
|
||||||
|
|
||||||
private PipelineFull _pipeline;
|
private PipelineFull _pipeline;
|
||||||
|
|
||||||
@@ -327,7 +327,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
BufferManager = new BufferManager(this, _device);
|
BufferManager = new BufferManager(this, _device);
|
||||||
|
|
||||||
_syncManager = new SyncManager(this, _device);
|
SyncManager = new SyncManager(this, _device);
|
||||||
_pipeline = new PipelineFull(this, _device);
|
_pipeline = new PipelineFull(this, _device);
|
||||||
_pipeline.Initialize();
|
_pipeline.Initialize();
|
||||||
|
|
||||||
@@ -436,7 +436,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
internal void RegisterFlush()
|
internal void RegisterFlush()
|
||||||
{
|
{
|
||||||
_syncManager.RegisterFlush();
|
SyncManager.RegisterFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PinnedSpan<byte> GetBufferData(BufferHandle buffer, int offset, int size)
|
public PinnedSpan<byte> GetBufferData(BufferHandle buffer, int offset, int size)
|
||||||
@@ -696,7 +696,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public void PreFrame()
|
public void PreFrame()
|
||||||
{
|
{
|
||||||
_syncManager.Cleanup();
|
SyncManager.Cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, bool hostReserved)
|
public ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, bool hostReserved)
|
||||||
@@ -736,7 +736,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public void CreateSync(ulong id, bool strict)
|
public void CreateSync(ulong id, bool strict)
|
||||||
{
|
{
|
||||||
_syncManager.Create(id, strict);
|
SyncManager.Create(id, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IProgram LoadProgramBinary(byte[] programBinary, bool isFragment, ShaderInfo info)
|
public IProgram LoadProgramBinary(byte[] programBinary, bool isFragment, ShaderInfo info)
|
||||||
@@ -746,12 +746,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public void WaitSync(ulong id)
|
public void WaitSync(ulong id)
|
||||||
{
|
{
|
||||||
_syncManager.Wait(id);
|
SyncManager.Wait(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong GetCurrentSync()
|
public ulong GetCurrentSync()
|
||||||
{
|
{
|
||||||
return _syncManager.GetCurrent();
|
return SyncManager.GetCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetInterruptAction(Action<Action> interruptAction)
|
public void SetInterruptAction(Action<Action> interruptAction)
|
||||||
|
Reference in New Issue
Block a user