Make PPTC state non-static (#4157)

* Make PPTC state non-static

* DiskCacheLoadState can be null
This commit is contained in:
gdkchan 2023-01-04 20:01:44 -03:00 committed by GitHub
parent 08831eecf7
commit fc4b7cba2c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 434 additions and 230 deletions

View file

@ -6,7 +6,6 @@ using ARMeilleure.Instructions;
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Memory; using ARMeilleure.Memory;
using ARMeilleure.State; using ARMeilleure.State;
using ARMeilleure.Translation.PTC;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
@ -44,14 +43,13 @@ namespace ARMeilleure.Translation
public IMemoryManager Memory { get; } public IMemoryManager Memory { get; }
public bool HasPtc { get; }
public EntryTable<uint> CountTable { get; } public EntryTable<uint> CountTable { get; }
public AddressTable<ulong> FunctionTable { get; } public AddressTable<ulong> FunctionTable { get; }
public TranslatorStubs Stubs { get; } public TranslatorStubs Stubs { get; }
public ulong EntryAddress { get; } public ulong EntryAddress { get; }
public bool HighCq { get; } public bool HighCq { get; }
public bool HasPtc { get; }
public Aarch32Mode Mode { get; } public Aarch32Mode Mode { get; }
private int _ifThenBlockStateIndex = 0; private int _ifThenBlockStateIndex = 0;
@ -66,15 +64,16 @@ namespace ARMeilleure.Translation
TranslatorStubs stubs, TranslatorStubs stubs,
ulong entryAddress, ulong entryAddress,
bool highCq, bool highCq,
bool hasPtc,
Aarch32Mode mode) Aarch32Mode mode)
{ {
HasPtc = Ptc.State != PtcState.Disabled;
Memory = memory; Memory = memory;
CountTable = countTable; CountTable = countTable;
FunctionTable = funcTable; FunctionTable = funcTable;
Stubs = stubs; Stubs = stubs;
EntryAddress = entryAddress; EntryAddress = entryAddress;
HighCq = highCq; HighCq = highCq;
HasPtc = hasPtc;
Mode = mode; Mode = mode;
_labels = new Dictionary<ulong, Operand>(); _labels = new Dictionary<ulong, Operand>();

View file

@ -0,0 +1,10 @@
using System;
namespace ARMeilleure.Translation.PTC
{
public interface IPtcLoadState
{
event Action<PtcLoadingState, int, int> PtcStateChanged;
void Continue();
}
}

View file

@ -22,7 +22,7 @@ using static ARMeilleure.Translation.PTC.PtcFormatter;
namespace ARMeilleure.Translation.PTC namespace ARMeilleure.Translation.PTC
{ {
public static class Ptc class Ptc : IPtcLoadState
{ {
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";
@ -35,45 +35,49 @@ namespace ARMeilleure.Translation.PTC
private const string TitleIdTextDefault = "0000000000000000"; private const string TitleIdTextDefault = "0000000000000000";
private const string DisplayVersionDefault = "0"; private const string DisplayVersionDefault = "0";
internal static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1); public static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
internal static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2); public static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
internal static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3); public static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
private const byte FillingByte = 0x00; private const byte FillingByte = 0x00;
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest; private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
public PtcProfiler Profiler { get; }
// Carriers. // Carriers.
private static MemoryStream _infosStream; private MemoryStream _infosStream;
private static List<byte[]> _codesList; private List<byte[]> _codesList;
private static MemoryStream _relocsStream; private MemoryStream _relocsStream;
private static MemoryStream _unwindInfosStream; private MemoryStream _unwindInfosStream;
private static readonly ulong _outerHeaderMagic; private readonly ulong _outerHeaderMagic;
private static readonly ulong _innerHeaderMagic; 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; } public string TitleIdText { get; private set; }
internal static string DisplayVersion { get; private set; } public string DisplayVersion { get; private set; }
private static MemoryManagerMode _memoryMode; private MemoryManagerType _memoryMode;
internal static string CachePathActual { get; private set; } public string CachePathActual { get; private set; }
internal static string CachePathBackup { 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. // Progress reporting helpers.
private static volatile int _translateCount; private volatile int _translateCount;
private static volatile int _translateTotalCount; private volatile int _translateTotalCount;
public static event Action<PtcLoadingState, int, int> PtcStateChanged; public event Action<PtcLoadingState, int, int> PtcStateChanged;
static Ptc() public Ptc()
{ {
Profiler = new PtcProfiler(this);
InitializeCarriers(); InitializeCarriers();
_outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan()); _outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
@ -94,12 +98,12 @@ namespace ARMeilleure.Translation.PTC
Disable(); 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(); Wait();
PtcProfiler.Wait(); Profiler.Wait();
PtcProfiler.ClearEntries(); Profiler.ClearEntries();
Logger.Info?.Print(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache (enabled: {enabled})."); 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); CachePathBackup = Path.Combine(workPathBackup, DisplayVersion);
PreLoad(); PreLoad();
PtcProfiler.PreLoad(); Profiler.PreLoad();
Enable(); Enable();
} }
private static void InitializeCarriers() private void InitializeCarriers()
{ {
_infosStream = new MemoryStream(); _infosStream = new MemoryStream();
_codesList = new List<byte[]>(); _codesList = new List<byte[]>();
@ -150,7 +154,7 @@ namespace ARMeilleure.Translation.PTC
_unwindInfosStream = new MemoryStream(); _unwindInfosStream = new MemoryStream();
} }
private static void DisposeCarriers() private void DisposeCarriers()
{ {
_infosStream.Dispose(); _infosStream.Dispose();
_codesList.Clear(); _codesList.Clear();
@ -158,12 +162,12 @@ namespace ARMeilleure.Translation.PTC
_unwindInfosStream.Dispose(); _unwindInfosStream.Dispose();
} }
private static bool AreCarriersEmpty() private bool AreCarriersEmpty()
{ {
return _infosStream.Length == 0L && _codesList.Count == 0 && _relocsStream.Length == 0L && _unwindInfosStream.Length == 0L; return _infosStream.Length == 0L && _codesList.Count == 0 && _relocsStream.Length == 0L && _unwindInfosStream.Length == 0L;
} }
private static void ResetCarriersIfNeeded() private void ResetCarriersIfNeeded()
{ {
if (AreCarriersEmpty()) if (AreCarriersEmpty())
{ {
@ -175,7 +179,7 @@ namespace ARMeilleure.Translation.PTC
InitializeCarriers(); InitializeCarriers();
} }
private static void PreLoad() private void PreLoad()
{ {
string fileNameActual = string.Concat(CachePathActual, ".cache"); string fileNameActual = string.Concat(CachePathActual, ".cache");
string fileNameBackup = string.Concat(CachePathBackup, ".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 (FileStream compressedStream = new(fileName, FileMode.Open))
using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true)) using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true))
@ -376,12 +380,12 @@ namespace ARMeilleure.Translation.PTC
return true; return true;
} }
private static void InvalidateCompressedStream(FileStream compressedStream) private void InvalidateCompressedStream(FileStream compressedStream)
{ {
compressedStream.SetLength(0L); compressedStream.SetLength(0L);
} }
private static void PreSave() private void PreSave()
{ {
_waitEvent.Reset(); _waitEvent.Reset();
@ -409,7 +413,7 @@ namespace ARMeilleure.Translation.PTC
_waitEvent.Set(); _waitEvent.Set();
} }
private static unsafe void Save(string fileName) private unsafe void Save(string fileName)
{ {
int translatedFuncsCount; int translatedFuncsCount;
@ -517,7 +521,7 @@ namespace ARMeilleure.Translation.PTC
} }
} }
internal static void LoadTranslations(Translator translator) public void LoadTranslations(Translator translator)
{ {
if (AreCarriersEmpty()) if (AreCarriersEmpty())
{ {
@ -550,7 +554,7 @@ namespace ARMeilleure.Translation.PTC
bool isEntryChanged = infoEntry.Hash != ComputeHash(translator.Memory, infoEntry.Address, infoEntry.GuestSize); 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.Stubbed = true;
infoEntry.CodeLength = 0; infoEntry.CodeLength = 0;
@ -601,38 +605,38 @@ namespace ARMeilleure.Translation.PTC
Logger.Info?.Print(LogClass.Ptc, $"{translator.Functions.Count} translated functions loaded"); Logger.Info?.Print(LogClass.Ptc, $"{translator.Functions.Count} translated functions loaded");
} }
private static int GetEntriesCount() private int GetEntriesCount()
{ {
return _codesList.Count; return _codesList.Count;
} }
[Conditional("DEBUG")] [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(_codesList[index].Length == 0);
Debug.Assert(codeLength == 0); Debug.Assert(codeLength == 0);
} }
private static void SkipReloc(int relocEntriesCount) private void SkipReloc(int relocEntriesCount)
{ {
_relocsStream.Seek(relocEntriesCount * RelocEntry.Stride, SeekOrigin.Current); _relocsStream.Seek(relocEntriesCount * RelocEntry.Stride, SeekOrigin.Current);
} }
private static void SkipUnwindInfo(BinaryReader unwindInfosReader) private void SkipUnwindInfo(BinaryReader unwindInfosReader)
{ {
int pushEntriesLength = unwindInfosReader.ReadInt32(); int pushEntriesLength = unwindInfosReader.ReadInt32();
_unwindInfosStream.Seek(pushEntriesLength * UnwindPushEntry.Stride + UnwindInfo.Stride, SeekOrigin.Current); _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); Debug.Assert(_codesList[index].Length == codeLength);
return _codesList[index]; return _codesList[index];
} }
private static RelocEntry[] GetRelocEntries(BinaryReader relocsReader, int relocEntriesCount) private RelocEntry[] GetRelocEntries(BinaryReader relocsReader, int relocEntriesCount)
{ {
RelocEntry[] relocEntries = new RelocEntry[relocEntriesCount]; RelocEntry[] relocEntries = new RelocEntry[relocEntriesCount];
@ -648,7 +652,7 @@ namespace ARMeilleure.Translation.PTC
return relocEntries; 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; 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(); int pushEntriesLength = unwindInfosReader.ReadInt32();
@ -723,7 +727,7 @@ namespace ARMeilleure.Translation.PTC
return new UnwindInfo(pushEntries, prologueSize); return new UnwindInfo(pushEntries, prologueSize);
} }
private static TranslatedFunction FastTranslate( private TranslatedFunction FastTranslate(
byte[] code, byte[] code,
Counter<uint> callCounter, Counter<uint> callCounter,
ulong guestSize, ulong guestSize,
@ -736,19 +740,19 @@ namespace ARMeilleure.Translation.PTC
return new TranslatedFunction(gFunc, callCounter, guestSize, highCq); 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); _infosStream.Seek(-Unsafe.SizeOf<InfoEntry>(), SeekOrigin.Current);
SerializeStructure(_infosStream, infoEntry); SerializeStructure(_infosStream, infoEntry);
} }
private static void StubCode(int index) private void StubCode(int index)
{ {
_codesList[index] = Array.Empty<byte>(); _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++) 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(); 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; _translateCount = 0;
_translateTotalCount = profiledFuncsToTranslate.Count; _translateTotalCount = profiledFuncsToTranslate.Count;
@ -811,7 +815,7 @@ namespace ARMeilleure.Translation.PTC
{ {
ulong address = item.address; 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); TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq);
@ -861,7 +865,7 @@ namespace ARMeilleure.Translation.PTC
preSaveThread.Start(); preSaveThread.Start();
} }
private static void ReportProgress(object state) private void ReportProgress(object state)
{ {
const int refreshRate = 50; // ms. const int refreshRate = 50; // ms.
@ -882,12 +886,12 @@ namespace ARMeilleure.Translation.PTC
while (!endEvent.WaitOne(refreshRate)); 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)))); 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) 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()); _codesList.Add(code.ToArray());
} }
internal static bool GetEndianness() public static bool GetEndianness()
{ {
return BitConverter.IsLittleEndian; return BitConverter.IsLittleEndian;
} }
@ -955,7 +959,7 @@ namespace ARMeilleure.Translation.PTC
(uint)HardwareCapabilities.FeatureInfo7Ecx); (uint)HardwareCapabilities.FeatureInfo7Ecx);
} }
private static byte GetMemoryManagerMode() private byte GetMemoryManagerMode()
{ {
return (byte)_memoryMode; return (byte)_memoryMode;
} }
@ -1050,12 +1054,12 @@ namespace ARMeilleure.Translation.PTC
public int RelocEntriesCount; public int RelocEntriesCount;
} }
private static void Enable() private void Enable()
{ {
State = PtcState.Enabled; State = PtcState.Enabled;
} }
public static void Continue() public void Continue()
{ {
if (State == PtcState.Enabled) if (State == PtcState.Enabled)
{ {
@ -1063,7 +1067,7 @@ namespace ARMeilleure.Translation.PTC
} }
} }
public static void Close() public void Close()
{ {
if (State == PtcState.Enabled || if (State == PtcState.Enabled ||
State == PtcState.Continuing) State == PtcState.Continuing)
@ -1072,17 +1076,17 @@ namespace ARMeilleure.Translation.PTC
} }
} }
internal static void Disable() public void Disable()
{ {
State = PtcState.Disabled; State = PtcState.Disabled;
} }
private static void Wait() private void Wait()
{ {
_waitEvent.WaitOne(); _waitEvent.WaitOne();
} }
public static void Dispose() public void Dispose()
{ {
if (!_disposed) if (!_disposed)
{ {

View file

@ -16,7 +16,7 @@ using static ARMeilleure.Translation.PTC.PtcFormatter;
namespace ARMeilleure.Translation.PTC namespace ARMeilleure.Translation.PTC
{ {
public static class PtcProfiler class PtcProfiler
{ {
private const string OuterHeaderMagicString = "Pohd\0\0\0\0"; private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
@ -26,27 +26,31 @@ namespace ARMeilleure.Translation.PTC
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest; 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 bool Enabled { get; private set; }
public static ulong StaticCodeSize { internal get; 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 = new System.Timers.Timer((double)SaveInterval * 1000d);
_timer.Elapsed += PreSave; _timer.Elapsed += PreSave;
@ -63,7 +67,7 @@ namespace ARMeilleure.Translation.PTC
Enabled = false; Enabled = false;
} }
internal static void AddEntry(ulong address, ExecutionMode mode, bool highCq) public void AddEntry(ulong address, ExecutionMode mode, bool highCq)
{ {
if (IsAddressInStaticCodeRange(address)) 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)) 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; 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)>(); var profiledFuncsToTranslate = new ConcurrentQueue<(ulong address, FuncProfile funcProfile)>();
@ -111,18 +115,18 @@ namespace ARMeilleure.Translation.PTC
return profiledFuncsToTranslate; return profiledFuncsToTranslate;
} }
internal static void ClearEntries() public void ClearEntries()
{ {
ProfiledFuncs.Clear(); ProfiledFuncs.Clear();
ProfiledFuncs.TrimExcess(); ProfiledFuncs.TrimExcess();
} }
internal static void PreLoad() public void PreLoad()
{ {
_lastHash = default; _lastHash = default;
string fileNameActual = string.Concat(Ptc.CachePathActual, ".info"); string fileNameActual = string.Concat(_ptc.CachePathActual, ".info");
string fileNameBackup = string.Concat(Ptc.CachePathBackup, ".info"); string fileNameBackup = string.Concat(_ptc.CachePathBackup, ".info");
FileInfo fileInfoActual = new FileInfo(fileNameActual); FileInfo fileInfoActual = new FileInfo(fileNameActual);
FileInfo fileInfoBackup = new FileInfo(fileNameBackup); 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 (FileStream compressedStream = new(fileName, FileMode.Open))
using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true)) 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)); 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); 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); compressedStream.SetLength(0L);
} }
private static void PreSave(object source, System.Timers.ElapsedEventArgs e) private void PreSave(object source, System.Timers.ElapsedEventArgs e)
{ {
_waitEvent.Reset(); _waitEvent.Reset();
string fileNameActual = string.Concat(Ptc.CachePathActual, ".info"); string fileNameActual = string.Concat(_ptc.CachePathActual, ".info");
string fileNameBackup = string.Concat(Ptc.CachePathBackup, ".info"); string fileNameBackup = string.Concat(_ptc.CachePathBackup, ".info");
FileInfo fileInfoActual = new FileInfo(fileNameActual); FileInfo fileInfoActual = new FileInfo(fileNameActual);
@ -257,7 +261,7 @@ namespace ARMeilleure.Translation.PTC
_waitEvent.Set(); _waitEvent.Set();
} }
private static void Save(string fileName) private void Save(string fileName)
{ {
int profiledFuncsCount; 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)); SerializeDictionary(stream, profiledFuncs, (stream, structure) => SerializeStructure(stream, structure));
} }
@ -361,7 +365,7 @@ namespace ARMeilleure.Translation.PTC
} }
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 5*/)] [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 5*/)]
internal struct FuncProfile public struct FuncProfile
{ {
public ExecutionMode Mode; public ExecutionMode Mode;
public bool HighCq; public bool HighCq;
@ -373,10 +377,10 @@ namespace ARMeilleure.Translation.PTC
} }
} }
internal static void Start() public void Start()
{ {
if (Ptc.State == PtcState.Enabled || if (_ptc.State == PtcState.Enabled ||
Ptc.State == PtcState.Continuing) _ptc.State == PtcState.Continuing)
{ {
Enabled = true; Enabled = true;
@ -384,7 +388,7 @@ namespace ARMeilleure.Translation.PTC
} }
} }
public static void Stop() public void Stop()
{ {
Enabled = false; Enabled = false;
@ -394,12 +398,12 @@ namespace ARMeilleure.Translation.PTC
} }
} }
internal static void Wait() public void Wait()
{ {
_waitEvent.WaitOne(); _waitEvent.WaitOne();
} }
public static void Dispose() public void Dispose()
{ {
if (!_disposed) if (!_disposed)
{ {

View file

@ -44,6 +44,8 @@ namespace ARMeilleure.Translation
private readonly IJitMemoryAllocator _allocator; private readonly IJitMemoryAllocator _allocator;
private readonly ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>> _oldFuncs; private readonly ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>> _oldFuncs;
private readonly Ptc _ptc;
internal TranslatorCache<TranslatedFunction> Functions { get; } internal TranslatorCache<TranslatedFunction> Functions { get; }
internal AddressTable<ulong> FunctionTable { get; } internal AddressTable<ulong> FunctionTable { get; }
internal EntryTable<uint> CountTable { get; } internal EntryTable<uint> CountTable { get; }
@ -63,6 +65,8 @@ namespace ARMeilleure.Translation
_oldFuncs = new ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>>(); _oldFuncs = new ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>>();
_ptc = new Ptc();
Queue = new TranslatorQueue(); Queue = new TranslatorQueue();
JitCache.Initialize(allocator); 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) public void Execute(State.ExecutionContext context, ulong address)
{ {
if (Interlocked.Increment(ref _threadCount) == 1) if (Interlocked.Increment(ref _threadCount) == 1)
{ {
IsReadyForTranslation.WaitOne(); IsReadyForTranslation.WaitOne();
if (Ptc.State == PtcState.Enabled) if (_ptc.State == PtcState.Enabled)
{ {
Debug.Assert(Functions.Count == 0); Debug.Assert(Functions.Count == 0);
Ptc.LoadTranslations(this); _ptc.LoadTranslations(this);
Ptc.MakeAndSaveTranslations(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 // 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 // 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(); Stubs.Dispose();
FunctionTable.Dispose(); FunctionTable.Dispose();
CountTable.Dispose(); CountTable.Dispose();
_ptc.Close();
_ptc.Profiler.Stop();
_ptc.Dispose();
_ptc.Profiler.Dispose();
} }
} }
@ -189,9 +214,9 @@ namespace ARMeilleure.Translation
func = oldFunc; 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); RegisterFunction(address, func);
@ -217,6 +242,7 @@ namespace ARMeilleure.Translation
Stubs, Stubs,
address, address,
highCq, highCq,
_ptc.State != PtcState.Disabled,
mode: Aarch32Mode.User); mode: Aarch32Mode.User);
Logger.StartPass(PassName.Decoding); Logger.StartPass(PassName.Decoding);
@ -262,7 +288,7 @@ namespace ARMeilleure.Translation
{ {
Hash128 hash = Ptc.ComputeHash(Memory, address, funcSize); 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>(); GuestFunction func = compiledFunc.Map<GuestFunction>();
@ -284,9 +310,9 @@ namespace ARMeilleure.Translation
return func; 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); RegisterFunction(request.Address, func);

View file

@ -1,5 +1,4 @@
using ARMeilleure.Translation; using ARMeilleure.Translation;
using ARMeilleure.Translation.PTC;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Threading; using Avalonia.Threading;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
@ -280,7 +279,7 @@ namespace Ryujinx.Ava
_parent.Title = $"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}"; _parent.Title = $"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
}); });
_parent.ViewModel.HandleShaderProgress(Device); _parent.ViewModel.SetUiProgressHandlers(Device);
Renderer.SizeChanged += Window_SizeChanged; Renderer.SizeChanged += Window_SizeChanged;
@ -357,8 +356,6 @@ namespace Ryujinx.Ava
DisplaySleep.Restore(); DisplaySleep.Restore();
Ptc.Close();
PtcProfiler.Stop();
NpadManager.Dispose(); NpadManager.Dispose();
TouchScreenManager.Dispose(); TouchScreenManager.Dispose();
Device.Dispose(); Device.Dispose();
@ -949,7 +946,7 @@ namespace Ryujinx.Ava
if (_keyboardInterface.GetKeyboardStateSnapshot().IsPressed(Key.Delete) && _parent.WindowState != WindowState.FullScreen) if (_keyboardInterface.GetKeyboardStateSnapshot().IsPressed(Key.Delete) && _parent.WindowState != WindowState.FullScreen)
{ {
Ptc.Continue(); Device.Application.DiskCacheLoadState?.Cancel();
} }
}); });
} }

