forked from Mirror/Ryujinx
Make PPTC state non-static (#4157)
* Make PPTC state non-static * DiskCacheLoadState can be null
This commit is contained in:
parent
08831eecf7
commit
fc4b7cba2c
21 changed files with 434 additions and 230 deletions
|
@ -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>();
|
||||||
|
|
10
ARMeilleure/Translation/PTC/IPtcLoadState.cs
Normal file
10
ARMeilleure/Translation/PTC/IPtcLoadState.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Translation.PTC
|
||||||
|
{
|
||||||
|
public interface IPtcLoadState
|
||||||
|
{
|
||||||
|
event Action<PtcLoadingState, int, int> PtcStateChanged;
|
||||||
|
void Continue();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
@ -436,7 +433,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ShowMenuAndStatusBar
|
public bool ShowMenuAndStatusBar
|
||||||
{
|
{
|
||||||
get => _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;
|
||||||
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 = "";
|
||||||
|
@ -1166,7 +1169,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "1"));
|
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?).
|
// 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),
|
string.Format(LocaleManager.Instance[LocaleKeys.DialogPPTCDeletionMessage], selection.TitleName),
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
20
Ryujinx.Cpu/IDiskCacheState.cs
Normal file
20
Ryujinx.Cpu/IDiskCacheState.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
38
Ryujinx.Cpu/Jit/JitDiskCacheLoadState.cs
Normal file
38
Ryujinx.Cpu/Jit/JitDiskCacheLoadState.cs
Normal 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
12
Ryujinx.Cpu/LoadState.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
namespace Ryujinx.Cpu
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Load state.
|
||||||
|
/// </summary>
|
||||||
|
public enum LoadState
|
||||||
|
{
|
||||||
|
Unloaded,
|
||||||
|
Loading,
|
||||||
|
Loaded
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -519,7 +518,7 @@ namespace Ryujinx.Ui
|
||||||
_gpuCancellationTokenSource.Cancel();
|
_gpuCancellationTokenSource.Cancel();
|
||||||
|
|
||||||
_isStopped = true;
|
_isStopped = true;
|
||||||
|
|
||||||
if (_isActive)
|
if (_isActive)
|
||||||
{
|
{
|
||||||
_isActive = false;
|
_isActive = false;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue