aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ARMeilleure/Translation/ArmEmitterContext.cs7
-rw-r--r--ARMeilleure/Translation/PTC/IPtcLoadState.cs10
-rw-r--r--ARMeilleure/Translation/PTC/Ptc.cs136
-rw-r--r--ARMeilleure/Translation/PTC/PtcProfiler.cs74
-rw-r--r--ARMeilleure/Translation/Translator.cs46
-rw-r--r--Ryujinx.Ava/AppHost.cs7
-rw-r--r--Ryujinx.Ava/Program.cs7
-rw-r--r--Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs25
-rw-r--r--Ryujinx.Cpu/ICpuContext.cs22
-rw-r--r--Ryujinx.Cpu/IDiskCacheState.cs20
-rw-r--r--Ryujinx.Cpu/Jit/JitCpuContext.cs12
-rw-r--r--Ryujinx.Cpu/Jit/JitDiskCacheLoadState.cs38
-rw-r--r--Ryujinx.Cpu/LoadState.cs12
-rw-r--r--Ryujinx.HLE/HOS/ApplicationLoader.cs55
-rw-r--r--Ryujinx.HLE/HOS/ArmProcessContext.cs23
-rw-r--r--Ryujinx.HLE/HOS/ArmProcessContextFactory.cs33
-rw-r--r--Ryujinx.HLE/HOS/ProgramLoader.cs92
-rw-r--r--Ryujinx.Headless.SDL2/Program.cs14
-rw-r--r--Ryujinx/Program.cs7
-rw-r--r--Ryujinx/Ui/MainWindow.cs21
-rw-r--r--Ryujinx/Ui/RendererWidgetBase.cs5
21 files changed, 435 insertions, 231 deletions
diff --git a/ARMeilleure/Translation/ArmEmitterContext.cs b/ARMeilleure/Translation/ArmEmitterContext.cs
index 33355dae..48254de4 100644
--- a/ARMeilleure/Translation/ArmEmitterContext.cs
+++ b/ARMeilleure/Translation/ArmEmitterContext.cs
@@ -6,7 +6,6 @@ using ARMeilleure.Instructions;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Memory;
using ARMeilleure.State;
-using ARMeilleure.Translation.PTC;
using System;
using System.Collections.Generic;
using System.Reflection;
@@ -44,14 +43,13 @@ namespace ARMeilleure.Translation
public IMemoryManager Memory { get; }
- public bool HasPtc { get; }
-
public EntryTable<uint> CountTable { get; }
public AddressTable<ulong> FunctionTable { get; }
public TranslatorStubs Stubs { get; }
public ulong EntryAddress { get; }
public bool HighCq { get; }
+ public bool HasPtc { get; }
public Aarch32Mode Mode { get; }
private int _ifThenBlockStateIndex = 0;
@@ -66,15 +64,16 @@ namespace ARMeilleure.Translation
TranslatorStubs stubs,
ulong entryAddress,
bool highCq,
+ bool hasPtc,
Aarch32Mode mode)
{
- HasPtc = Ptc.State != PtcState.Disabled;
Memory = memory;
CountTable = countTable;
FunctionTable = funcTable;
Stubs = stubs;
EntryAddress = entryAddress;
HighCq = highCq;
+ HasPtc = hasPtc;
Mode = mode;
_labels = new Dictionary<ulong, Operand>();
diff --git a/ARMeilleure/Translation/PTC/IPtcLoadState.cs b/ARMeilleure/Translation/PTC/IPtcLoadState.cs
new file mode 100644
index 00000000..1b11ac0b
--- /dev/null
+++ b/ARMeilleure/Translation/PTC/IPtcLoadState.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace ARMeilleure.Translation.PTC
+{
+ public interface IPtcLoadState
+ {
+ event Action<PtcLoadingState, int, int> PtcStateChanged;
+ void Continue();
+ }
+} \ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs
index c2d358c1..f99d6e51 100644
--- a/ARMeilleure/Translation/PTC/Ptc.cs
+++ b/ARMeilleure/Translation/PTC/Ptc.cs
@@ -22,7 +22,7 @@ using static ARMeilleure.Translation.PTC.PtcFormatter;
namespace ARMeilleure.Translation.PTC
{
- public static class Ptc
+ class Ptc : IPtcLoadState
{
private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0";
@@ -35,45 +35,49 @@ namespace ARMeilleure.Translation.PTC
private const string TitleIdTextDefault = "0000000000000000";
private const string DisplayVersionDefault = "0";
- internal static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
- internal static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
- internal static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
+ public static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
+ public static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
+ public static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
private const byte FillingByte = 0x00;
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
+ public PtcProfiler Profiler { get; }
+
// Carriers.
- private static MemoryStream _infosStream;
- private static List<byte[]> _codesList;
- private static MemoryStream _relocsStream;
- private static MemoryStream _unwindInfosStream;
+ private MemoryStream _infosStream;
+ private List<byte[]> _codesList;
+ private MemoryStream _relocsStream;
+ private MemoryStream _unwindInfosStream;
- private static readonly ulong _outerHeaderMagic;
- private static readonly ulong _innerHeaderMagic;
+ private readonly ulong _outerHeaderMagic;
+ private readonly ulong _innerHeaderMagic;
- private static readonly ManualResetEvent _waitEvent;
+ private readonly ManualResetEvent _waitEvent;
- private static readonly object _lock;
+ private readonly object _lock;
- private static bool _disposed;
+ private bool _disposed;
- internal static string TitleIdText { get; private set; }
- internal static string DisplayVersion { get; private set; }
+ public string TitleIdText { get; private set; }
+ public string DisplayVersion { get; private set; }
- private static MemoryManagerMode _memoryMode;
+ private MemoryManagerType _memoryMode;
- internal static string CachePathActual { get; private set; }
- internal static string CachePathBackup { get; private set; }
+ public string CachePathActual { get; private set; }
+ public string CachePathBackup { get; private set; }
- internal static PtcState State { get; private set; }
+ public PtcState State { get; private set; }
// Progress reporting helpers.
- private static volatile int _translateCount;
- private static volatile int _translateTotalCount;
- public static event Action<PtcLoadingState, int, int> PtcStateChanged;
+ private volatile int _translateCount;
+ private volatile int _translateTotalCount;
+ public event Action<PtcLoadingState, int, int> PtcStateChanged;
- static Ptc()
+ public Ptc()
{
+ Profiler = new PtcProfiler(this);
+
InitializeCarriers();
_outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
@@ -94,12 +98,12 @@ namespace ARMeilleure.Translation.PTC
Disable();
}
- public static void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerMode memoryMode)
+ public void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerType memoryMode)
{
Wait();
- PtcProfiler.Wait();
- PtcProfiler.ClearEntries();
+ Profiler.Wait();
+ Profiler.ClearEntries();
Logger.Info?.Print(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache (enabled: {enabled}).");
@@ -137,12 +141,12 @@ namespace ARMeilleure.Translation.PTC
CachePathBackup = Path.Combine(workPathBackup, DisplayVersion);
PreLoad();
- PtcProfiler.PreLoad();
+ Profiler.PreLoad();
Enable();
}
- private static void InitializeCarriers()
+ private void InitializeCarriers()
{
_infosStream = new MemoryStream();
_codesList = new List<byte[]>();
@@ -150,7 +154,7 @@ namespace ARMeilleure.Translation.PTC
_unwindInfosStream = new MemoryStream();
}
- private static void DisposeCarriers()
+ private void DisposeCarriers()
{
_infosStream.Dispose();
_codesList.Clear();
@@ -158,12 +162,12 @@ namespace ARMeilleure.Translation.PTC
_unwindInfosStream.Dispose();
}
- private static bool AreCarriersEmpty()
+ private bool AreCarriersEmpty()
{
return _infosStream.Length == 0L && _codesList.Count == 0 && _relocsStream.Length == 0L && _unwindInfosStream.Length == 0L;
}
- private static void ResetCarriersIfNeeded()
+ private void ResetCarriersIfNeeded()
{
if (AreCarriersEmpty())
{
@@ -175,7 +179,7 @@ namespace ARMeilleure.Translation.PTC
InitializeCarriers();
}
- private static void PreLoad()
+ private void PreLoad()
{
string fileNameActual = string.Concat(CachePathActual, ".cache");
string fileNameBackup = string.Concat(CachePathBackup, ".cache");
@@ -199,7 +203,7 @@ namespace ARMeilleure.Translation.PTC
}
}
- private static unsafe bool Load(string fileName, bool isBackup)
+ private unsafe bool Load(string fileName, bool isBackup)
{
using (FileStream compressedStream = new(fileName, FileMode.Open))
using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true))
@@ -376,12 +380,12 @@ namespace ARMeilleure.Translation.PTC
return true;
}
- private static void InvalidateCompressedStream(FileStream compressedStream)
+ private void InvalidateCompressedStream(FileStream compressedStream)
{
compressedStream.SetLength(0L);
}
- private static void PreSave()
+ private void PreSave()
{
_waitEvent.Reset();
@@ -409,7 +413,7 @@ namespace ARMeilleure.Translation.PTC
_waitEvent.Set();
}
- private static unsafe void Save(string fileName)
+ private unsafe void Save(string fileName)
{
int translatedFuncsCount;
@@ -517,7 +521,7 @@ namespace ARMeilleure.Translation.PTC
}
}
- internal static void LoadTranslations(Translator translator)
+ public void LoadTranslations(Translator translator)
{
if (AreCarriersEmpty())
{
@@ -550,7 +554,7 @@ namespace ARMeilleure.Translation.PTC
bool isEntryChanged = infoEntry.Hash != ComputeHash(translator.Memory, infoEntry.Address, infoEntry.GuestSize);
- if (isEntryChanged || (!infoEntry.HighCq && PtcProfiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) && value.HighCq))
+ if (isEntryChanged || (!infoEntry.HighCq && Profiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) && value.HighCq))
{
infoEntry.Stubbed = true;
infoEntry.CodeLength = 0;
@@ -601,38 +605,38 @@ namespace ARMeilleure.Translation.PTC
Logger.Info?.Print(LogClass.Ptc, $"{translator.Functions.Count} translated functions loaded");
}
- private static int GetEntriesCount()
+ private int GetEntriesCount()
{
return _codesList.Count;
}
[Conditional("DEBUG")]
- private static void SkipCode(int index, int codeLength)
+ private void SkipCode(int index, int codeLength)
{
Debug.Assert(_codesList[index].Length == 0);
Debug.Assert(codeLength == 0);
}
- private static void SkipReloc(int relocEntriesCount)
+ private void SkipReloc(int relocEntriesCount)
{
_relocsStream.Seek(relocEntriesCount * RelocEntry.Stride, SeekOrigin.Current);
}
- private static void SkipUnwindInfo(BinaryReader unwindInfosReader)
+ private void SkipUnwindInfo(BinaryReader unwindInfosReader)
{
int pushEntriesLength = unwindInfosReader.ReadInt32();
_unwindInfosStream.Seek(pushEntriesLength * UnwindPushEntry.Stride + UnwindInfo.Stride, SeekOrigin.Current);
}
- private static byte[] ReadCode(int index, int codeLength)
+ private byte[] ReadCode(int index, int codeLength)
{
Debug.Assert(_codesList[index].Length == codeLength);
return _codesList[index];
}
- private static RelocEntry[] GetRelocEntries(BinaryReader relocsReader, int relocEntriesCount)
+ private RelocEntry[] GetRelocEntries(BinaryReader relocsReader, int relocEntriesCount)
{
RelocEntry[] relocEntries = new RelocEntry[relocEntriesCount];
@@ -648,7 +652,7 @@ namespace ARMeilleure.Translation.PTC
return relocEntries;
}
- private static void PatchCode(Translator translator, Span<byte> code, RelocEntry[] relocEntries, out Counter<uint> callCounter)
+ private void PatchCode(Translator translator, Span<byte> code, RelocEntry[] relocEntries, out Counter<uint> callCounter)
{
callCounter = null;
@@ -702,7 +706,7 @@ namespace ARMeilleure.Translation.PTC
}
}
- private static UnwindInfo ReadUnwindInfo(BinaryReader unwindInfosReader)
+ private UnwindInfo ReadUnwindInfo(BinaryReader unwindInfosReader)
{
int pushEntriesLength = unwindInfosReader.ReadInt32();
@@ -723,7 +727,7 @@ namespace ARMeilleure.Translation.PTC
return new UnwindInfo(pushEntries, prologueSize);
}
- private static TranslatedFunction FastTranslate(
+ private TranslatedFunction FastTranslate(
byte[] code,
Counter<uint> callCounter,
ulong guestSize,
@@ -736,19 +740,19 @@ namespace ARMeilleure.Translation.PTC
return new TranslatedFunction(gFunc, callCounter, guestSize, highCq);
}
- private static void UpdateInfo(InfoEntry infoEntry)
+ private void UpdateInfo(InfoEntry infoEntry)
{
_infosStream.Seek(-Unsafe.SizeOf<InfoEntry>(), SeekOrigin.Current);
SerializeStructure(_infosStream, infoEntry);
}
- private static void StubCode(int index)
+ private void StubCode(int index)
{
_codesList[index] = Array.Empty<byte>();
}
- private static void StubReloc(int relocEntriesCount)
+ private void StubReloc(int relocEntriesCount)
{
for (int i = 0; i < relocEntriesCount * RelocEntry.Stride; i++)
{
@@ -756,7 +760,7 @@ namespace ARMeilleure.Translation.PTC
}
}
- private static void StubUnwindInfo(BinaryReader unwindInfosReader)
+ private void StubUnwindInfo(BinaryReader unwindInfosReader)
{
int pushEntriesLength = unwindInfosReader.ReadInt32();
@@ -766,9 +770,9 @@ namespace ARMeilleure.Translation.PTC
}
}
- internal static void MakeAndSaveTranslations(Translator translator)
+ public void MakeAndSaveTranslations(Translator translator)
{
- var profiledFuncsToTranslate = PtcProfiler.GetProfiledFuncsToTranslate(translator.Functions);
+ var profiledFuncsToTranslate = Profiler.GetProfiledFuncsToTranslate(translator.Functions);
_translateCount = 0;
_translateTotalCount = profiledFuncsToTranslate.Count;
@@ -811,7 +815,7 @@ namespace ARMeilleure.Translation.PTC
{
ulong address = item.address;
- Debug.Assert(PtcProfiler.IsAddressInStaticCodeRange(address));
+ Debug.Assert(Profiler.IsAddressInStaticCodeRange(address));
TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq);
@@ -861,7 +865,7 @@ namespace ARMeilleure.Translation.PTC
preSaveThread.Start();
}
- private static void ReportProgress(object state)
+ private void ReportProgress(object state)
{
const int refreshRate = 50; // ms.
@@ -882,12 +886,12 @@ namespace ARMeilleure.Translation.PTC
while (!endEvent.WaitOne(refreshRate));
}
- internal static Hash128 ComputeHash(IMemoryManager memory, ulong address, ulong guestSize)
+ public static Hash128 ComputeHash(IMemoryManager memory, ulong address, ulong guestSize)
{
return XXHash128.ComputeHash(memory.GetSpan(address, checked((int)(guestSize))));
}
- internal static void WriteCompiledFunction(ulong address, ulong guestSize, Hash128 hash, bool highCq, CompiledFunction compiledFunc)
+ public void WriteCompiledFunction(ulong address, ulong guestSize, Hash128 hash, bool highCq, CompiledFunction compiledFunc)
{
lock (_lock)
{
@@ -936,12 +940,12 @@ namespace ARMeilleure.Translation.PTC
}
}
- private static void WriteCode(ReadOnlySpan<byte> code)
+ private void WriteCode(ReadOnlySpan<byte> code)
{
_codesList.Add(code.ToArray());
}
- internal static bool GetEndianness()
+ public static bool GetEndianness()
{
return BitConverter.IsLittleEndian;
}
@@ -955,7 +959,7 @@ namespace ARMeilleure.Translation.PTC
(uint)HardwareCapabilities.FeatureInfo7Ecx);
}
- private static byte GetMemoryManagerMode()
+ private byte GetMemoryManagerMode()
{
return (byte)_memoryMode;
}
@@ -1050,12 +1054,12 @@ namespace ARMeilleure.Translation.PTC
public int RelocEntriesCount;
}
- private static void Enable()
+ private void Enable()
{
State = PtcState.Enabled;
}
- public static void Continue()
+ public void Continue()
{
if (State == PtcState.Enabled)
{
@@ -1063,7 +1067,7 @@ namespace ARMeilleure.Translation.PTC
}
}
- public static void Close()
+ public void Close()
{
if (State == PtcState.Enabled ||
State == PtcState.Continuing)
@@ -1072,17 +1076,17 @@ namespace ARMeilleure.Translation.PTC
}
}
- internal static void Disable()
+ public void Disable()
{
State = PtcState.Disabled;
}
- private static void Wait()
+ private void Wait()
{
_waitEvent.WaitOne();
}
- public static void Dispose()
+ public void Dispose()
{
if (!_disposed)
{
diff --git a/ARMeilleure/Translation/PTC/PtcProfiler.cs b/ARMeilleure/Translation/PTC/PtcProfiler.cs
index bb70da8d..0d554628 100644
--- a/ARMeilleure/Translation/PTC/PtcProfiler.cs
+++ b/ARMeilleure/Translation/PTC/PtcProfiler.cs
@@ -16,7 +16,7 @@ using static ARMeilleure.Translation.PTC.PtcFormatter;
namespace ARMeilleure.Translation.PTC
{
- public static class PtcProfiler
+ class PtcProfiler
{
private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
@@ -26,27 +26,31 @@ namespace ARMeilleure.Translation.PTC
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
- private static readonly System.Timers.Timer _timer;
+ private readonly Ptc _ptc;
- private static readonly ulong _outerHeaderMagic;
+ private readonly System.Timers.Timer _timer;
- private static readonly ManualResetEvent _waitEvent;
+ private readonly ulong _outerHeaderMagic;
- private static readonly object _lock;
+ private readonly ManualResetEvent _waitEvent;
- private static bool _disposed;
+ private readonly object _lock;
- private static Hash128 _lastHash;
+ private bool _disposed;
- internal static Dictionary<ulong, FuncProfile> ProfiledFuncs { get; private set; }
+ private Hash128 _lastHash;
- internal static bool Enabled { get; private set; }
+ public Dictionary<ulong, FuncProfile> ProfiledFuncs { get; private set; }
- public static ulong StaticCodeStart { internal get; set; }
- public static ulong StaticCodeSize { internal get; set; }
+ public bool Enabled { get; private set; }
- static PtcProfiler()
+ public ulong StaticCodeStart { get; set; }
+ public ulong StaticCodeSize { get; set; }
+
+ public PtcProfiler(Ptc ptc)
{
+ _ptc = ptc;
+
_timer = new System.Timers.Timer((double)SaveInterval * 1000d);
_timer.Elapsed += PreSave;
@@ -63,7 +67,7 @@ namespace ARMeilleure.Translation.PTC
Enabled = false;
}
- internal static void AddEntry(ulong address, ExecutionMode mode, bool highCq)
+ public void AddEntry(ulong address, ExecutionMode mode, bool highCq)
{
if (IsAddressInStaticCodeRange(address))
{
@@ -76,7 +80,7 @@ namespace ARMeilleure.Translation.PTC
}
}
- internal static void UpdateEntry(ulong address, ExecutionMode mode, bool highCq)
+ public void UpdateEntry(ulong address, ExecutionMode mode, bool highCq)
{
if (IsAddressInStaticCodeRange(address))
{
@@ -91,12 +95,12 @@ namespace ARMeilleure.Translation.PTC
}
}
- internal static bool IsAddressInStaticCodeRange(ulong address)
+ public bool IsAddressInStaticCodeRange(ulong address)
{
return address >= StaticCodeStart && address < StaticCodeStart + StaticCodeSize;
}
- internal static ConcurrentQueue<(ulong address, FuncProfile funcProfile)> GetProfiledFuncsToTranslate(TranslatorCache<TranslatedFunction> funcs)
+ public ConcurrentQueue<(ulong address, FuncProfile funcProfile)> GetProfiledFuncsToTranslate(TranslatorCache<TranslatedFunction> funcs)
{
var profiledFuncsToTranslate = new ConcurrentQueue<(ulong address, FuncProfile funcProfile)>();
@@ -111,18 +115,18 @@ namespace ARMeilleure.Translation.PTC
return profiledFuncsToTranslate;
}
- internal static void ClearEntries()
+ public void ClearEntries()
{
ProfiledFuncs.Clear();
ProfiledFuncs.TrimExcess();
}
- internal static void PreLoad()
+ public void PreLoad()
{
_lastHash = default;
- string fileNameActual = string.Concat(Ptc.CachePathActual, ".info");
- string fileNameBackup = string.Concat(Ptc.CachePathBackup, ".info");
+ string fileNameActual = string.Concat(_ptc.CachePathActual, ".info");
+ string fileNameBackup = string.Concat(_ptc.CachePathBackup, ".info");
FileInfo fileInfoActual = new FileInfo(fileNameActual);
FileInfo fileInfoBackup = new FileInfo(fileNameBackup);
@@ -143,7 +147,7 @@ namespace ARMeilleure.Translation.PTC
}
}
- private static bool Load(string fileName, bool isBackup)
+ private bool Load(string fileName, bool isBackup)
{
using (FileStream compressedStream = new(fileName, FileMode.Open))
using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true))
@@ -228,22 +232,22 @@ namespace ARMeilleure.Translation.PTC
return DeserializeDictionary<ulong, FuncProfile>(stream, (stream) => DeserializeStructure<FuncProfile>(stream));
}
- private static ReadOnlySpan<byte> GetReadOnlySpan(MemoryStream memoryStream)
+ private ReadOnlySpan<byte> GetReadOnlySpan(MemoryStream memoryStream)
{
return new(memoryStream.GetBuffer(), (int)memoryStream.Position, (int)memoryStream.Length - (int)memoryStream.Position);
}
- private static void InvalidateCompressedStream(FileStream compressedStream)
+ private void InvalidateCompressedStream(FileStream compressedStream)
{
compressedStream.SetLength(0L);
}
- private static void PreSave(object source, System.Timers.ElapsedEventArgs e)
+ private void PreSave(object source, System.Timers.ElapsedEventArgs e)
{
_waitEvent.Reset();
- string fileNameActual = string.Concat(Ptc.CachePathActual, ".info");
- string fileNameBackup = string.Concat(Ptc.CachePathBackup, ".info");
+ string fileNameActual = string.Concat(_ptc.CachePathActual, ".info");
+ string fileNameBackup = string.Concat(_ptc.CachePathBackup, ".info");
FileInfo fileInfoActual = new FileInfo(fileNameActual);
@@ -257,7 +261,7 @@ namespace ARMeilleure.Translation.PTC
_waitEvent.Set();
}
- private static void Save(string fileName)
+ private void Save(string fileName)
{
int profiledFuncsCount;
@@ -329,7 +333,7 @@ namespace ARMeilleure.Translation.PTC
}
}
- private static void Serialize(Stream stream, Dictionary<ulong, FuncProfile> profiledFuncs)
+ private void Serialize(Stream stream, Dictionary<ulong, FuncProfile> profiledFuncs)
{
SerializeDictionary(stream, profiledFuncs, (stream, structure) => SerializeStructure(stream, structure));
}
@@ -361,7 +365,7 @@ namespace ARMeilleure.Translation.PTC
}
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 5*/)]
- internal struct FuncProfile
+ public struct FuncProfile
{
public ExecutionMode Mode;
public bool HighCq;
@@ -373,10 +377,10 @@ namespace ARMeilleure.Translation.PTC
}
}
- internal static void Start()
+ public void Start()
{
- if (Ptc.State == PtcState.Enabled ||
- Ptc.State == PtcState.Continuing)
+ if (_ptc.State == PtcState.Enabled ||
+ _ptc.State == PtcState.Continuing)
{
Enabled = true;
@@ -384,7 +388,7 @@ namespace ARMeilleure.Translation.PTC
}
}
- public static void Stop()
+ public void Stop()
{
Enabled = false;
@@ -394,12 +398,12 @@ namespace ARMeilleure.Translation.PTC
}
}
- internal static void Wait()
+ public void Wait()
{
_waitEvent.WaitOne();
}
- public static void Dispose()
+ public void Dispose()
{
if (!_disposed)
{
diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs
index 2edbe401..77ccdaea 100644
--- a/ARMeilleure/Translation/Translator.cs
+++ b/ARMeilleure/Translation/Translator.cs
@@ -44,6 +44,8 @@ namespace ARMeilleure.Translation
private readonly IJitMemoryAllocator _allocator;
private readonly ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>> _oldFuncs;
+ private readonly Ptc _ptc;
+
internal TranslatorCache<TranslatedFunction> Functions { get; }
internal AddressTable<ulong> FunctionTable { get; }
internal EntryTable<uint> CountTable { get; }
@@ -63,6 +65,8 @@ namespace ARMeilleure.Translation
_oldFuncs = new ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>>();
+ _ptc = new Ptc();
+
Queue = new TranslatorQueue();
JitCache.Initialize(allocator);
@@ -80,22 +84,37 @@ namespace ARMeilleure.Translation
}
}
+ public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
+ {
+ _ptc.Initialize(titleIdText, displayVersion, enabled, Memory.Type);
+ return _ptc;
+ }
+
+ public void PrepareCodeRange(ulong address, ulong size)
+ {
+ if (_ptc.Profiler.StaticCodeSize == 0)
+ {
+ _ptc.Profiler.StaticCodeStart = address;
+ _ptc.Profiler.StaticCodeSize = size;
+ }
+ }
+
public void Execute(State.ExecutionContext context, ulong address)
{
if (Interlocked.Increment(ref _threadCount) == 1)
{
IsReadyForTranslation.WaitOne();
- if (Ptc.State == PtcState.Enabled)
+ if (_ptc.State == PtcState.Enabled)
{
Debug.Assert(Functions.Count == 0);
- Ptc.LoadTranslations(this);
- Ptc.MakeAndSaveTranslations(this);
+ _ptc.LoadTranslations(this);
+ _ptc.MakeAndSaveTranslations(this);
}
- PtcProfiler.Start();
+ _ptc.Profiler.Start();
- Ptc.Disable();
+ _ptc.Disable();
// Simple heuristic, should be user configurable in future. (1 for 4 core/ht or less, 2 for 6 core + ht
// etc). All threads are normal priority except from the last, which just fills as much of the last core
@@ -148,6 +167,12 @@ namespace ARMeilleure.Translation
Stubs.Dispose();
FunctionTable.Dispose();
CountTable.Dispose();
+
+ _ptc.Close();
+ _ptc.Profiler.Stop();
+
+ _ptc.Dispose();
+ _ptc.Profiler.Dispose();
}
}
@@ -189,9 +214,9 @@ namespace ARMeilleure.Translation
func = oldFunc;
}
- if (PtcProfiler.Enabled)
+ if (_ptc.Profiler.Enabled)
{
- PtcProfiler.AddEntry(address, mode, highCq: false);
+ _ptc.Profiler.AddEntry(address, mode, highCq: false);
}
RegisterFunction(address, func);
@@ -217,6 +242,7 @@ namespace ARMeilleure.Translation
Stubs,
address,
highCq,
+ _ptc.State != PtcState.Disabled,
mode: Aarch32Mode.User);
Logger.StartPass(PassName.Decoding);
@@ -262,7 +288,7 @@ namespace ARMeilleure.Translation
{
Hash128 hash = Ptc.ComputeHash(Memory, address, funcSize);
- Ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
+ _ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
}
GuestFunction func = compiledFunc.Map<GuestFunction>();
@@ -284,9 +310,9 @@ namespace ARMeilleure.Translation
return func;
});
- if (PtcProfiler.Enabled)
+ if (_ptc.Profiler.Enabled)
{
- PtcProfiler.UpdateEntry(request.Address, request.Mode, highCq: true);
+ _ptc.Profiler.UpdateEntry(request.Address, request.Mode, highCq: true);
}
RegisterFunction(request.Address, func);
diff --git a/Ryujinx.Ava/AppHost.cs b/Ryujinx.Ava/AppHost.cs
index 0baa94c3..2cf53ef6 100644
--- a/Ryujinx.Ava/AppHost.cs
+++ b/Ryujinx.Ava/AppHost.cs
@@ -1,5 +1,4 @@
using ARMeilleure.Translation;
-using ARMeilleure.Translation.PTC;
using Avalonia.Input;
using Avalonia.Threading;
using LibHac.Tools.FsSystem;
@@ -280,7 +279,7 @@ namespace Ryujinx.Ava
_parent.Title = $"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
});
- _parent.ViewModel.HandleShaderProgress(Device);
+ _parent.ViewModel.SetUiProgressHandlers(Device);
Renderer.SizeChanged += Window_SizeChanged;
@@ -357,8 +356,6 @@ namespace Ryujinx.Ava
DisplaySleep.Restore();
- Ptc.Close();
- PtcProfiler.Stop();
NpadManager.Dispose();
TouchScreenManager.Dispose();
Device.Dispose();
@@ -949,7 +946,7 @@ namespace Ryujinx.Ava
if (_keyboardInterface.GetKeyboardStateSnapshot().IsPressed(Key.Delete) && _parent.WindowState != WindowState.FullScreen)
{
- Ptc.Continue();
+ Device.Application.DiskCacheLoadState?.Cancel();
}
});
}
diff --git a/Ryujinx.Ava/Program.cs b/Ryujinx.Ava/Program.cs
index 142d7820..836801c8 100644
--- a/Ryujinx.Ava/Program.cs
+++ b/Ryujinx.Ava/Program.cs
@@ -1,4 +1,3 @@
-using ARMeilleure.Translation.PTC;
using Avalonia;
using Avalonia.Threading;
using Ryujinx.Ava.UI.Windows;
@@ -197,9 +196,6 @@ namespace Ryujinx.Ava
private static void ProcessUnhandledException(Exception ex, bool isTerminating)
{
- Ptc.Close();
- PtcProfiler.Stop();
-
string message = $"Unhandled exception caught: {ex}";
Logger.Error?.PrintMsg(LogClass.Application, message);
@@ -219,9 +215,6 @@ namespace Ryujinx.Ava
{
DiscordIntegrationModule.Exit();
- Ptc.Dispose();
- PtcProfiler.Dispose();
-
Logger.Shutdown();
}
}
diff --git a/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs b/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
index 878af3f8..953f8562 100644
--- a/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
+++ b/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
@@ -1,4 +1,3 @@
-using ARMeilleure.Translation.PTC;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
@@ -18,6 +17,7 @@ using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
+using Ryujinx.Cpu;
using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
@@ -107,9 +107,6 @@ namespace Ryujinx.Ava.UI.ViewModels
{
ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated;
ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded;
-
- Ptc.PtcStateChanged -= ProgressHandler;
- Ptc.PtcStateChanged += ProgressHandler;
}
public string SearchText
@@ -436,7 +433,7 @@ namespace Ryujinx.Ava.UI.ViewModels
OnPropertyChanged();
}
}
-
+
public bool ShowMenuAndStatusBar
{
get => _showMenuAndStatusBar;
@@ -745,8 +742,14 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
- public void HandleShaderProgress(Switch emulationContext)
+ public void SetUiProgressHandlers(Switch emulationContext)
{
+ if (emulationContext.Application.DiskCacheLoadState != null)
+ {
+ emulationContext.Application.DiskCacheLoadState.StateChanged -= ProgressHandler;
+ emulationContext.Application.DiskCacheLoadState.StateChanged += ProgressHandler;
+ }
+
emulationContext.Gpu.ShaderCacheStateChanged -= ProgressHandler;
emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler;
}
@@ -1033,16 +1036,16 @@ namespace Ryujinx.Ava.UI.ViewModels
switch (state)
{
- case PtcLoadingState ptcState:
+ case LoadState ptcState:
CacheLoadStatus = $"{current} / {total}";
switch (ptcState)
{
- case PtcLoadingState.Start:
- case PtcLoadingState.Loading:
+ case LoadState.Unloaded:
+ case LoadState.Loading:
LoadHeading = LocaleManager.Instance[LocaleKeys.CompilingPPTC];
IsLoadingIndeterminate = false;
break;
- case PtcLoadingState.Loaded:
+ case LoadState.Loaded:
LoadHeading = string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], TitleName);
IsLoadingIndeterminate = true;
CacheLoadStatus = "";
@@ -1166,7 +1169,7 @@ namespace Ryujinx.Ava.UI.ViewModels
DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "1"));
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
- UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
+ UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
string.Format(LocaleManager.Instance[LocaleKeys.DialogPPTCDeletionMessage], selection.TitleName),
LocaleManager.Instance[LocaleKeys.InputDialogYes],
LocaleManager.Instance[LocaleKeys.InputDialogNo],
diff --git a/Ryujinx.Cpu/ICpuContext.cs b/Ryujinx.Cpu/ICpuContext.cs
index 4a73a833..80916d1c 100644
--- a/Ryujinx.Cpu/ICpuContext.cs
+++ b/Ryujinx.Cpu/ICpuContext.cs
@@ -35,5 +35,27 @@ namespace Ryujinx.Cpu
/// <param name="address">Address of the region to be invalidated</param>
/// <param name="size">Size of the region to be invalidated</param>
void InvalidateCacheRegion(ulong address, ulong size);
+
+ /// <summary>
+ /// Loads cached code from disk for a given application.
+ /// </summary>
+ /// <remarks>
+ /// If the execution engine is recompiling guest code, this can be used to load cached code from disk.
+ /// </remarks>
+ /// <param name="titleIdText">Title ID of the application in padded hex form</param>
+ /// <param name="displayVersion">Version of the application</param>
+ /// <param name="enabled">True if the cache should be loaded from disk if it exists, false otherwise</param>
+ /// <returns>Disk cache load progress reporter and manager</returns>
+ IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled);
+
+ /// <summary>
+ /// Indicates that code has been loaded into guest memory, and that it might be executed in the future.
+ /// </summary>
+ /// <remarks>
+ /// Some execution engines might use this information to cache recompiled code on disk or to ensure it can be executed.
+ /// </remarks>
+ /// <param name="address">CPU virtual address where the code starts</param>
+ /// <param name="size">Size of the code range in bytes</param>
+ void PrepareCodeRange(ulong address, ulong size);
}
}
diff --git a/Ryujinx.Cpu/IDiskCacheState.cs b/Ryujinx.Cpu/IDiskCacheState.cs
new file mode 100644
index 00000000..61bbdf92
--- /dev/null
+++ b/Ryujinx.Cpu/IDiskCacheState.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Ryujinx.Cpu
+{
+ /// <summary>
+ /// Disk cache load state report and management interface.
+ /// </summary>
+ public interface IDiskCacheLoadState
+ {
+ /// <summary>
+ /// Event used to report the cache load progress.
+ /// </summary>
+ event Action<LoadState, int, int> StateChanged;
+
+ /// <summary>
+ /// Cancels the disk cache load process.
+ /// </summary>
+ void Cancel();
+ }
+}
diff --git a/Ryujinx.Cpu/Jit/JitCpuContext.cs b/Ryujinx.Cpu/Jit/JitCpuContext.cs
index d6892ea7..02465a0b 100644
--- a/Ryujinx.Cpu/Jit/JitCpuContext.cs
+++ b/Ryujinx.Cpu/Jit/JitCpuContext.cs
@@ -37,5 +37,17 @@ namespace Ryujinx.Cpu.Jit
{
_translator.InvalidateJitCacheRegion(address, size);
}
+
+ /// <inheritdoc/>
+ public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
+ {
+ return new JitDiskCacheLoadState(_translator.LoadDiskCache(titleIdText, displayVersion, enabled));
+ }
+
+ /// <inheritdoc/>
+ public void PrepareCodeRange(ulong address, ulong size)
+ {
+ _translator.PrepareCodeRange(address, size);
+ }
}
}
diff --git a/Ryujinx.Cpu/Jit/JitDiskCacheLoadState.cs b/Ryujinx.Cpu/Jit/JitDiskCacheLoadState.cs
new file mode 100644
index 00000000..7a4b670b
--- /dev/null
+++ b/Ryujinx.Cpu/Jit/JitDiskCacheLoadState.cs
@@ -0,0 +1,38 @@
+using ARMeilleure.Translation.PTC;
+using System;
+
+namespace Ryujinx.Cpu.Jit
+{
+ public class JitDiskCacheLoadState : IDiskCacheLoadState
+ {
+ /// <inheritdoc/>
+ public event Action<LoadState, int, int> StateChanged;
+
+ private readonly IPtcLoadState _loadState;
+
+ public JitDiskCacheLoadState(IPtcLoadState loadState)
+ {
+ loadState.PtcStateChanged += LoadStateChanged;
+ _loadState = loadState;
+ }
+
+ private void LoadStateChanged(PtcLoadingState newState, int current, int total)
+ {
+ LoadState state = newState switch
+ {
+ PtcLoadingState.Start => LoadState.Unloaded,
+ PtcLoadingState.Loading => LoadState.Loading,
+ PtcLoadingState.Loaded => LoadState.Loaded,
+ _ => throw new ArgumentException($"Invalid load state \"{newState}\".")
+ };
+
+ StateChanged?.Invoke(state, current, total);
+ }
+
+ /// <inheritdoc/>
+ public void Cancel()
+ {
+ _loadState.Continue();
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Cpu/LoadState.cs b/Ryujinx.Cpu/LoadState.cs
new file mode 100644
index 00000000..1f2e1ae8
--- /dev/null
+++ b/Ryujinx.Cpu/LoadState.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Cpu
+{
+ /// <summary>
+ /// Load state.
+ /// </summary>
+ public enum LoadState
+ {
+ Unloaded,
+ Loading,
+ Loaded
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/ApplicationLoader.cs b/Ryujinx.HLE/HOS/ApplicationLoader.cs
index 61fcd0c3..06281b49 100644
--- a/Ryujinx.HLE/HOS/ApplicationLoader.cs
+++ b/Ryujinx.HLE/HOS/ApplicationLoader.cs
@@ -1,4 +1,3 @@
-using ARMeilleure.Translation.PTC;
using LibHac;
using LibHac.Account;
using LibHac.Common;
@@ -14,8 +13,8 @@ using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
+using Ryujinx.Cpu;
using Ryujinx.HLE.FileSystem;
-using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.Memory;
using System;
@@ -67,6 +66,8 @@ namespace Ryujinx.HLE.HOS
public string TitleIdText => TitleId.ToString("x16");
+ public IDiskCacheLoadState DiskCacheLoadState { get; private set; }
+
public ApplicationLoader(Switch device)
{
_device = device;
@@ -94,7 +95,7 @@ namespace Ryujinx.HLE.HOS
EnsureSaveData(new ApplicationId(TitleId));
}
- LoadExeFs(codeFs, metaData);
+ LoadExeFs(codeFs, string.Empty, metaData);
}
public static (Nca main, Nca patch, Nca control) GetGameData(VirtualFileSystem fileSystem, PartitionFileSystem pfs, int programIndex)
@@ -302,12 +303,6 @@ namespace Ryujinx.HLE.HOS
public void LoadServiceNca(string ncaFile)
{
- // Disable PPTC here as it does not support multiple processes running.
- // TODO: This should be eventually removed and it should stop using global state and
- // instead manage the cache per process.
- Ptc.Close();
- PtcProfiler.Stop();
-
FileStream file = new FileStream(ncaFile, FileMode.Open, FileAccess.Read);
Nca mainNca = new Nca(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false));
@@ -369,16 +364,12 @@ namespace Ryujinx.HLE.HOS
// Collect the nsos, ignoring ones that aren't used.
NsoExecutable[] programs = nsos.Where(x => x != null).ToArray();
- MemoryManagerMode memoryManagerMode = _device.Configuration.MemoryManagerMode;
-
- if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))
- {
- memoryManagerMode = MemoryManagerMode.SoftwarePageTable;
- }
+ string displayVersion = _device.System.ContentManager.GetCurrentFirmwareVersion().VersionString;
+ bool usePtc = _device.System.EnablePtc;
metaData.GetNpdm(out Npdm npdm).ThrowIfFailure();
- ProgramInfo programInfo = new ProgramInfo(in npdm, allowCodeMemoryForJit: false);
- ProgramLoader.LoadNsos(_device.System.KernelContext, out _, metaData, programInfo, executables: programs);
+ ProgramInfo programInfo = new ProgramInfo(in npdm, displayVersion, usePtc, allowCodeMemoryForJit: false);
+ ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: programs);
string titleIdText = npdm.Aci.Value.ProgramId.Value.ToString("x16");
bool titleIs64Bit = (npdm.Meta.Value.Flags & 1) != 0;
@@ -477,9 +468,11 @@ namespace Ryujinx.HLE.HOS
_device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath(),
_device.Configuration.VirtualFileSystem.ModLoader.GetSdModsBasePath());
+ string displayVersion = string.Empty;
+
if (controlNca != null)
{
- ReadControlData(_device, controlNca, ref _controlData, ref _titleName, ref _displayVersion);
+ ReadControlData(_device, controlNca, ref _controlData, ref _titleName, ref displayVersion);
}
else
{
@@ -493,9 +486,11 @@ namespace Ryujinx.HLE.HOS
string dummyTitleName = "";
BlitStruct<ApplicationControlProperty> dummyControl = new BlitStruct<ApplicationControlProperty>(1);
- ReadControlData(_device, updateProgram0ControlNca, ref dummyControl, ref dummyTitleName, ref _displayVersion);
+ ReadControlData(_device, updateProgram0ControlNca, ref dummyControl, ref dummyTitleName, ref displayVersion);
}
+ _displayVersion = displayVersion;
+
if (dataStorage == null)
{
Logger.Warning?.Print(LogClass.Loader, "No RomFS found in NCA");
@@ -515,7 +510,7 @@ namespace Ryujinx.HLE.HOS
EnsureSaveData(new ApplicationId(TitleId & ~0xFul));
}
- LoadExeFs(codeFs, metaData);
+ LoadExeFs(codeFs, displayVersion, metaData);
Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {TitleName} v{DisplayVersion} [{TitleIdText}] [{(TitleIs64Bit ? "64-bit" : "32-bit")}]");
}
@@ -584,7 +579,7 @@ namespace Ryujinx.HLE.HOS
}
}
- private void LoadExeFs(IFileSystem codeFs, MetaLoader metaData = null, bool isHomebrew = false)
+ private void LoadExeFs(IFileSystem codeFs, string displayVersion, MetaLoader metaData = null, bool isHomebrew = false)
{
if (_device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs))
{
@@ -649,23 +644,23 @@ namespace Ryujinx.HLE.HOS
memoryManagerMode = MemoryManagerMode.SoftwarePageTable;
}
- Ptc.Initialize(TitleIdText, DisplayVersion, usePtc, memoryManagerMode);
-
// We allow it for nx-hbloader because it can be used to launch homebrew.
bool allowCodeMemoryForJit = TitleId == 0x010000000000100DUL || isHomebrew;
metaData.GetNpdm(out Npdm npdm).ThrowIfFailure();
- ProgramInfo programInfo = new ProgramInfo(in npdm, allowCodeMemoryForJit);
- ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, programInfo, executables: programs);
+ ProgramInfo programInfo = new ProgramInfo(in npdm, displayVersion, usePtc, allowCodeMemoryForJit);
+ ProgramLoadResult result = ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: programs);
+
+ DiskCacheLoadState = result.DiskCacheLoadState;
- _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine);
+ _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine);
}
public void LoadProgram(string filePath)
{
MetaLoader metaData = GetDefaultNpdm();
metaData.GetNpdm(out Npdm npdm).ThrowIfFailure();
- ProgramInfo programInfo = new ProgramInfo(in npdm, allowCodeMemoryForJit: true);
+ ProgramInfo programInfo = new ProgramInfo(in npdm, string.Empty, diskCacheEnabled: false, allowCodeMemoryForJit: true);
bool isNro = Path.GetExtension(filePath).ToLower() == ".nro";
@@ -761,9 +756,11 @@ namespace Ryujinx.HLE.HOS
Graphics.Gpu.GraphicsConfig.TitleId = null;
_device.Gpu.HostInitalized.Set();
- ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, programInfo, executables: executable);
+ ProgramLoadResult result = ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: executable);
+
+ DiskCacheLoadState = result.DiskCacheLoadState;
- _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine);
+ _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine);
}
private MetaLoader GetDefaultNpdm()
diff --git a/Ryujinx.HLE/HOS/ArmProcessContext.cs b/Ryujinx.HLE/HOS/ArmProcessContext.cs
index 072df0b6..6338edc1 100644
--- a/Ryujinx.HLE/HOS/ArmProcessContext.cs
+++ b/Ryujinx.HLE/HOS/ArmProcessContext.cs
@@ -6,7 +6,17 @@ using Ryujinx.Memory;
namespace Ryujinx.HLE.HOS
{
- class ArmProcessContext<T> : IProcessContext where T : class, IVirtualMemoryManagerTracked, IMemoryManager
+ interface IArmProcessContext : IProcessContext
+ {
+ IDiskCacheLoadState Initialize(
+ string titleIdText,
+ string displayVersion,
+ bool diskCacheEnabled,
+ ulong codeAddress,
+ ulong codeSize);
+ }
+
+ class ArmProcessContext<T> : IArmProcessContext where T : class, IVirtualMemoryManagerTracked, IMemoryManager
{
private readonly ulong _pid;
private readonly GpuContext _gpuContext;
@@ -40,6 +50,17 @@ namespace Ryujinx.HLE.HOS
_cpuContext.Execute(context, codeAddress);
}
+ public IDiskCacheLoadState Initialize(
+ string titleIdText,
+ string displayVersion,
+ bool diskCacheEnabled,
+ ulong codeAddress,
+ ulong codeSize)
+ {
+ _cpuContext.PrepareCodeRange(codeAddress, codeSize);
+ return _cpuContext.LoadDiskCache(titleIdText, displayVersion, diskCacheEnabled);
+ }
+
public void InvalidateCacheRegion(ulong address, ulong size)
{
_cpuContext.InvalidateCacheRegion(address, size);
diff --git a/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs b/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs
index 7d1c4e1d..5ecaf38e 100644
--- a/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs
+++ b/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs
@@ -13,11 +13,30 @@ namespace Ryujinx.HLE.HOS
{
private readonly ICpuEngine _cpuEngine;
private readonly GpuContext _gpu;
+ private readonly string _titleIdText;
+ private readonly string _displayVersion;
+ private readonly bool _diskCacheEnabled;
+ private readonly ulong _codeAddress;
+ private readonly ulong _codeSize;
- public ArmProcessContextFactory(ICpuEngine cpuEngine, GpuContext gpu)
+ public IDiskCacheLoadState DiskCacheLoadState { get; private set; }
+
+ public ArmProcessContextFactory(
+ ICpuEngine cpuEngine,
+ GpuContext gpu,
+ string titleIdText,
+ string displayVersion,
+ bool diskCacheEnabled,
+ ulong codeAddress,
+ ulong codeSize)
{
_cpuEngine = cpuEngine;
_gpu = gpu;
+ _titleIdText = titleIdText;
+ _displayVersion = displayVersion;
+ _diskCacheEnabled = diskCacheEnabled;
+ _codeAddress = codeAddress;
+ _codeSize = codeSize;
}
public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit)
@@ -29,21 +48,29 @@ namespace Ryujinx.HLE.HOS
mode = MemoryManagerMode.SoftwarePageTable;
}
+ IArmProcessContext processContext;
+
switch (mode)
{
case MemoryManagerMode.SoftwarePageTable:
var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
- return new ArmProcessContext<MemoryManager>(pid, _cpuEngine, _gpu, memoryManager, for64Bit);
+ processContext = new ArmProcessContext<MemoryManager>(pid, _cpuEngine, _gpu, memoryManager, for64Bit);
+ break;
case MemoryManagerMode.HostMapped:
case MemoryManagerMode.HostMappedUnsafe:
bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe;
var memoryManagerHostMapped = new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler);
- return new ArmProcessContext<MemoryManagerHostMapped>(pid, _cpuEngine, _gpu, memoryManagerHostMapped, for64Bit);
+ processContext = new ArmProcessContext<MemoryManagerHostMapped>(pid, _cpuEngine, _gpu, memoryManagerHostMapped, for64Bit);
+ break;
default:
throw new ArgumentOutOfRangeException();
}
+
+ DiskCacheLoadState = processContext.Initialize(_titleIdText, _displayVersion, _diskCacheEnabled, _codeAddress, _codeSize);
+
+ return processContext;
}
}
}
diff --git a/Ryujinx.HLE/HOS/ProgramLoader.cs b/Ryujinx.HLE/HOS/ProgramLoader.cs
index b422fef7..09e1ac31 100644
--- a/Ryujinx.HLE/HOS/ProgramLoader.cs
+++ b/Ryujinx.HLE/HOS/ProgramLoader.cs
@@ -1,9 +1,9 @@
-using ARMeilleure.Translation.PTC;
using LibHac.Loader;
using LibHac.Ncm;
using LibHac.Util;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
+using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
@@ -21,16 +21,40 @@ namespace Ryujinx.HLE.HOS
{
public string Name;
public ulong ProgramId;
- public bool AllowCodeMemoryForJit;
+ public readonly string TitleIdText;
+ public readonly string DisplayVersion;
+ public readonly bool DiskCacheEnabled;
+ public readonly bool AllowCodeMemoryForJit;
- public ProgramInfo(in Npdm npdm, bool allowCodeMemoryForJit)
+ public ProgramInfo(in Npdm npdm, string displayVersion, bool diskCacheEnabled, bool allowCodeMemoryForJit)
{
+ ulong programId = npdm.Aci.Value.ProgramId.Value;
+
Name = StringUtils.Utf8ZToString(npdm.Meta.Value.ProgramName);
- ProgramId = npdm.Aci.Value.ProgramId.Value;
+ ProgramId = programId;
+ TitleIdText = programId.ToString("x16");
+ DisplayVersion = displayVersion;
+ DiskCacheEnabled = diskCacheEnabled;
AllowCodeMemoryForJit = allowCodeMemoryForJit;
}
}
+ struct ProgramLoadResult
+ {
+ public static ProgramLoadResult Failed => new ProgramLoadResult(false, null, null);
+
+ public readonly bool Success;
+ public readonly ProcessTamperInfo TamperInfo;
+ public readonly IDiskCacheLoadState DiskCacheLoadState;
+
+ public ProgramLoadResult(bool success, ProcessTamperInfo tamperInfo, IDiskCacheLoadState diskCacheLoadState)
+ {
+ Success = success;
+ TamperInfo = tamperInfo;
+ DiskCacheLoadState = diskCacheLoadState;
+ }
+ }
+
static class ProgramLoader
{
private const bool AslrEnabled = true;
@@ -102,7 +126,14 @@ namespace Ryujinx.HLE.HOS
KProcess process = new KProcess(context);
- var processContextFactory = new ArmProcessContextFactory(context.Device.System.CpuEngine, context.Device.Gpu);
+ var processContextFactory = new ArmProcessContextFactory(
+ context.Device.System.CpuEngine,
+ context.Device.Gpu,
+ string.Empty,
+ string.Empty,
+ false,
+ codeAddress,
+ codeSize);
result = process.InitializeKip(
creationInfo,
@@ -144,9 +175,8 @@ namespace Ryujinx.HLE.HOS
return true;
}
- public static bool LoadNsos(
+ public static ProgramLoadResult LoadNsos(
KernelContext context,
- out ProcessTamperInfo tamperInfo,
MetaLoader metaData,
ProgramInfo programInfo,
byte[] arguments = null,
@@ -156,8 +186,7 @@ namespace Ryujinx.HLE.HOS
if (rc.IsFailure())
{
- tamperInfo = null;
- return false;
+ return ProgramLoadResult.Failed;
}
ref readonly var meta = ref npdm.Meta.Value;
@@ -212,9 +241,6 @@ namespace Ryujinx.HLE.HOS
}
}
- PtcProfiler.StaticCodeStart = codeStart;
- PtcProfiler.StaticCodeSize = (ulong)codeSize;
-
int codePagesCount = (int)(codeSize / KPageTableBase.PageSize);
int personalMmHeapPagesCount = (int)(meta.SystemResourceSize / KPageTableBase.PageSize);
@@ -263,9 +289,7 @@ namespace Ryujinx.HLE.HOS
{
Logger.Error?.Print(LogClass.Loader, $"Process initialization failed setting resource limit values.");
- tamperInfo = null;
-
- return false;
+ return ProgramLoadResult.Failed;
}
KProcess process = new KProcess(context, programInfo.AllowCodeMemoryForJit);
@@ -276,12 +300,17 @@ namespace Ryujinx.HLE.HOS
{
Logger.Error?.Print(LogClass.Loader, $"Process initialization failed due to invalid ACID flags.");
- tamperInfo = null;
-
- return false;
+ return ProgramLoadResult.Failed;
}
- var processContextFactory = new ArmProcessContextFactory(context.Device.System.CpuEngine, context.Device.Gpu);
+ var processContextFactory = new ArmProcessContextFactory(
+ context.Device.System.CpuEngine,
+ context.Device.Gpu,
+ programInfo.TitleIdText,
+ programInfo.DisplayVersion,
+ programInfo.DiskCacheEnabled,
+ codeStart,
+ codeSize);
result = process.Initialize(
creationInfo,
@@ -294,9 +323,7 @@ namespace Ryujinx.HLE.HOS
{
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
- tamperInfo = null;
-
- return false;
+ return ProgramLoadResult.Failed;
}
for (int index = 0; index < executables.Length; index++)
@@ -309,9 +336,7 @@ namespace Ryujinx.HLE.HOS
{
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
- tamperInfo = null;
-
- return false;
+ return ProgramLoadResult.Failed;
}
}
@@ -323,9 +348,7 @@ namespace Ryujinx.HLE.HOS
{
Logger.Error?.Print(LogClass.Loader, $"Process start returned error \"{result}\".");
- tamperInfo = null;
-
- return false;
+ return ProgramLoadResult.Failed;
}
context.Processes.TryAdd(process.Pid, process);
@@ -333,10 +356,15 @@ namespace Ryujinx.HLE.HOS
// Keep the build ids because the tamper machine uses them to know which process to associate a
// tamper to and also keep the starting address of each executable inside a process because some
// memory modifications are relative to this address.
- tamperInfo = new ProcessTamperInfo(process, buildIds, nsoBase, process.MemoryManager.HeapRegionStart,
- process.MemoryManager.AliasRegionStart, process.MemoryManager.CodeRegionStart);
-
- return true;
+ ProcessTamperInfo tamperInfo = new ProcessTamperInfo(
+ process,
+ buildIds,
+ nsoBase,
+ process.MemoryManager.HeapRegionStart,
+ process.MemoryManager.AliasRegionStart,
+ process.MemoryManager.CodeRegionStart);
+
+ return new ProgramLoadResult(true, tamperInfo, processContextFactory.DiskCacheLoadState);
}
private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)
diff --git a/Ryujinx.Headless.SDL2/Program.cs b/Ryujinx.Headless.SDL2/Program.cs
index 4a2ba99d..b0c29e56 100644
--- a/Ryujinx.Headless.SDL2/Program.cs
+++ b/Ryujinx.Headless.SDL2/Program.cs
@@ -1,5 +1,4 @@
using ARMeilleure.Translation;
-using ARMeilleure.Translation.PTC;
using CommandLine;
using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.SDL2;
@@ -12,6 +11,7 @@ using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.Logging;
using Ryujinx.Common.SystemInterop;
using Ryujinx.Common.Utilities;
+using Ryujinx.Cpu;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.Gpu;
@@ -447,8 +447,11 @@ namespace Ryujinx.Headless.SDL2
private static void SetupProgressHandler()
{
- Ptc.PtcStateChanged -= ProgressHandler;
- Ptc.PtcStateChanged += ProgressHandler;
+ if (_emulationContext.Application.DiskCacheLoadState != null)
+ {
+ _emulationContext.Application.DiskCacheLoadState.StateChanged -= ProgressHandler;
+ _emulationContext.Application.DiskCacheLoadState.StateChanged += ProgressHandler;
+ }
_emulationContext.Gpu.ShaderCacheStateChanged -= ProgressHandler;
_emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler;
@@ -460,7 +463,7 @@ namespace Ryujinx.Headless.SDL2
switch (state)
{
- case PtcLoadingState ptcState:
+ case LoadState ptcState:
label = $"PTC : {current}/{total}";
break;
case ShaderCacheState shaderCacheState:
@@ -563,9 +566,6 @@ namespace Ryujinx.Headless.SDL2
_window.Execute();
- Ptc.Close();
- PtcProfiler.Stop();
-
_emulationContext.Dispose();
_window.Dispose();
diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs
index e27c4ae9..787a8ad5 100644
--- a/Ryujinx/Program.cs
+++ b/Ryujinx/Program.cs
@@ -1,4 +1,3 @@
-using ARMeilleure.Translation.PTC;
using Gtk;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
@@ -308,9 +307,6 @@ namespace Ryujinx
private static void ProcessUnhandledException(Exception ex, bool isTerminating)
{
- Ptc.Close();
- PtcProfiler.Stop();
-
string message = $"Unhandled exception caught: {ex}";
Logger.Error?.PrintMsg(LogClass.Application, message);
@@ -330,9 +326,6 @@ namespace Ryujinx
{
DiscordIntegrationModule.Exit();
- Ptc.Dispose();
- PtcProfiler.Dispose();
-
Logger.Shutdown();
}
}
diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs
index 0e7e4d62..495f6651 100644
--- a/Ryujinx/Ui/MainWindow.cs
+++ b/Ryujinx/Ui/MainWindow.cs
@@ -1,5 +1,4 @@
using ARMeilleure.Translation;
-using ARMeilleure.Translation.PTC;
using Gtk;
using LibHac.Common;
using LibHac.Common.Keys;
@@ -16,6 +15,7 @@ using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Common.SystemInterop;
+using Ryujinx.Cpu;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.OpenGL;
@@ -46,7 +46,6 @@ using System.Threading;
using System.Threading.Tasks;
using GUI = Gtk.Builder.ObjectAttribute;
-using PtcLoadingState = ARMeilleure.Translation.PTC.PtcLoadingState;
using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
namespace Ryujinx.Ui
@@ -588,8 +587,11 @@ namespace Ryujinx.Ui
private void SetupProgressUiHandlers()
{
- Ptc.PtcStateChanged -= ProgressHandler;
- Ptc.PtcStateChanged += ProgressHandler;
+ if (_emulationContext.Application.DiskCacheLoadState != null)
+ {
+ _emulationContext.Application.DiskCacheLoadState.StateChanged -= ProgressHandler;
+ _emulationContext.Application.DiskCacheLoadState.StateChanged += ProgressHandler;
+ }
_emulationContext.Gpu.ShaderCacheStateChanged -= ProgressHandler;
_emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler;
@@ -602,8 +604,8 @@ namespace Ryujinx.Ui
switch (state)
{
- case PtcLoadingState ptcState:
- visible = ptcState != PtcLoadingState.Loaded;
+ case LoadState ptcState:
+ visible = ptcState != LoadState.Loaded;
label = $"PTC : {current}/{total}";
break;
case ShaderCacheLoadingState shaderCacheState:
@@ -705,8 +707,6 @@ namespace Ryujinx.Ui
UpdateGraphicsConfig();
- SetupProgressUiHandlers();
-
SystemVersion firmwareVersion = _contentManager.GetCurrentFirmwareVersion();
bool isDirectory = Directory.Exists(path);
@@ -841,6 +841,8 @@ namespace Ryujinx.Ui
return;
}
+ SetupProgressUiHandlers();
+
_currentEmulatedGamePath = path;
_deviceExitStatus.Reset();
@@ -967,9 +969,6 @@ namespace Ryujinx.Ui
RendererWidget.Start();
- Ptc.Close();
- PtcProfiler.Stop();
-
_emulationContext.Dispose();
_deviceExitStatus.Set();
diff --git a/Ryujinx/Ui/RendererWidgetBase.cs b/Ryujinx/Ui/RendererWidgetBase.cs
index 9dabe817..8db023be 100644
--- a/Ryujinx/Ui/RendererWidgetBase.cs
+++ b/Ryujinx/Ui/RendererWidgetBase.cs
@@ -1,5 +1,4 @@
using ARMeilleure.Translation;
-using ARMeilleure.Translation.PTC;
using Gdk;
using Gtk;
using Ryujinx.Common;
@@ -519,7 +518,7 @@ namespace Ryujinx.Ui
_gpuCancellationTokenSource.Cancel();
_isStopped = true;
-
+
if (_isActive)
{
_isActive = false;
@@ -585,7 +584,7 @@ namespace Ryujinx.Ui
{
if (!ParentWindow.State.HasFlag(WindowState.Fullscreen))
{
- Ptc.Continue();
+ Device.Application.DiskCacheLoadState?.Cancel();
}
}
});