View file

@ -1,4 +1,3 @@
using ARMeilleure.Translation.PTC;
using Avalonia; using Avalonia;
using Avalonia.Threading; using Avalonia.Threading;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
@ -197,9 +196,6 @@ namespace Ryujinx.Ava
private static void ProcessUnhandledException(Exception ex, bool isTerminating) private static void ProcessUnhandledException(Exception ex, bool isTerminating)
{ {
Ptc.Close();
PtcProfiler.Stop();
string message = $"Unhandled exception caught: {ex}"; string message = $"Unhandled exception caught: {ex}";
Logger.Error?.PrintMsg(LogClass.Application, message); Logger.Error?.PrintMsg(LogClass.Application, message);
@ -219,9 +215,6 @@ namespace Ryujinx.Ava
{ {
DiscordIntegrationModule.Exit(); DiscordIntegrationModule.Exit();
Ptc.Dispose();
PtcProfiler.Dispose();
Logger.Shutdown(); Logger.Shutdown();
} }
} }

View file

@ -1,4 +1,3 @@
using ARMeilleure.Translation.PTC;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
@ -18,6 +17,7 @@ using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE; using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
@ -107,9 +107,6 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated; ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated;
ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded; ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded;
Ptc.PtcStateChanged -= ProgressHandler;
Ptc.PtcStateChanged += ProgressHandler;
} }
public string SearchText public string SearchText
@ -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;
emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler; emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler;
} }
@ -1033,16 +1036,16 @@ namespace Ryujinx.Ava.UI.ViewModels
switch (state) switch (state)
{ {
case PtcLoadingState ptcState: case LoadState ptcState:
CacheLoadStatus = $"{current} / {total}"; CacheLoadStatus = $"{current} / {total}";
switch (ptcState) switch (ptcState)
{ {
case PtcLoadingState.Start: case LoadState.Unloaded:
case PtcLoadingState.Loading: case LoadState.Loading:
LoadHeading = LocaleManager.Instance[LocaleKeys.CompilingPPTC]; LoadHeading = LocaleManager.Instance[LocaleKeys.CompilingPPTC];
IsLoadingIndeterminate = false; IsLoadingIndeterminate = false;
break; break;
case PtcLoadingState.Loaded: case LoadState.Loaded:
LoadHeading = string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], TitleName); LoadHeading = string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], TitleName);
IsLoadingIndeterminate = true; IsLoadingIndeterminate = true;
CacheLoadStatus = ""; CacheLoadStatus = "";

View file

@ -35,5 +35,27 @@ namespace Ryujinx.Cpu
/// <param name="address">Address of the region to be invalidated</param> /// <param name="address">Address of the region to be invalidated</param>
/// <param name="size">Size of the region to be invalidated</param> /// <param name="size">Size of the region to be invalidated</param>
void InvalidateCacheRegion(ulong address, ulong size); 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);
} }
} }

View file

@ -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();
}
}

View file

@ -37,5 +37,17 @@ namespace Ryujinx.Cpu.Jit
{ {
_translator.InvalidateJitCacheRegion(address, size); _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);
}
} }
} }

View file

@ -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();
}
}
}

12
Ryujinx.Cpu/LoadState.cs Normal file
View file

@ -0,0 +1,12 @@
namespace Ryujinx.Cpu
{
/// <summary>
/// Load state.
/// </summary>
public enum LoadState
{
Unloaded,
Loading,
Loaded
}
}

View file

@ -1,4 +1,3 @@
using ARMeilleure.Translation.PTC;
using LibHac; using LibHac;
using LibHac.Account; using LibHac.Account;
using LibHac.Common; using LibHac.Common;
@ -14,8 +13,8 @@ using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.Memory; using Ryujinx.Memory;
using System; using System;
@ -67,6 +66,8 @@ namespace Ryujinx.HLE.HOS
public string TitleIdText => TitleId.ToString("x16"); public string TitleIdText => TitleId.ToString("x16");
public IDiskCacheLoadState DiskCacheLoadState { get; private set; }
public ApplicationLoader(Switch device) public ApplicationLoader(Switch device)
{ {
_device = device; _device = device;
@ -94,7 +95,7 @@ namespace Ryujinx.HLE.HOS
EnsureSaveData(new ApplicationId(TitleId)); 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) 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) 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); FileStream file = new FileStream(ncaFile, FileMode.Open, FileAccess.Read);
Nca mainNca = new Nca(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false)); 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. // Collect the nsos, ignoring ones that aren't used.
NsoExecutable[] programs = nsos.Where(x => x != null).ToArray(); NsoExecutable[] programs = nsos.Where(x => x != null).ToArray();
MemoryManagerMode memoryManagerMode = _device.Configuration.MemoryManagerMode; string displayVersion = _device.System.ContentManager.GetCurrentFirmwareVersion().VersionString;
bool usePtc = _device.System.EnablePtc;
if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))
{
memoryManagerMode = MemoryManagerMode.SoftwarePageTable;
}
metaData.GetNpdm(out Npdm npdm).ThrowIfFailure(); metaData.GetNpdm(out Npdm npdm).ThrowIfFailure();
ProgramInfo programInfo = new ProgramInfo(in npdm, allowCodeMemoryForJit: false); ProgramInfo programInfo = new ProgramInfo(in npdm, displayVersion, usePtc, allowCodeMemoryForJit: false);
ProgramLoader.LoadNsos(_device.System.KernelContext, out _, metaData, programInfo, executables: programs); ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: programs);
string titleIdText = npdm.Aci.Value.ProgramId.Value.ToString("x16"); string titleIdText = npdm.Aci.Value.ProgramId.Value.ToString("x16");
bool titleIs64Bit = (npdm.Meta.Value.Flags & 1) != 0; 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.GetModsBasePath(),
_device.Configuration.VirtualFileSystem.ModLoader.GetSdModsBasePath()); _device.Configuration.VirtualFileSystem.ModLoader.GetSdModsBasePath());
string displayVersion = string.Empty;
if (controlNca != null) if (controlNca != null)
{ {
ReadControlData(_device, controlNca, ref _controlData, ref _titleName, ref _displayVersion); ReadControlData(_device, controlNca, ref _controlData, ref _titleName, ref displayVersion);
} }
else else
{ {
@ -493,9 +486,11 @@ namespace Ryujinx.HLE.HOS
string dummyTitleName = ""; string dummyTitleName = "";
BlitStruct<ApplicationControlProperty> dummyControl = new BlitStruct<ApplicationControlProperty>(1); 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) if (dataStorage == null)
{ {
Logger.Warning?.Print(LogClass.Loader, "No RomFS found in NCA"); Logger.Warning?.Print(LogClass.Loader, "No RomFS found in NCA");
@ -515,7 +510,7 @@ namespace Ryujinx.HLE.HOS
EnsureSaveData(new ApplicationId(TitleId & ~0xFul)); 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")}]"); 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)) if (_device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs))
{ {
@ -649,23 +644,23 @@ namespace Ryujinx.HLE.HOS
memoryManagerMode = MemoryManagerMode.SoftwarePageTable; memoryManagerMode = MemoryManagerMode.SoftwarePageTable;
} }
Ptc.Initialize(TitleIdText, DisplayVersion, usePtc, memoryManagerMode);
// We allow it for nx-hbloader because it can be used to launch homebrew. // We allow it for nx-hbloader because it can be used to launch homebrew.
bool allowCodeMemoryForJit = TitleId == 0x010000000000100DUL || isHomebrew; bool allowCodeMemoryForJit = TitleId == 0x010000000000100DUL || isHomebrew;
metaData.GetNpdm(out Npdm npdm).ThrowIfFailure(); metaData.GetNpdm(out Npdm npdm).ThrowIfFailure();
ProgramInfo programInfo = new ProgramInfo(in npdm, allowCodeMemoryForJit); ProgramInfo programInfo = new ProgramInfo(in npdm, displayVersion, usePtc, allowCodeMemoryForJit);
ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, programInfo, executables: programs); ProgramLoadResult result = ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: programs);
_device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine); DiskCacheLoadState = result.DiskCacheLoadState;
_device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine);
} }
public void LoadProgram(string filePath) public void LoadProgram(string filePath)
{ {
MetaLoader metaData = GetDefaultNpdm(); MetaLoader metaData = GetDefaultNpdm();
metaData.GetNpdm(out Npdm npdm).ThrowIfFailure(); 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"; bool isNro = Path.GetExtension(filePath).ToLower() == ".nro";
@ -761,9 +756,11 @@ namespace Ryujinx.HLE.HOS
Graphics.Gpu.GraphicsConfig.TitleId = null; Graphics.Gpu.GraphicsConfig.TitleId = null;
_device.Gpu.HostInitalized.Set(); _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);
_device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine); DiskCacheLoadState = result.DiskCacheLoadState;
_device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine);
} }
private MetaLoader GetDefaultNpdm() private MetaLoader GetDefaultNpdm()

View file

@ -6,7 +6,17 @@ using Ryujinx.Memory;
namespace Ryujinx.HLE.HOS 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 ulong _pid;
private readonly GpuContext _gpuContext; private readonly GpuContext _gpuContext;
@ -40,6 +50,17 @@ namespace Ryujinx.HLE.HOS
_cpuContext.Execute(context, codeAddress); _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) public void InvalidateCacheRegion(ulong address, ulong size)
{ {
_cpuContext.InvalidateCacheRegion(address, size); _cpuContext.InvalidateCacheRegion(address, size);

View file

@ -13,11 +13,30 @@ namespace Ryujinx.HLE.HOS
{ {
private readonly ICpuEngine _cpuEngine; private readonly ICpuEngine _cpuEngine;
private readonly GpuContext _gpu; 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; _cpuEngine = cpuEngine;
_gpu = gpu; _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) public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit)
@ -29,21 +48,29 @@ namespace Ryujinx.HLE.HOS
mode = MemoryManagerMode.SoftwarePageTable; mode = MemoryManagerMode.SoftwarePageTable;
} }
IArmProcessContext processContext;
switch (mode) switch (mode)
{ {
case MemoryManagerMode.SoftwarePageTable: case MemoryManagerMode.SoftwarePageTable:
var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler); 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.HostMapped:
case MemoryManagerMode.HostMappedUnsafe: case MemoryManagerMode.HostMappedUnsafe:
bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe; bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe;
var memoryManagerHostMapped = new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler); 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: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
DiskCacheLoadState = processContext.Initialize(_titleIdText, _displayVersion, _diskCacheEnabled, _codeAddress, _codeSize);
return processContext;
} }
} }
} }

View file

@ -1,9 +1,9 @@
using ARMeilleure.Translation.PTC;
using LibHac.Loader; using LibHac.Loader;
using LibHac.Ncm; using LibHac.Ncm;
using LibHac.Util; using LibHac.Util;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Memory;
@ -21,16 +21,40 @@ namespace Ryujinx.HLE.HOS
{ {
public string Name; public string Name;
public ulong ProgramId; 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); 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; 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 static class ProgramLoader
{ {
private const bool AslrEnabled = true; private const bool AslrEnabled = true;
@ -102,7 +126,14 @@ namespace Ryujinx.HLE.HOS
KProcess process = new KProcess(context); 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( result = process.InitializeKip(
creationInfo, creationInfo,
@ -144,9 +175,8 @@ namespace Ryujinx.HLE.HOS
return true; return true;
} }
public static bool LoadNsos( public static ProgramLoadResult LoadNsos(
KernelContext context, KernelContext context,
out ProcessTamperInfo tamperInfo,
MetaLoader metaData, MetaLoader metaData,
ProgramInfo programInfo, ProgramInfo programInfo,
byte[] arguments = null, byte[] arguments = null,
@ -156,8 +186,7 @@ namespace Ryujinx.HLE.HOS
if (rc.IsFailure()) if (rc.IsFailure())
{ {
tamperInfo = null; return ProgramLoadResult.Failed;
return false;
} }
ref readonly var meta = ref npdm.Meta.Value; 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 codePagesCount = (int)(codeSize / KPageTableBase.PageSize);
int personalMmHeapPagesCount = (int)(meta.SystemResourceSize / 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."); Logger.Error?.Print(LogClass.Loader, $"Process initialization failed setting resource limit values.");
tamperInfo = null; return ProgramLoadResult.Failed;
return false;
} }
KProcess process = new KProcess(context, programInfo.AllowCodeMemoryForJit); 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."); Logger.Error?.Print(LogClass.Loader, $"Process initialization failed due to invalid ACID flags.");
tamperInfo = null; return ProgramLoadResult.Failed;
return false;
} }
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( result = process.Initialize(
creationInfo, creationInfo,
@ -294,9 +323,7 @@ namespace Ryujinx.HLE.HOS
{ {
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\"."); Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
tamperInfo = null; return ProgramLoadResult.Failed;
return false;
} }
for (int index = 0; index < executables.Length; index++) 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}\"."); Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
tamperInfo = null; return ProgramLoadResult.Failed;
return false;
} }
} }
@ -323,9 +348,7 @@ namespace Ryujinx.HLE.HOS
{ {
Logger.Error?.Print(LogClass.Loader, $"Process start returned error \"{result}\"."); Logger.Error?.Print(LogClass.Loader, $"Process start returned error \"{result}\".");
tamperInfo = null; return ProgramLoadResult.Failed;
return false;
} }
context.Processes.TryAdd(process.Pid, process); 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 // 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 // tamper to and also keep the starting address of each executable inside a process because some
// memory modifications are relative to this address. // memory modifications are relative to this address.
tamperInfo = new ProcessTamperInfo(process, buildIds, nsoBase, process.MemoryManager.HeapRegionStart, ProcessTamperInfo tamperInfo = new ProcessTamperInfo(
process.MemoryManager.AliasRegionStart, process.MemoryManager.CodeRegionStart); process,
buildIds,
nsoBase,
process.MemoryManager.HeapRegionStart,
process.MemoryManager.AliasRegionStart,
process.MemoryManager.CodeRegionStart);
return true; return new ProgramLoadResult(true, tamperInfo, processContextFactory.DiskCacheLoadState);
} }
private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress) private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)

View file

@ -1,5 +1,4 @@
using ARMeilleure.Translation; using ARMeilleure.Translation;
using ARMeilleure.Translation.PTC;
using CommandLine; using CommandLine;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.SDL2; using Ryujinx.Audio.Backends.SDL2;
@ -12,6 +11,7 @@ using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.SystemInterop; using Ryujinx.Common.SystemInterop;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using Ryujinx.Cpu;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading; using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.Gpu;
@ -447,8 +447,11 @@ namespace Ryujinx.Headless.SDL2
private static void SetupProgressHandler() private static void SetupProgressHandler()
{ {
Ptc.PtcStateChanged -= ProgressHandler; if (_emulationContext.Application.DiskCacheLoadState != null)
Ptc.PtcStateChanged += ProgressHandler; {
_emulationContext.Application.DiskCacheLoadState.StateChanged -= ProgressHandler;
_emulationContext.Application.DiskCacheLoadState.StateChanged += ProgressHandler;
}
_emulationContext.Gpu.ShaderCacheStateChanged -= ProgressHandler; _emulationContext.Gpu.ShaderCacheStateChanged -= ProgressHandler;
_emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler; _emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler;
@ -460,7 +463,7 @@ namespace Ryujinx.Headless.SDL2
switch (state) switch (state)
{ {
case PtcLoadingState ptcState: case LoadState ptcState:
label = $"PTC : {current}/{total}"; label = $"PTC : {current}/{total}";
break; break;
case ShaderCacheState shaderCacheState: case ShaderCacheState shaderCacheState:
@ -563,9 +566,6 @@ namespace Ryujinx.Headless.SDL2
_window.Execute(); _window.Execute();
Ptc.Close();
PtcProfiler.Stop();
_emulationContext.Dispose(); _emulationContext.Dispose();
_window.Dispose(); _window.Dispose();

View file

@ -1,4 +1,3 @@
using ARMeilleure.Translation.PTC;
using Gtk; using Gtk;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
@ -308,9 +307,6 @@ namespace Ryujinx
private static void ProcessUnhandledException(Exception ex, bool isTerminating) private static void ProcessUnhandledException(Exception ex, bool isTerminating)
{ {
Ptc.Close();
PtcProfiler.Stop();
string message = $"Unhandled exception caught: {ex}"; string message = $"Unhandled exception caught: {ex}";
Logger.Error?.PrintMsg(LogClass.Application, message); Logger.Error?.PrintMsg(LogClass.Application, message);
@ -330,9 +326,6 @@ namespace Ryujinx
{ {
DiscordIntegrationModule.Exit(); DiscordIntegrationModule.Exit();
Ptc.Dispose();
PtcProfiler.Dispose();
Logger.Shutdown(); Logger.Shutdown();
} }
} }

View file

@ -1,5 +1,4 @@
using ARMeilleure.Translation; using ARMeilleure.Translation;
using ARMeilleure.Translation.PTC;
using Gtk; using Gtk;
using LibHac.Common; using LibHac.Common;
using LibHac.Common.Keys; using LibHac.Common.Keys;
@ -16,6 +15,7 @@ using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.SystemInterop; using Ryujinx.Common.SystemInterop;
using Ryujinx.Cpu;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading; using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.OpenGL; using Ryujinx.Graphics.OpenGL;
@ -46,7 +46,6 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using GUI = Gtk.Builder.ObjectAttribute; using GUI = Gtk.Builder.ObjectAttribute;
using PtcLoadingState = ARMeilleure.Translation.PTC.PtcLoadingState;
using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState; using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
namespace Ryujinx.Ui namespace Ryujinx.Ui
@ -588,8 +587,11 @@ namespace Ryujinx.Ui
private void SetupProgressUiHandlers() private void SetupProgressUiHandlers()
{ {
Ptc.PtcStateChanged -= ProgressHandler; if (_emulationContext.Application.DiskCacheLoadState != null)
Ptc.PtcStateChanged += ProgressHandler; {
_emulationContext.Application.DiskCacheLoadState.StateChanged -= ProgressHandler;
_emulationContext.Application.DiskCacheLoadState.StateChanged += ProgressHandler;
}
_emulationContext.Gpu.ShaderCacheStateChanged -= ProgressHandler; _emulationContext.Gpu.ShaderCacheStateChanged -= ProgressHandler;
_emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler; _emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler;
@ -602,8 +604,8 @@ namespace Ryujinx.Ui
switch (state) switch (state)
{ {
case PtcLoadingState ptcState: case LoadState ptcState:
visible = ptcState != PtcLoadingState.Loaded; visible = ptcState != LoadState.Loaded;
label = $"PTC : {current}/{total}"; label = $"PTC : {current}/{total}";
break; break;
case ShaderCacheLoadingState shaderCacheState: case ShaderCacheLoadingState shaderCacheState:
@ -705,8 +707,6 @@ namespace Ryujinx.Ui
UpdateGraphicsConfig(); UpdateGraphicsConfig();
SetupProgressUiHandlers();
SystemVersion firmwareVersion = _contentManager.GetCurrentFirmwareVersion(); SystemVersion firmwareVersion = _contentManager.GetCurrentFirmwareVersion();
bool isDirectory = Directory.Exists(path); bool isDirectory = Directory.Exists(path);
@ -841,6 +841,8 @@ namespace Ryujinx.Ui
return; return;
} }
SetupProgressUiHandlers();
_currentEmulatedGamePath = path; _currentEmulatedGamePath = path;
_deviceExitStatus.Reset(); _deviceExitStatus.Reset();
@ -967,9 +969,6 @@ namespace Ryujinx.Ui
RendererWidget.Start(); RendererWidget.Start();
Ptc.Close();
PtcProfiler.Stop();
_emulationContext.Dispose(); _emulationContext.Dispose();
_deviceExitStatus.Set(); _deviceExitStatus.Set();

View file

@ -1,5 +1,4 @@
using ARMeilleure.Translation; using ARMeilleure.Translation;
using ARMeilleure.Translation.PTC;
using Gdk; using Gdk;
using Gtk; using Gtk;
using Ryujinx.Common; using Ryujinx.Common;
@ -585,7 +584,7 @@ namespace Ryujinx.Ui
{ {
if (!ParentWindow.State.HasFlag(WindowState.Fullscreen)) if (!ParentWindow.State.HasFlag(WindowState.Fullscreen))
{ {
Ptc.Continue(); Device.Application.DiskCacheLoadState?.Cancel();
} }
} }
}); });