Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
81fae0d1a6 | ||
|
38519f3b9a | ||
|
7f27aabbd0 | ||
|
e876c43ce9 | ||
|
8639245533 | ||
|
d6b86a6629 | ||
|
8f2b7b5b8e | ||
|
fc4b7cba2c |
@@ -6,7 +6,6 @@ using ARMeilleure.Instructions;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation.PTC;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
@@ -44,14 +43,13 @@ namespace ARMeilleure.Translation
|
||||
|
||||
public IMemoryManager Memory { get; }
|
||||
|
||||
public bool HasPtc { get; }
|
||||
|
||||
public EntryTable<uint> CountTable { get; }
|
||||
public AddressTable<ulong> FunctionTable { get; }
|
||||
public TranslatorStubs Stubs { get; }
|
||||
|
||||
public ulong EntryAddress { get; }
|
||||
public bool HighCq { get; }
|
||||
public bool HasPtc { get; }
|
||||
public Aarch32Mode Mode { get; }
|
||||
|
||||
private int _ifThenBlockStateIndex = 0;
|
||||
@@ -66,15 +64,16 @@ namespace ARMeilleure.Translation
|
||||
TranslatorStubs stubs,
|
||||
ulong entryAddress,
|
||||
bool highCq,
|
||||
bool hasPtc,
|
||||
Aarch32Mode mode)
|
||||
{
|
||||
HasPtc = Ptc.State != PtcState.Disabled;
|
||||
Memory = memory;
|
||||
CountTable = countTable;
|
||||
FunctionTable = funcTable;
|
||||
Stubs = stubs;
|
||||
EntryAddress = entryAddress;
|
||||
HighCq = highCq;
|
||||
HasPtc = hasPtc;
|
||||
Mode = mode;
|
||||
|
||||
_labels = new Dictionary<ulong, Operand>();
|
||||
|
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
|
||||
{
|
||||
public static class Ptc
|
||||
class Ptc : IPtcLoadState
|
||||
{
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
@@ -35,45 +35,49 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string TitleIdTextDefault = "0000000000000000";
|
||||
private const string DisplayVersionDefault = "0";
|
||||
|
||||
internal static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
|
||||
internal static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
|
||||
internal static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
|
||||
public static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
|
||||
public static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
|
||||
public static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
|
||||
|
||||
private const byte FillingByte = 0x00;
|
||||
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
|
||||
|
||||
public PtcProfiler Profiler { get; }
|
||||
|
||||
// Carriers.
|
||||
private static MemoryStream _infosStream;
|
||||
private static List<byte[]> _codesList;
|
||||
private static MemoryStream _relocsStream;
|
||||
private static MemoryStream _unwindInfosStream;
|
||||
private MemoryStream _infosStream;
|
||||
private List<byte[]> _codesList;
|
||||
private MemoryStream _relocsStream;
|
||||
private MemoryStream _unwindInfosStream;
|
||||
|
||||
private static readonly ulong _outerHeaderMagic;
|
||||
private static readonly ulong _innerHeaderMagic;
|
||||
private readonly ulong _outerHeaderMagic;
|
||||
private readonly ulong _innerHeaderMagic;
|
||||
|
||||
private static readonly ManualResetEvent _waitEvent;
|
||||
private readonly ManualResetEvent _waitEvent;
|
||||
|
||||
private static readonly object _lock;
|
||||
private readonly object _lock;
|
||||
|
||||
private static bool _disposed;
|
||||
private bool _disposed;
|
||||
|
||||
internal static string TitleIdText { get; private set; }
|
||||
internal static string DisplayVersion { get; private set; }
|
||||
public string TitleIdText { get; private set; }
|
||||
public string DisplayVersion { get; private set; }
|
||||
|
||||
private static MemoryManagerMode _memoryMode;
|
||||
private MemoryManagerType _memoryMode;
|
||||
|
||||
internal static string CachePathActual { get; private set; }
|
||||
internal static string CachePathBackup { get; private set; }
|
||||
public string CachePathActual { get; private set; }
|
||||
public string CachePathBackup { get; private set; }
|
||||
|
||||
internal static PtcState State { get; private set; }
|
||||
public PtcState State { get; private set; }
|
||||
|
||||
// Progress reporting helpers.
|
||||
private static volatile int _translateCount;
|
||||
private static volatile int _translateTotalCount;
|
||||
public static event Action<PtcLoadingState, int, int> PtcStateChanged;
|
||||
private volatile int _translateCount;
|
||||
private volatile int _translateTotalCount;
|
||||
public event Action<PtcLoadingState, int, int> PtcStateChanged;
|
||||
|
||||
static Ptc()
|
||||
public Ptc()
|
||||
{
|
||||
Profiler = new PtcProfiler(this);
|
||||
|
||||
InitializeCarriers();
|
||||
|
||||
_outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
|
||||
@@ -94,12 +98,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
Disable();
|
||||
}
|
||||
|
||||
public static void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerMode memoryMode)
|
||||
public void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerType memoryMode)
|
||||
{
|
||||
Wait();
|
||||
|
||||
PtcProfiler.Wait();
|
||||
PtcProfiler.ClearEntries();
|
||||
Profiler.Wait();
|
||||
Profiler.ClearEntries();
|
||||
|
||||
Logger.Info?.Print(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache (enabled: {enabled}).");
|
||||
|
||||
@@ -137,12 +141,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
CachePathBackup = Path.Combine(workPathBackup, DisplayVersion);
|
||||
|
||||
PreLoad();
|
||||
PtcProfiler.PreLoad();
|
||||
Profiler.PreLoad();
|
||||
|
||||
Enable();
|
||||
}
|
||||
|
||||
private static void InitializeCarriers()
|
||||
private void InitializeCarriers()
|
||||
{
|
||||
_infosStream = new MemoryStream();
|
||||
_codesList = new List<byte[]>();
|
||||
@@ -150,7 +154,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
_unwindInfosStream = new MemoryStream();
|
||||
}
|
||||
|
||||
private static void DisposeCarriers()
|
||||
private void DisposeCarriers()
|
||||
{
|
||||
_infosStream.Dispose();
|
||||
_codesList.Clear();
|
||||
@@ -158,12 +162,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
_unwindInfosStream.Dispose();
|
||||
}
|
||||
|
||||
private static bool AreCarriersEmpty()
|
||||
private bool AreCarriersEmpty()
|
||||
{
|
||||
return _infosStream.Length == 0L && _codesList.Count == 0 && _relocsStream.Length == 0L && _unwindInfosStream.Length == 0L;
|
||||
}
|
||||
|
||||
private static void ResetCarriersIfNeeded()
|
||||
private void ResetCarriersIfNeeded()
|
||||
{
|
||||
if (AreCarriersEmpty())
|
||||
{
|
||||
@@ -175,7 +179,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
InitializeCarriers();
|
||||
}
|
||||
|
||||
private static void PreLoad()
|
||||
private void PreLoad()
|
||||
{
|
||||
string fileNameActual = string.Concat(CachePathActual, ".cache");
|
||||
string fileNameBackup = string.Concat(CachePathBackup, ".cache");
|
||||
@@ -199,7 +203,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe bool Load(string fileName, bool isBackup)
|
||||
private unsafe bool Load(string fileName, bool isBackup)
|
||||
{
|
||||
using (FileStream compressedStream = new(fileName, FileMode.Open))
|
||||
using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true))
|
||||
@@ -376,12 +380,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void InvalidateCompressedStream(FileStream compressedStream)
|
||||
private void InvalidateCompressedStream(FileStream compressedStream)
|
||||
{
|
||||
compressedStream.SetLength(0L);
|
||||
}
|
||||
|
||||
private static void PreSave()
|
||||
private void PreSave()
|
||||
{
|
||||
_waitEvent.Reset();
|
||||
|
||||
@@ -409,7 +413,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
private static unsafe void Save(string fileName)
|
||||
private unsafe void Save(string fileName)
|
||||
{
|
||||
int translatedFuncsCount;
|
||||
|
||||
@@ -517,7 +521,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static void LoadTranslations(Translator translator)
|
||||
public void LoadTranslations(Translator translator)
|
||||
{
|
||||
if (AreCarriersEmpty())
|
||||
{
|
||||
@@ -550,7 +554,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
bool isEntryChanged = infoEntry.Hash != ComputeHash(translator.Memory, infoEntry.Address, infoEntry.GuestSize);
|
||||
|
||||
if (isEntryChanged || (!infoEntry.HighCq && PtcProfiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) && value.HighCq))
|
||||
if (isEntryChanged || (!infoEntry.HighCq && Profiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) && value.HighCq))
|
||||
{
|
||||
infoEntry.Stubbed = true;
|
||||
infoEntry.CodeLength = 0;
|
||||
@@ -601,38 +605,38 @@ namespace ARMeilleure.Translation.PTC
|
||||
Logger.Info?.Print(LogClass.Ptc, $"{translator.Functions.Count} translated functions loaded");
|
||||
}
|
||||
|
||||
private static int GetEntriesCount()
|
||||
private int GetEntriesCount()
|
||||
{
|
||||
return _codesList.Count;
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private static void SkipCode(int index, int codeLength)
|
||||
private void SkipCode(int index, int codeLength)
|
||||
{
|
||||
Debug.Assert(_codesList[index].Length == 0);
|
||||
Debug.Assert(codeLength == 0);
|
||||
}
|
||||
|
||||
private static void SkipReloc(int relocEntriesCount)
|
||||
private void SkipReloc(int relocEntriesCount)
|
||||
{
|
||||
_relocsStream.Seek(relocEntriesCount * RelocEntry.Stride, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
private static void SkipUnwindInfo(BinaryReader unwindInfosReader)
|
||||
private void SkipUnwindInfo(BinaryReader unwindInfosReader)
|
||||
{
|
||||
int pushEntriesLength = unwindInfosReader.ReadInt32();
|
||||
|
||||
_unwindInfosStream.Seek(pushEntriesLength * UnwindPushEntry.Stride + UnwindInfo.Stride, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
private static byte[] ReadCode(int index, int codeLength)
|
||||
private byte[] ReadCode(int index, int codeLength)
|
||||
{
|
||||
Debug.Assert(_codesList[index].Length == codeLength);
|
||||
|
||||
return _codesList[index];
|
||||
}
|
||||
|
||||
private static RelocEntry[] GetRelocEntries(BinaryReader relocsReader, int relocEntriesCount)
|
||||
private RelocEntry[] GetRelocEntries(BinaryReader relocsReader, int relocEntriesCount)
|
||||
{
|
||||
RelocEntry[] relocEntries = new RelocEntry[relocEntriesCount];
|
||||
|
||||
@@ -648,7 +652,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
return relocEntries;
|
||||
}
|
||||
|
||||
private static void PatchCode(Translator translator, Span<byte> code, RelocEntry[] relocEntries, out Counter<uint> callCounter)
|
||||
private void PatchCode(Translator translator, Span<byte> code, RelocEntry[] relocEntries, out Counter<uint> callCounter)
|
||||
{
|
||||
callCounter = null;
|
||||
|
||||
@@ -702,7 +706,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
private static UnwindInfo ReadUnwindInfo(BinaryReader unwindInfosReader)
|
||||
private UnwindInfo ReadUnwindInfo(BinaryReader unwindInfosReader)
|
||||
{
|
||||
int pushEntriesLength = unwindInfosReader.ReadInt32();
|
||||
|
||||
@@ -723,7 +727,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
return new UnwindInfo(pushEntries, prologueSize);
|
||||
}
|
||||
|
||||
private static TranslatedFunction FastTranslate(
|
||||
private TranslatedFunction FastTranslate(
|
||||
byte[] code,
|
||||
Counter<uint> callCounter,
|
||||
ulong guestSize,
|
||||
@@ -736,19 +740,19 @@ namespace ARMeilleure.Translation.PTC
|
||||
return new TranslatedFunction(gFunc, callCounter, guestSize, highCq);
|
||||
}
|
||||
|
||||
private static void UpdateInfo(InfoEntry infoEntry)
|
||||
private void UpdateInfo(InfoEntry infoEntry)
|
||||
{
|
||||
_infosStream.Seek(-Unsafe.SizeOf<InfoEntry>(), SeekOrigin.Current);
|
||||
|
||||
SerializeStructure(_infosStream, infoEntry);
|
||||
}
|
||||
|
||||
private static void StubCode(int index)
|
||||
private void StubCode(int index)
|
||||
{
|
||||
_codesList[index] = Array.Empty<byte>();
|
||||
}
|
||||
|
||||
private static void StubReloc(int relocEntriesCount)
|
||||
private void StubReloc(int relocEntriesCount)
|
||||
{
|
||||
for (int i = 0; i < relocEntriesCount * RelocEntry.Stride; i++)
|
||||
{
|
||||
@@ -756,7 +760,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
private static void StubUnwindInfo(BinaryReader unwindInfosReader)
|
||||
private void StubUnwindInfo(BinaryReader unwindInfosReader)
|
||||
{
|
||||
int pushEntriesLength = unwindInfosReader.ReadInt32();
|
||||
|
||||
@@ -766,9 +770,9 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MakeAndSaveTranslations(Translator translator)
|
||||
public void MakeAndSaveTranslations(Translator translator)
|
||||
{
|
||||
var profiledFuncsToTranslate = PtcProfiler.GetProfiledFuncsToTranslate(translator.Functions);
|
||||
var profiledFuncsToTranslate = Profiler.GetProfiledFuncsToTranslate(translator.Functions);
|
||||
|
||||
_translateCount = 0;
|
||||
_translateTotalCount = profiledFuncsToTranslate.Count;
|
||||
@@ -811,7 +815,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
ulong address = item.address;
|
||||
|
||||
Debug.Assert(PtcProfiler.IsAddressInStaticCodeRange(address));
|
||||
Debug.Assert(Profiler.IsAddressInStaticCodeRange(address));
|
||||
|
||||
TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq);
|
||||
|
||||
@@ -861,7 +865,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
preSaveThread.Start();
|
||||
}
|
||||
|
||||
private static void ReportProgress(object state)
|
||||
private void ReportProgress(object state)
|
||||
{
|
||||
const int refreshRate = 50; // ms.
|
||||
|
||||
@@ -882,12 +886,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
while (!endEvent.WaitOne(refreshRate));
|
||||
}
|
||||
|
||||
internal static Hash128 ComputeHash(IMemoryManager memory, ulong address, ulong guestSize)
|
||||
public static Hash128 ComputeHash(IMemoryManager memory, ulong address, ulong guestSize)
|
||||
{
|
||||
return XXHash128.ComputeHash(memory.GetSpan(address, checked((int)(guestSize))));
|
||||
}
|
||||
|
||||
internal static void WriteCompiledFunction(ulong address, ulong guestSize, Hash128 hash, bool highCq, CompiledFunction compiledFunc)
|
||||
public void WriteCompiledFunction(ulong address, ulong guestSize, Hash128 hash, bool highCq, CompiledFunction compiledFunc)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
@@ -936,12 +940,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteCode(ReadOnlySpan<byte> code)
|
||||
private void WriteCode(ReadOnlySpan<byte> code)
|
||||
{
|
||||
_codesList.Add(code.ToArray());
|
||||
}
|
||||
|
||||
internal static bool GetEndianness()
|
||||
public static bool GetEndianness()
|
||||
{
|
||||
return BitConverter.IsLittleEndian;
|
||||
}
|
||||
@@ -955,7 +959,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
(uint)HardwareCapabilities.FeatureInfo7Ecx);
|
||||
}
|
||||
|
||||
private static byte GetMemoryManagerMode()
|
||||
private byte GetMemoryManagerMode()
|
||||
{
|
||||
return (byte)_memoryMode;
|
||||
}
|
||||
@@ -1050,12 +1054,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
public int RelocEntriesCount;
|
||||
}
|
||||
|
||||
private static void Enable()
|
||||
private void Enable()
|
||||
{
|
||||
State = PtcState.Enabled;
|
||||
}
|
||||
|
||||
public static void Continue()
|
||||
public void Continue()
|
||||
{
|
||||
if (State == PtcState.Enabled)
|
||||
{
|
||||
@@ -1063,7 +1067,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
public static void Close()
|
||||
public void Close()
|
||||
{
|
||||
if (State == PtcState.Enabled ||
|
||||
State == PtcState.Continuing)
|
||||
@@ -1072,17 +1076,17 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Disable()
|
||||
public void Disable()
|
||||
{
|
||||
State = PtcState.Disabled;
|
||||
}
|
||||
|
||||
private static void Wait()
|
||||
private void Wait()
|
||||
{
|
||||
_waitEvent.WaitOne();
|
||||
}
|
||||
|
||||
public static void Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
|
@@ -16,7 +16,7 @@ using static ARMeilleure.Translation.PTC.PtcFormatter;
|
||||
|
||||
namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
public static class PtcProfiler
|
||||
class PtcProfiler
|
||||
{
|
||||
private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
|
||||
|
||||
@@ -26,27 +26,31 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
|
||||
|
||||
private static readonly System.Timers.Timer _timer;
|
||||
private readonly Ptc _ptc;
|
||||
|
||||
private static readonly ulong _outerHeaderMagic;
|
||||
private readonly System.Timers.Timer _timer;
|
||||
|
||||
private static readonly ManualResetEvent _waitEvent;
|
||||
private readonly ulong _outerHeaderMagic;
|
||||
|
||||
private static readonly object _lock;
|
||||
private readonly ManualResetEvent _waitEvent;
|
||||
|
||||
private static bool _disposed;
|
||||
private readonly object _lock;
|
||||
|
||||
private static Hash128 _lastHash;
|
||||
private bool _disposed;
|
||||
|
||||
internal static Dictionary<ulong, FuncProfile> ProfiledFuncs { get; private set; }
|
||||
private Hash128 _lastHash;
|
||||
|
||||
internal static bool Enabled { get; private set; }
|
||||
public Dictionary<ulong, FuncProfile> ProfiledFuncs { get; private set; }
|
||||
|
||||
public static ulong StaticCodeStart { internal get; set; }
|
||||
public static ulong StaticCodeSize { internal get; set; }
|
||||
public bool Enabled { get; private set; }
|
||||
|
||||
static PtcProfiler()
|
||||
public ulong StaticCodeStart { get; set; }
|
||||
public ulong StaticCodeSize { get; set; }
|
||||
|
||||
public PtcProfiler(Ptc ptc)
|
||||
{
|
||||
_ptc = ptc;
|
||||
|
||||
_timer = new System.Timers.Timer((double)SaveInterval * 1000d);
|
||||
_timer.Elapsed += PreSave;
|
||||
|
||||
@@ -63,7 +67,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
Enabled = false;
|
||||
}
|
||||
|
||||
internal static void AddEntry(ulong address, ExecutionMode mode, bool highCq)
|
||||
public void AddEntry(ulong address, ExecutionMode mode, bool highCq)
|
||||
{
|
||||
if (IsAddressInStaticCodeRange(address))
|
||||
{
|
||||
@@ -76,7 +80,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static void UpdateEntry(ulong address, ExecutionMode mode, bool highCq)
|
||||
public void UpdateEntry(ulong address, ExecutionMode mode, bool highCq)
|
||||
{
|
||||
if (IsAddressInStaticCodeRange(address))
|
||||
{
|
||||
@@ -91,12 +95,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsAddressInStaticCodeRange(ulong address)
|
||||
public bool IsAddressInStaticCodeRange(ulong address)
|
||||
{
|
||||
return address >= StaticCodeStart && address < StaticCodeStart + StaticCodeSize;
|
||||
}
|
||||
|
||||
internal static ConcurrentQueue<(ulong address, FuncProfile funcProfile)> GetProfiledFuncsToTranslate(TranslatorCache<TranslatedFunction> funcs)
|
||||
public ConcurrentQueue<(ulong address, FuncProfile funcProfile)> GetProfiledFuncsToTranslate(TranslatorCache<TranslatedFunction> funcs)
|
||||
{
|
||||
var profiledFuncsToTranslate = new ConcurrentQueue<(ulong address, FuncProfile funcProfile)>();
|
||||
|
||||
@@ -111,18 +115,18 @@ namespace ARMeilleure.Translation.PTC
|
||||
return profiledFuncsToTranslate;
|
||||
}
|
||||
|
||||
internal static void ClearEntries()
|
||||
public void ClearEntries()
|
||||
{
|
||||
ProfiledFuncs.Clear();
|
||||
ProfiledFuncs.TrimExcess();
|
||||
}
|
||||
|
||||
internal static void PreLoad()
|
||||
public void PreLoad()
|
||||
{
|
||||
_lastHash = default;
|
||||
|
||||
string fileNameActual = string.Concat(Ptc.CachePathActual, ".info");
|
||||
string fileNameBackup = string.Concat(Ptc.CachePathBackup, ".info");
|
||||
string fileNameActual = string.Concat(_ptc.CachePathActual, ".info");
|
||||
string fileNameBackup = string.Concat(_ptc.CachePathBackup, ".info");
|
||||
|
||||
FileInfo fileInfoActual = new FileInfo(fileNameActual);
|
||||
FileInfo fileInfoBackup = new FileInfo(fileNameBackup);
|
||||
@@ -143,7 +147,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
private static bool Load(string fileName, bool isBackup)
|
||||
private bool Load(string fileName, bool isBackup)
|
||||
{
|
||||
using (FileStream compressedStream = new(fileName, FileMode.Open))
|
||||
using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true))
|
||||
@@ -228,22 +232,22 @@ namespace ARMeilleure.Translation.PTC
|
||||
return DeserializeDictionary<ulong, FuncProfile>(stream, (stream) => DeserializeStructure<FuncProfile>(stream));
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<byte> GetReadOnlySpan(MemoryStream memoryStream)
|
||||
private ReadOnlySpan<byte> GetReadOnlySpan(MemoryStream memoryStream)
|
||||
{
|
||||
return new(memoryStream.GetBuffer(), (int)memoryStream.Position, (int)memoryStream.Length - (int)memoryStream.Position);
|
||||
}
|
||||
|
||||
private static void InvalidateCompressedStream(FileStream compressedStream)
|
||||
private void InvalidateCompressedStream(FileStream compressedStream)
|
||||
{
|
||||
compressedStream.SetLength(0L);
|
||||
}
|
||||
|
||||
private static void PreSave(object source, System.Timers.ElapsedEventArgs e)
|
||||
private void PreSave(object source, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
_waitEvent.Reset();
|
||||
|
||||
string fileNameActual = string.Concat(Ptc.CachePathActual, ".info");
|
||||
string fileNameBackup = string.Concat(Ptc.CachePathBackup, ".info");
|
||||
string fileNameActual = string.Concat(_ptc.CachePathActual, ".info");
|
||||
string fileNameBackup = string.Concat(_ptc.CachePathBackup, ".info");
|
||||
|
||||
FileInfo fileInfoActual = new FileInfo(fileNameActual);
|
||||
|
||||
@@ -257,7 +261,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
private static void Save(string fileName)
|
||||
private void Save(string fileName)
|
||||
{
|
||||
int profiledFuncsCount;
|
||||
|
||||
@@ -329,7 +333,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
private static void Serialize(Stream stream, Dictionary<ulong, FuncProfile> profiledFuncs)
|
||||
private void Serialize(Stream stream, Dictionary<ulong, FuncProfile> profiledFuncs)
|
||||
{
|
||||
SerializeDictionary(stream, profiledFuncs, (stream, structure) => SerializeStructure(stream, structure));
|
||||
}
|
||||
@@ -361,7 +365,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 5*/)]
|
||||
internal struct FuncProfile
|
||||
public struct FuncProfile
|
||||
{
|
||||
public ExecutionMode Mode;
|
||||
public bool HighCq;
|
||||
@@ -373,10 +377,10 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Start()
|
||||
public void Start()
|
||||
{
|
||||
if (Ptc.State == PtcState.Enabled ||
|
||||
Ptc.State == PtcState.Continuing)
|
||||
if (_ptc.State == PtcState.Enabled ||
|
||||
_ptc.State == PtcState.Continuing)
|
||||
{
|
||||
Enabled = true;
|
||||
|
||||
@@ -384,7 +388,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
public static void Stop()
|
||||
public void Stop()
|
||||
{
|
||||
Enabled = false;
|
||||
|
||||
@@ -394,12 +398,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Wait()
|
||||
public void Wait()
|
||||
{
|
||||
_waitEvent.WaitOne();
|
||||
}
|
||||
|
||||
public static void Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
|
@@ -44,6 +44,8 @@ namespace ARMeilleure.Translation
|
||||
private readonly IJitMemoryAllocator _allocator;
|
||||
private readonly ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>> _oldFuncs;
|
||||
|
||||
private readonly Ptc _ptc;
|
||||
|
||||
internal TranslatorCache<TranslatedFunction> Functions { get; }
|
||||
internal AddressTable<ulong> FunctionTable { get; }
|
||||
internal EntryTable<uint> CountTable { get; }
|
||||
@@ -63,6 +65,8 @@ namespace ARMeilleure.Translation
|
||||
|
||||
_oldFuncs = new ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>>();
|
||||
|
||||
_ptc = new Ptc();
|
||||
|
||||
Queue = new TranslatorQueue();
|
||||
|
||||
JitCache.Initialize(allocator);
|
||||
@@ -80,22 +84,37 @@ namespace ARMeilleure.Translation
|
||||
}
|
||||
}
|
||||
|
||||
public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
|
||||
{
|
||||
_ptc.Initialize(titleIdText, displayVersion, enabled, Memory.Type);
|
||||
return _ptc;
|
||||
}
|
||||
|
||||
public void PrepareCodeRange(ulong address, ulong size)
|
||||
{
|
||||
if (_ptc.Profiler.StaticCodeSize == 0)
|
||||
{
|
||||
_ptc.Profiler.StaticCodeStart = address;
|
||||
_ptc.Profiler.StaticCodeSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
public void Execute(State.ExecutionContext context, ulong address)
|
||||
{
|
||||
if (Interlocked.Increment(ref _threadCount) == 1)
|
||||
{
|
||||
IsReadyForTranslation.WaitOne();
|
||||
|
||||
if (Ptc.State == PtcState.Enabled)
|
||||
if (_ptc.State == PtcState.Enabled)
|
||||
{
|
||||
Debug.Assert(Functions.Count == 0);
|
||||
Ptc.LoadTranslations(this);
|
||||
Ptc.MakeAndSaveTranslations(this);
|
||||
_ptc.LoadTranslations(this);
|
||||
_ptc.MakeAndSaveTranslations(this);
|
||||
}
|
||||
|
||||
PtcProfiler.Start();
|
||||
_ptc.Profiler.Start();
|
||||
|
||||
Ptc.Disable();
|
||||
_ptc.Disable();
|
||||
|
||||
// Simple heuristic, should be user configurable in future. (1 for 4 core/ht or less, 2 for 6 core + ht
|
||||
// etc). All threads are normal priority except from the last, which just fills as much of the last core
|
||||
@@ -148,6 +167,12 @@ namespace ARMeilleure.Translation
|
||||
Stubs.Dispose();
|
||||
FunctionTable.Dispose();
|
||||
CountTable.Dispose();
|
||||
|
||||
_ptc.Close();
|
||||
_ptc.Profiler.Stop();
|
||||
|
||||
_ptc.Dispose();
|
||||
_ptc.Profiler.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,9 +214,9 @@ namespace ARMeilleure.Translation
|
||||
func = oldFunc;
|
||||
}
|
||||
|
||||
if (PtcProfiler.Enabled)
|
||||
if (_ptc.Profiler.Enabled)
|
||||
{
|
||||
PtcProfiler.AddEntry(address, mode, highCq: false);
|
||||
_ptc.Profiler.AddEntry(address, mode, highCq: false);
|
||||
}
|
||||
|
||||
RegisterFunction(address, func);
|
||||
@@ -217,6 +242,7 @@ namespace ARMeilleure.Translation
|
||||
Stubs,
|
||||
address,
|
||||
highCq,
|
||||
_ptc.State != PtcState.Disabled,
|
||||
mode: Aarch32Mode.User);
|
||||
|
||||
Logger.StartPass(PassName.Decoding);
|
||||
@@ -262,7 +288,7 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
Hash128 hash = Ptc.ComputeHash(Memory, address, funcSize);
|
||||
|
||||
Ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
|
||||
_ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
|
||||
}
|
||||
|
||||
GuestFunction func = compiledFunc.Map<GuestFunction>();
|
||||
@@ -284,9 +310,9 @@ namespace ARMeilleure.Translation
|
||||
return func;
|
||||
});
|
||||
|
||||
if (PtcProfiler.Enabled)
|
||||
if (_ptc.Profiler.Enabled)
|
||||
{
|
||||
PtcProfiler.UpdateEntry(request.Address, request.Mode, highCq: true);
|
||||
_ptc.Profiler.UpdateEntry(request.Address, request.Mode, highCq: true);
|
||||
}
|
||||
|
||||
RegisterFunction(request.Address, func);
|
||||
|
@@ -34,7 +34,7 @@
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.24.2-build21" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.26.1-build23" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.1" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||
@@ -50,7 +50,5 @@
|
||||
<PackageVersion Include="System.Net.NameResolution" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Threading.ThreadPool" Version="4.3.0" />
|
||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.5.1" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3"/>
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
@@ -1,5 +1,4 @@
|
||||
using ARMeilleure.Translation;
|
||||
using ARMeilleure.Translation.PTC;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Threading;
|
||||
using LibHac.Tools.FsSystem;
|
||||
@@ -280,7 +279,7 @@ namespace Ryujinx.Ava
|
||||
_parent.Title = $"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
|
||||
});
|
||||
|
||||
_parent.ViewModel.HandleShaderProgress(Device);
|
||||
_parent.ViewModel.SetUiProgressHandlers(Device);
|
||||
|
||||
Renderer.SizeChanged += Window_SizeChanged;
|
||||
|
||||
@@ -357,8 +356,6 @@ namespace Ryujinx.Ava
|
||||
|
||||
DisplaySleep.Restore();
|
||||
|
||||
Ptc.Close();
|
||||
PtcProfiler.Stop();
|
||||
NpadManager.Dispose();
|
||||
TouchScreenManager.Dispose();
|
||||
Device.Dispose();
|
||||
@@ -949,7 +946,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
if (_keyboardInterface.GetKeyboardStateSnapshot().IsPressed(Key.Delete) && _parent.WindowState != WindowState.FullScreen)
|
||||
{
|
||||
Ptc.Continue();
|
||||
Device.Application.DiskCacheLoadState?.Cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -1,4 +1,3 @@
|
||||
using ARMeilleure.Translation.PTC;
|
||||
using Avalonia;
|
||||
using Avalonia.Threading;
|
||||
using Ryujinx.Ava.UI.Windows;
|
||||
@@ -197,9 +196,6 @@ namespace Ryujinx.Ava
|
||||
|
||||
private static void ProcessUnhandledException(Exception ex, bool isTerminating)
|
||||
{
|
||||
Ptc.Close();
|
||||
PtcProfiler.Stop();
|
||||
|
||||
string message = $"Unhandled exception caught: {ex}";
|
||||
|
||||
Logger.Error?.PrintMsg(LogClass.Application, message);
|
||||
@@ -219,9 +215,6 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
DiscordIntegrationModule.Exit();
|
||||
|
||||
Ptc.Dispose();
|
||||
PtcProfiler.Dispose();
|
||||
|
||||
Logger.Shutdown();
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,3 @@
|
||||
using ARMeilleure.Translation.PTC;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
@@ -18,6 +17,7 @@ using Ryujinx.Ava.UI.Windows;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS;
|
||||
@@ -107,9 +107,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated;
|
||||
ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded;
|
||||
|
||||
Ptc.PtcStateChanged -= ProgressHandler;
|
||||
Ptc.PtcStateChanged += ProgressHandler;
|
||||
}
|
||||
|
||||
public string SearchText
|
||||
@@ -436,7 +433,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool ShowMenuAndStatusBar
|
||||
{
|
||||
get => _showMenuAndStatusBar;
|
||||
@@ -745,8 +742,14 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleShaderProgress(Switch emulationContext)
|
||||
public void SetUiProgressHandlers(Switch emulationContext)
|
||||
{
|
||||
if (emulationContext.Application.DiskCacheLoadState != null)
|
||||
{
|
||||
emulationContext.Application.DiskCacheLoadState.StateChanged -= ProgressHandler;
|
||||
emulationContext.Application.DiskCacheLoadState.StateChanged += ProgressHandler;
|
||||
}
|
||||
|
||||
emulationContext.Gpu.ShaderCacheStateChanged -= ProgressHandler;
|
||||
emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler;
|
||||
}
|
||||
@@ -1033,16 +1036,16 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case PtcLoadingState ptcState:
|
||||
case LoadState ptcState:
|
||||
CacheLoadStatus = $"{current} / {total}";
|
||||
switch (ptcState)
|
||||
{
|
||||
case PtcLoadingState.Start:
|
||||
case PtcLoadingState.Loading:
|
||||
case LoadState.Unloaded:
|
||||
case LoadState.Loading:
|
||||
LoadHeading = LocaleManager.Instance[LocaleKeys.CompilingPPTC];
|
||||
IsLoadingIndeterminate = false;
|
||||
break;
|
||||
case PtcLoadingState.Loaded:
|
||||
case LoadState.Loaded:
|
||||
LoadHeading = string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], TitleName);
|
||||
IsLoadingIndeterminate = true;
|
||||
CacheLoadStatus = "";
|
||||
@@ -1166,7 +1169,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "1"));
|
||||
|
||||
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
|
||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogPPTCDeletionMessage], selection.TitleName),
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
|
@@ -1,4 +1,3 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
@@ -8,8 +7,6 @@ using Ryujinx.Audio.Backends.OpenAL;
|
||||
using Ryujinx.Audio.Backends.SDL2;
|
||||
using Ryujinx.Audio.Backends.SoundIo;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Input;
|
||||
using Ryujinx.Ava.UI.Controls;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.Windows;
|
||||
using Ryujinx.Common.Configuration;
|
||||
@@ -19,7 +16,6 @@ using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.Vulkan;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||
using Ryujinx.Input;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Ryujinx.Ui.Common.Configuration.System;
|
||||
using System;
|
||||
@@ -30,11 +26,10 @@ using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
internal class SettingsViewModel : BaseModel
|
||||
public class SettingsViewModel : BaseModel
|
||||
{
|
||||
private readonly VirtualFileSystem _virtualFileSystem;
|
||||
private readonly ContentManager _contentManager;
|
||||
private readonly StyleableWindow _owner;
|
||||
private TimeZoneContentManager _timeZoneContentManager;
|
||||
|
||||
private readonly List<string> _validTzRegions;
|
||||
@@ -44,10 +39,14 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
private int _graphicsBackendMultithreadingIndex;
|
||||
private float _volume;
|
||||
private bool _isVulkanAvailable = true;
|
||||
private bool _directoryChanged = false;
|
||||
private List<string> _gpuIds = new List<string>();
|
||||
private bool _directoryChanged;
|
||||
private List<string> _gpuIds = new();
|
||||
private KeyboardHotkeys _keyboardHotkeys;
|
||||
private int _graphicsBackendIndex;
|
||||
private string _customThemePath;
|
||||
|
||||
public event Action CloseWindow;
|
||||
public event Action SaveSettingsEvent;
|
||||
|
||||
public int ResolutionScale
|
||||
{
|
||||
@@ -67,19 +66,16 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
_graphicsBackendMultithreadingIndex = value;
|
||||
|
||||
if (_owner != null)
|
||||
if (_graphicsBackendMultithreadingIndex != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value)
|
||||
{
|
||||
if (_graphicsBackendMultithreadingIndex != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value)
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage],
|
||||
"",
|
||||
"",
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningTitle]);
|
||||
});
|
||||
}
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage],
|
||||
"",
|
||||
"",
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningTitle]);
|
||||
});
|
||||
}
|
||||
|
||||
OnPropertyChanged();
|
||||
@@ -120,12 +116,12 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsMacOS
|
||||
{
|
||||
get => OperatingSystem.IsMacOS();
|
||||
}
|
||||
|
||||
|
||||
public bool EnableDiscordIntegration { get; set; }
|
||||
public bool CheckUpdatesOnStart { get; set; }
|
||||
public bool ShowConfirmExit { get; set; }
|
||||
@@ -160,7 +156,20 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
public string TimeZone { get; set; }
|
||||
public string ShaderDumpPath { get; set; }
|
||||
public string CustomThemePath { get; set; }
|
||||
|
||||
public string CustomThemePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _customThemePath;
|
||||
}
|
||||
set
|
||||
{
|
||||
_customThemePath = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public int Language { get; set; }
|
||||
public int Region { get; set; }
|
||||
@@ -191,7 +200,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
_volume = value;
|
||||
|
||||
ConfigurationState.Instance.System.AudioVolume.Value = (float)(_volume / 100);
|
||||
ConfigurationState.Instance.System.AudioVolume.Value = _volume / 100;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
@@ -199,7 +208,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
public DateTimeOffset DateOffset { get; set; }
|
||||
public TimeSpan TimeOffset { get; set; }
|
||||
public AvaloniaList<TimeZone> TimeZones { get; set; }
|
||||
private AvaloniaList<TimeZone> TimeZones { get; set; }
|
||||
public AvaloniaList<string> GameDirectories { get; set; }
|
||||
public ObservableCollection<ComboBoxItem> AvailableGpus { get; set; }
|
||||
|
||||
@@ -214,17 +223,13 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public IGamepadDriver AvaloniaKeyboardDriver { get; }
|
||||
|
||||
public SettingsViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager, StyleableWindow owner) : this()
|
||||
public SettingsViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this()
|
||||
{
|
||||
_virtualFileSystem = virtualFileSystem;
|
||||
_contentManager = contentManager;
|
||||
_owner = owner;
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
LoadTimeZones();
|
||||
AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,10 +256,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
IsSDL2Enabled = SDL2HardwareDeviceDriver.IsSupported;
|
||||
}
|
||||
|
||||
private unsafe void LoadAvailableGpus()
|
||||
private void LoadAvailableGpus()
|
||||
{
|
||||
_gpuIds = new List<string>();
|
||||
List<string> names = new List<string>();
|
||||
List<string> names = new();
|
||||
var devices = VulkanRenderer.GetPhysicalDevices();
|
||||
|
||||
if (devices.Length == 0)
|
||||
@@ -272,7 +277,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
|
||||
AvailableGpus.Clear();
|
||||
AvailableGpus.AddRange(names.Select(x => new ComboBoxItem() { Content = x }));
|
||||
AvailableGpus.AddRange(names.Select(x => new ComboBoxItem { Content = x }));
|
||||
}
|
||||
|
||||
public void LoadTimeZones()
|
||||
@@ -302,25 +307,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public async void BrowseTheme()
|
||||
{
|
||||
var dialog = new OpenFileDialog()
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.SettingsSelectThemeFileDialogTitle],
|
||||
AllowMultiple = false
|
||||
};
|
||||
|
||||
dialog.Filters.Add(new FileDialogFilter() { Extensions = { "xaml" }, Name = LocaleManager.Instance[LocaleKeys.SettingsXamlThemeFile] });
|
||||
|
||||
var file = await dialog.ShowAsync(_owner);
|
||||
|
||||
if (file != null && file.Length > 0)
|
||||
{
|
||||
CustomThemePath = file[0];
|
||||
OnPropertyChanged(nameof(CustomThemePath));
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadCurrentConfiguration()
|
||||
{
|
||||
ConfigurationState config = ConfigurationState.Instance;
|
||||
@@ -477,16 +463,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
config.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||
|
||||
MainWindow.UpdateGraphicsConfig();
|
||||
|
||||
if (_owner is SettingsWindow owner)
|
||||
{
|
||||
owner.ControllerSettings?.SaveCurrentProfile();
|
||||
}
|
||||
|
||||
if (_owner.Owner is MainWindow window && _directoryChanged)
|
||||
{
|
||||
window.ViewModel.LoadApplications();
|
||||
}
|
||||
|
||||
SaveSettingsEvent?.Invoke();
|
||||
|
||||
_directoryChanged = false;
|
||||
}
|
||||
@@ -504,13 +482,13 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
public void OkButton()
|
||||
{
|
||||
SaveSettings();
|
||||
_owner.Close();
|
||||
CloseWindow?.Invoke();
|
||||
}
|
||||
|
||||
public void CancelButton()
|
||||
{
|
||||
RevertIfNotSaved();
|
||||
_owner.Close();
|
||||
CloseWindow?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
81
Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml
Normal file
81
Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml
Normal file
@@ -0,0 +1,81 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsAudioView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="viewModels:SettingsViewModel">
|
||||
<Design.DataContext>
|
||||
<viewModels:SettingsViewModel />
|
||||
</Design.DataContext>
|
||||
<ScrollViewer
|
||||
Name="AudioPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabAudio}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemAudioBackend}"
|
||||
ToolTip.Tip="{locale:Locale AudioBackendTooltip}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding AudioBackend}"
|
||||
Width="350"
|
||||
HorizontalContentAlignment="Left">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendDummy}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem IsEnabled="{Binding IsOpenAlEnabled}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendOpenAL}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem IsEnabled="{Binding IsSoundIoEnabled}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendSoundIO}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem IsEnabled="{Binding IsSDL2Enabled}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendSDL2}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemAudioVolume}"
|
||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||
Width="250" />
|
||||
<ui:NumberBox Value="{Binding Volume}"
|
||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||
Width="350"
|
||||
SmallChange="1"
|
||||
LargeChange="10"
|
||||
SimpleNumberFormat="F0"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Minimum="0"
|
||||
Maximum="100" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<Slider Value="{Binding Volume}"
|
||||
Margin="250,0,0,0"
|
||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||
Minimum="0"
|
||||
Maximum="100"
|
||||
SmallChange="5"
|
||||
TickFrequency="5"
|
||||
IsSnapToTickEnabled="True"
|
||||
LargeChange="10"
|
||||
Width="350" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
12
Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml.cs
Normal file
12
Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
public partial class SettingsAudioView : UserControl
|
||||
{
|
||||
public SettingsAudioView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
72
Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml
Normal file
72
Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml
Normal file
@@ -0,0 +1,72 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsCPUView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="viewModels:SettingsViewModel">
|
||||
<Design.DataContext>
|
||||
<viewModels:SettingsViewModel />
|
||||
</Design.DataContext>
|
||||
<ScrollViewer
|
||||
Name="CpuPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabCpuCache}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnablePptc}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnablePptc}"
|
||||
ToolTip.Tip="{locale:Locale PptcToggleTooltip}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabCpuMemory}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemMemoryManagerMode}"
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerTooltip}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding MemoryMode}"
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerTooltip}"
|
||||
HorizontalContentAlignment="Left"
|
||||
Width="350">
|
||||
<ComboBoxItem
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerSoftwareTooltip}">
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemMemoryManagerModeSoftware}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerHostTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemMemoryManagerModeHost}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerUnsafeTooltip}">
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemMemoryManagerModeHostUnchecked}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
12
Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml.cs
Normal file
12
Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
public partial class SettingsCPUView : UserControl
|
||||
{
|
||||
public SettingsCPUView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
218
Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml
Normal file
218
Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml
Normal file
@@ -0,0 +1,218 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsGraphicsView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="viewModels:SettingsViewModel">
|
||||
<Design.DataContext>
|
||||
<viewModels:SettingsViewModel />
|
||||
</Design.DataContext>
|
||||
<ScrollViewer
|
||||
Name="GraphicsPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsAPI}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsBackend}"
|
||||
Width="250" />
|
||||
<ComboBox Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}"
|
||||
SelectedIndex="{Binding GraphicsBackendIndex}">
|
||||
<ComboBoxItem IsVisible="{Binding IsVulkanAvailable}">
|
||||
<TextBlock Text="Vulkan" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem IsEnabled="{Binding IsOpenGLAvailable}">
|
||||
<TextBlock Text="OpenGL" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" IsVisible="{Binding IsVulkanSelected}">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsPreferredGpu}"
|
||||
Width="250" />
|
||||
<ComboBox Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}"
|
||||
SelectedIndex="{Binding PreferredGpuIndex}"
|
||||
Items="{Binding AvailableGpus}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsFeatures}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnableShaderCache}"
|
||||
ToolTip.Tip="{locale:Locale ShaderCacheToggleTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsEnableShaderCache}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableTextureRecompression}"
|
||||
ToolTip.Tip="{locale:Locale SettingsEnableTextureRecompressionTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsEnableTextureRecompression}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableMacroHLE}"
|
||||
ToolTip.Tip="{locale:Locale SettingsEnableMacroHLETooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale ResolutionScaleTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsResolutionScale}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding ResolutionScale}"
|
||||
Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale ResolutionScaleTooltip}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScaleCustom}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScaleNative}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale2x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale3x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale4x}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
<ui:NumberBox
|
||||
Margin="10,0,0,0"
|
||||
ToolTip.Tip="{locale:Locale ResolutionScaleEntryTooltip}"
|
||||
MinWidth="150"
|
||||
SmallChange="0.1"
|
||||
LargeChange="1"
|
||||
SimpleNumberFormat="F2"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
IsVisible="{Binding IsCustomResolutionScaleActive}"
|
||||
Maximum="100"
|
||||
Minimum="0.1"
|
||||
Value="{Binding CustomResolutionScale}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale AnisotropyTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding MaxAnisotropy}"
|
||||
Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale AnisotropyTooltip}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabGraphicsAnisotropicFilteringAuto}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering2x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering4x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering8x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering16x}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale AspectRatioTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsAspectRatio}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding AspectRatio}"
|
||||
Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale AspectRatioTooltip}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio4x3}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio16x9}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio16x10}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio21x9}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio32x9}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatioStretch}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale GraphicsBackendThreadingTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsBackendMultithreading}"
|
||||
Width="250" />
|
||||
<ComboBox Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale GalThreadingTooltip}"
|
||||
SelectedIndex="{Binding GraphicsBackendMultithreadingIndex}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale CommonAuto}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale CommonOff}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale CommonOn}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsDeveloperOptions}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale ShaderDumpPathTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsShaderDumpPath}"
|
||||
Width="250" />
|
||||
<TextBox Text="{Binding ShaderDumpPath}"
|
||||
Width="350"
|
||||
ToolTip.Tip="{locale:Locale ShaderDumpPathTooltip}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
12
Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml.cs
Normal file
12
Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
public partial class SettingsGraphicsView : UserControl
|
||||
{
|
||||
public SettingsGraphicsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
104
Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml
Normal file
104
Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml
Normal file
@@ -0,0 +1,104 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsHotkeysView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||
mc:Ignorable="d"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="viewModels:SettingsViewModel"
|
||||
Focusable="True">
|
||||
<Design.DataContext>
|
||||
<viewModels:SettingsViewModel />
|
||||
</Design.DataContext>
|
||||
<UserControl.Resources>
|
||||
<helpers:KeyValueConverter x:Key="Key" />
|
||||
</UserControl.Resources>
|
||||
<ScrollViewer
|
||||
Name="HotkeysPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel Margin="10" Orientation="Vertical" Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabHotkeysHotkeys}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleVsyncHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ToggleVsync, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysScreenshotHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.Screenshot, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysShowUiHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ShowUi, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysPauseHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.Pause, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleMuteHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ToggleMute, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleUpHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ResScaleUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleDownHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ResScaleDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeUpHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.VolumeUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeDownHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.VolumeDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
81
Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs
Normal file
81
Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Ryujinx.Ava.Input;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Input;
|
||||
using Ryujinx.Input.Assigner;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
public partial class SettingsHotkeysView : UserControl
|
||||
{
|
||||
private ButtonKeyAssigner _currentAssigner;
|
||||
private IGamepadDriver AvaloniaKeyboardDriver;
|
||||
|
||||
public SettingsHotkeysView()
|
||||
{
|
||||
InitializeComponent();
|
||||
AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this);
|
||||
}
|
||||
|
||||
private void MouseClick(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
|
||||
|
||||
_currentAssigner?.Cancel(shouldUnbind);
|
||||
|
||||
PointerPressed -= MouseClick;
|
||||
}
|
||||
|
||||
private void Button_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is ToggleButton button)
|
||||
{
|
||||
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_currentAssigner == null && button.IsChecked != null && (bool)button.IsChecked)
|
||||
{
|
||||
_currentAssigner = new ButtonKeyAssigner(button);
|
||||
|
||||
FocusManager.Instance?.Focus(this, NavigationMethod.Pointer);
|
||||
|
||||
PointerPressed += MouseClick;
|
||||
|
||||
var keyboard = (IKeyboard)AvaloniaKeyboardDriver.GetGamepad(AvaloniaKeyboardDriver.GamepadsIds[0]);
|
||||
IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
|
||||
|
||||
_currentAssigner.GetInputAndAssign(assigner);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_currentAssigner != null)
|
||||
{
|
||||
ToggleButton oldButton = _currentAssigner.ToggledButton;
|
||||
|
||||
_currentAssigner.Cancel();
|
||||
_currentAssigner = null;
|
||||
|
||||
button.IsChecked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Button_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_currentAssigner?.Cancel();
|
||||
_currentAssigner = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_currentAssigner?.Cancel();
|
||||
_currentAssigner = null;
|
||||
}
|
||||
}
|
||||
}
|
46
Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml
Normal file
46
Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml
Normal file
@@ -0,0 +1,46 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsInputView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="viewModels:SettingsViewModel">
|
||||
<Design.DataContext>
|
||||
<viewModels:SettingsViewModel />
|
||||
</Design.DataContext>
|
||||
<ScrollViewer
|
||||
Name="InputPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel Margin="4" Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox Margin="5,0"
|
||||
ToolTip.Tip="{locale:Locale DockModeToggleTooltip}"
|
||||
IsChecked="{Binding EnableDockedMode}">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabInputEnableDockedMode}" />
|
||||
</CheckBox>
|
||||
<CheckBox Margin="5,0"
|
||||
ToolTip.Tip="{locale:Locale DirectKeyboardTooltip}"
|
||||
IsChecked="{Binding EnableKeyboard}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabInputDirectKeyboardAccess}" />
|
||||
</CheckBox>
|
||||
<CheckBox Margin="5,0"
|
||||
ToolTip.Tip="{locale:Locale DirectMouseTooltip}"
|
||||
IsChecked="{Binding EnableMouse}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabInputDirectMouseAccess}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<window:ControllerSettingsWindow Name="ControllerSettings" Margin="0" MinHeight="600" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
17
Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml.cs
Normal file
17
Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
public partial class SettingsInputView : UserControl
|
||||
{
|
||||
public SettingsInputView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ControllerSettings.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
118
Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml
Normal file
118
Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml
Normal file
@@ -0,0 +1,118 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsLoggingView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="viewModels:SettingsViewModel">
|
||||
<Design.DataContext>
|
||||
<viewModels:SettingsViewModel />
|
||||
</Design.DataContext>
|
||||
<ScrollViewer
|
||||
Name="LoggingPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabLoggingLogging}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnableFileLog}"
|
||||
ToolTip.Tip="{locale:Locale FileLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableLoggingToFile}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableStub}"
|
||||
ToolTip.Tip="{locale:Locale StubLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableStubLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableInfo}"
|
||||
ToolTip.Tip="{locale:Locale InfoLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableInfoLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableWarn}"
|
||||
ToolTip.Tip="{locale:Locale WarnLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableWarningLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableError}"
|
||||
ToolTip.Tip="{locale:Locale ErrorLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableErrorLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableTrace}"
|
||||
ToolTip.Tip="{locale:Locale TraceLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableTraceLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableGuest}"
|
||||
ToolTip.Tip="{locale:Locale GuestLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableGuestLogs}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabLoggingDeveloperOptions}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnableDebug}"
|
||||
ToolTip.Tip="{locale:Locale DebugLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableDebugLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableFsAccessLog}"
|
||||
ToolTip.Tip="{locale:Locale FileAccessLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableFsAccessLogs}" />
|
||||
</CheckBox>
|
||||
<StackPanel Margin="0,10,0,0" Orientation="Horizontal" VerticalAlignment="Stretch">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale FSAccessLogModeTooltip}"
|
||||
Text="{locale:Locale SettingsTabLoggingFsGlobalAccessLogMode}"
|
||||
Width="285" />
|
||||
<ui:NumberBox
|
||||
Maximum="3"
|
||||
Minimum="0"
|
||||
Width="150"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
SmallChange="1"
|
||||
LargeChange="1"
|
||||
Value="{Binding FsGlobalAccessLogMode}" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,10,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevel}"
|
||||
ToolTip.Tip="{locale:Locale OpenGlLogLevel}"
|
||||
Width="285" />
|
||||
<ComboBox SelectedIndex="{Binding OpenglDebugLevel}"
|
||||
Width="150"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale OpenGlLogLevel}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelNone}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelError}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelPerformance}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelAll}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
12
Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml.cs
Normal file
12
Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
public partial class SettingsLoggingView : UserControl
|
||||
{
|
||||
public SettingsLoggingView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
35
Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml
Normal file
35
Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml
Normal file
@@ -0,0 +1,35 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsNetworkView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="viewModels:SettingsViewModel">
|
||||
<Design.DataContext>
|
||||
<viewModels:SettingsViewModel />
|
||||
</Design.DataContext>
|
||||
<ScrollViewer
|
||||
Name="NetworkPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabNetworkConnection}" />
|
||||
<CheckBox Margin="10,0,0,0" IsChecked="{Binding EnableInternetAccess}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnableInternetAccess}"
|
||||
ToolTip.Tip="{locale:Locale EnableInternetAccessTooltip}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
12
Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml.cs
Normal file
12
Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
public partial class SettingsNetworkView : UserControl
|
||||
{
|
||||
public SettingsNetworkView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
195
Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml
Normal file
195
Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml
Normal file
@@ -0,0 +1,195 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsSystemView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="viewModels:SettingsViewModel">
|
||||
<Design.DataContext>
|
||||
<viewModels:SettingsViewModel />
|
||||
</Design.DataContext>
|
||||
<ScrollViewer
|
||||
Name="SystemPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemCore}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemSystemRegion}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding Region}"
|
||||
ToolTip.Tip="{locale:Locale RegionTooltip}"
|
||||
HorizontalContentAlignment="Left"
|
||||
Width="350">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionJapan}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionUSA}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionEurope}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionAustralia}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionChina}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionKorea}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionTaiwan}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguage}"
|
||||
ToolTip.Tip="{locale:Locale LanguageTooltip}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding Language}"
|
||||
ToolTip.Tip="{locale:Locale LanguageTooltip}"
|
||||
HorizontalContentAlignment="Left"
|
||||
Width="350">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageJapanese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageAmericanEnglish}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageFrench}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageGerman}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageItalian}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageSpanish}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageChinese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageKorean}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageDutch}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguagePortuguese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageRussian}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageTaiwanese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageBritishEnglish}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageCanadianFrench}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageLatinAmericanSpanish}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageSimplifiedChinese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageTraditionalChinese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageBrazilianPortuguese}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemSystemTimeZone}"
|
||||
ToolTip.Tip="{locale:Locale TimezoneTooltip}"
|
||||
Width="250" />
|
||||
<AutoCompleteBox
|
||||
Name="TimeZoneBox"
|
||||
Width="350"
|
||||
MaxDropDownHeight="500"
|
||||
FilterMode="Contains"
|
||||
Items="{Binding TimeZones}"
|
||||
SelectionChanged="TimeZoneBox_OnSelectionChanged"
|
||||
Text="{Binding Path=TimeZone, Mode=OneWay}"
|
||||
TextChanged="TimeZoneBox_OnTextChanged"
|
||||
ToolTip.Tip="{locale:Locale TimezoneTooltip}" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemSystemTime}"
|
||||
ToolTip.Tip="{locale:Locale TimeTooltip}"
|
||||
Width="250"/>
|
||||
<DatePicker VerticalAlignment="Center" SelectedDate="{Binding DateOffset}"
|
||||
ToolTip.Tip="{locale:Locale TimeTooltip}"
|
||||
Width="350" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="250,0,0,10" Orientation="Horizontal">
|
||||
<TimePicker
|
||||
VerticalAlignment="Center"
|
||||
ClockIdentifier="24HourClock"
|
||||
SelectedTime="{Binding TimeOffset}"
|
||||
Width="350"
|
||||
ToolTip.Tip="{locale:Locale TimeTooltip}" />
|
||||
</StackPanel>
|
||||
<CheckBox IsChecked="{Binding EnableVsync}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnableVsync}"
|
||||
ToolTip.Tip="{locale:Locale VSyncToggleTooltip}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableFsIntegrityChecks}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnableFsIntegrityChecks}"
|
||||
ToolTip.Tip="{locale:Locale FsIntegrityToggleTooltip}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemHacks}" />
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemHacksNote}" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding ExpandDramSize}"
|
||||
ToolTip.Tip="{locale:Locale DRamTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemExpandDramSize}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding IgnoreMissingServices}"
|
||||
ToolTip.Tip="{locale:Locale IgnoreMissingServicesTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemIgnoreMissingServices}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
52
Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs
Normal file
52
Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Data.Converters;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
public partial class SettingsSystemView : UserControl
|
||||
{
|
||||
public SettingsViewModel ViewModel;
|
||||
|
||||
public SettingsSystemView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
FuncMultiValueConverter<string, string> converter = new(parts => string.Format("{0} {1} {2}", parts.ToArray()).Trim());
|
||||
MultiBinding tzMultiBinding = new() { Converter = converter };
|
||||
|
||||
tzMultiBinding.Bindings.Add(new Binding("UtcDifference"));
|
||||
tzMultiBinding.Bindings.Add(new Binding("Location"));
|
||||
tzMultiBinding.Bindings.Add(new Binding("Abbreviation"));
|
||||
|
||||
TimeZoneBox.ValueMemberBinding = tzMultiBinding;
|
||||
}
|
||||
|
||||
private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (e.AddedItems != null && e.AddedItems.Count > 0)
|
||||
{
|
||||
if (e.AddedItems[0] is TimeZone timeZone)
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
ViewModel.ValidateAndSetTimeZone(timeZone.Location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TimeZoneBox_OnTextChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is AutoCompleteBox box && box.SelectedItem is TimeZone timeZone)
|
||||
{
|
||||
{
|
||||
ViewModel.ValidateAndSetTimeZone(timeZone.Location);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
156
Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml
Normal file
156
Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml
Normal file
@@ -0,0 +1,156 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsUIView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="viewModels:SettingsViewModel">
|
||||
<Design.DataContext>
|
||||
<viewModels:SettingsViewModel />
|
||||
</Design.DataContext>
|
||||
<ScrollViewer
|
||||
Name="UiPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGeneral}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnableDiscordIntegration}">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale ToggleDiscordTooltip}"
|
||||
Text="{locale:Locale SettingsTabGeneralEnableDiscordRichPresence}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding CheckUpdatesOnStart}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralCheckUpdatesOnLaunch}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding ShowConfirmExit}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralShowConfirmExitDialog}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding HideCursorOnIdle}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralHideCursorOnIdle}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGameDirectories}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<ListBox
|
||||
Name="GameList"
|
||||
MinHeight="230"
|
||||
Items="{Binding GameDirectories}">
|
||||
<ListBox.Styles>
|
||||
<Style Selector="ListBoxItem">
|
||||
<Setter Property="Padding" Value="10" />
|
||||
<Setter Property="Background" Value="{DynamicResource ListBoxBackground}" />
|
||||
</Style>
|
||||
</ListBox.Styles>
|
||||
</ListBox>
|
||||
<Grid HorizontalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox
|
||||
Name="PathBox"
|
||||
Margin="0"
|
||||
ToolTip.Tip="{locale:Locale AddGameDirBoxTooltip}"
|
||||
VerticalAlignment="Stretch" />
|
||||
<Button
|
||||
Name="AddButton"
|
||||
Grid.Column="1"
|
||||
MinWidth="90"
|
||||
Margin="10,0,0,0"
|
||||
ToolTip.Tip="{locale:Locale AddGameDirTooltip}"
|
||||
Click="AddButton_OnClick">
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabGeneralAdd}" />
|
||||
</Button>
|
||||
<Button
|
||||
Name="RemoveButton"
|
||||
Grid.Column="2"
|
||||
MinWidth="90"
|
||||
Margin="10,0,0,0"
|
||||
ToolTip.Tip="{locale:Locale RemoveGameDirTooltip}"
|
||||
Click="RemoveButton_OnClick">
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabGeneralRemove}" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralTheme}" />
|
||||
<Grid Margin="10,0,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<CheckBox
|
||||
IsChecked="{Binding EnableCustomTheme}"
|
||||
ToolTip.Tip="{locale:Locale CustomThemeCheckTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeEnableCustomTheme}" />
|
||||
</CheckBox>
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,10,0,0"
|
||||
Text="{locale:Locale SettingsTabGeneralThemeCustomTheme}"
|
||||
ToolTip.Tip="{locale:Locale CustomThemePathTooltip}" />
|
||||
<TextBox
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="0,10,0,0"
|
||||
Text="{Binding CustomThemePath}" />
|
||||
<Button
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Margin="10,10,0,0"
|
||||
Click="BrowseTheme"
|
||||
ToolTip.Tip="{locale:Locale CustomThemeBrowseTooltip}"
|
||||
Content="{locale:Locale ButtonBrowse}" />
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Grid.Row="2"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,10,0,0"
|
||||
Text="{locale:Locale SettingsTabGeneralThemeBaseStyle}" />
|
||||
<ComboBox
|
||||
Grid.Column="1"
|
||||
Grid.Row="2"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,10,0,0"
|
||||
MinWidth="100"
|
||||
SelectedIndex="{Binding BaseStyleIndex}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeBaseStyleLight}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeBaseStyleDark}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
82
Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml.cs
Normal file
82
Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Interactivity;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
public partial class SettingsUIView : UserControl
|
||||
{
|
||||
public SettingsViewModel ViewModel;
|
||||
|
||||
public SettingsUIView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void AddButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string path = PathBox.Text;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.GameDirectories.Contains(path))
|
||||
{
|
||||
ViewModel.GameDirectories.Add(path);
|
||||
ViewModel.DirectoryChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
path = await new OpenFolderDialog().ShowAsync(desktop.MainWindow);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
ViewModel.GameDirectories.Add(path);
|
||||
ViewModel.DirectoryChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
int oldIndex = GameList.SelectedIndex;
|
||||
|
||||
foreach (string path in new List<string>(GameList.SelectedItems.Cast<string>()))
|
||||
{
|
||||
ViewModel.GameDirectories.Remove(path);
|
||||
ViewModel.DirectoryChanged = true;
|
||||
}
|
||||
|
||||
if (GameList.ItemCount > 0)
|
||||
{
|
||||
GameList.SelectedIndex = oldIndex < GameList.ItemCount ? oldIndex : 0;
|
||||
}
|
||||
}
|
||||
|
||||
public async void BrowseTheme(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new OpenFileDialog()
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.SettingsSelectThemeFileDialogTitle],
|
||||
AllowMultiple = false
|
||||
};
|
||||
|
||||
dialog.Filters.Add(new FileDialogFilter() { Extensions = { "xaml" }, Name = LocaleManager.Instance[LocaleKeys.SettingsXamlThemeFile] });
|
||||
|
||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
var file = await dialog.ShowAsync(desktop.MainWindow);
|
||||
|
||||
if (file != null && file.Length > 0)
|
||||
{
|
||||
ViewModel.CustomThemePath = file[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -6,13 +6,12 @@
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
xmlns:settings="clr-namespace:Ryujinx.Ava.UI.Views.Settings"
|
||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||
Width="1100"
|
||||
Height="768"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="950"
|
||||
MinWidth="800"
|
||||
MinHeight="480"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
@@ -23,9 +22,6 @@
|
||||
<Design.DataContext>
|
||||
<viewModels:SettingsViewModel />
|
||||
</Design.DataContext>
|
||||
<Window.Resources>
|
||||
<helpers:KeyValueConverter x:Key="Key" />
|
||||
</Window.Resources>
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinWidth="600">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
@@ -38,871 +34,15 @@
|
||||
IsVisible="False"
|
||||
KeyboardNavigation.IsTabStop="False"/>
|
||||
<Grid Name="Pages" IsVisible="False" Grid.Row="2">
|
||||
<ScrollViewer Name="UiPage"
|
||||
Margin="0,0,2,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGeneral}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnableDiscordIntegration}">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale ToggleDiscordTooltip}"
|
||||
Text="{locale:Locale SettingsTabGeneralEnableDiscordRichPresence}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding CheckUpdatesOnStart}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralCheckUpdatesOnLaunch}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding ShowConfirmExit}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralShowConfirmExitDialog}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding HideCursorOnIdle}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralHideCursorOnIdle}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGameDirectories}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<ListBox
|
||||
Name="GameList"
|
||||
MinHeight="250"
|
||||
Items="{Binding GameDirectories}" />
|
||||
<Grid HorizontalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox
|
||||
Name="PathBox"
|
||||
Margin="0"
|
||||
ToolTip.Tip="{locale:Locale AddGameDirBoxTooltip}"
|
||||
VerticalAlignment="Stretch" />
|
||||
<Button
|
||||
Name="AddButton"
|
||||
Grid.Column="1"
|
||||
MinWidth="90"
|
||||
Margin="10,0,0,0"
|
||||
ToolTip.Tip="{locale:Locale AddGameDirTooltip}"
|
||||
Click="AddButton_OnClick">
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabGeneralAdd}" />
|
||||
</Button>
|
||||
<Button
|
||||
Name="RemoveButton"
|
||||
Grid.Column="2"
|
||||
MinWidth="90"
|
||||
Margin="10,0,0,0"
|
||||
ToolTip.Tip="{locale:Locale RemoveGameDirTooltip}"
|
||||
Click="RemoveButton_OnClick">
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabGeneralRemove}" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralTheme}" />
|
||||
<Grid Margin="10,0,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<CheckBox IsChecked="{Binding EnableCustomTheme}"
|
||||
ToolTip.Tip="{locale:Locale CustomThemeCheckTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeEnableCustomTheme}" />
|
||||
</CheckBox>
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Margin="0,10,0,0"
|
||||
Grid.Row="1"
|
||||
Text="{locale:Locale SettingsTabGeneralThemeCustomTheme}"
|
||||
ToolTip.Tip="{locale:Locale CustomThemePathTooltip}" />
|
||||
<TextBox Margin="0,10,0,0"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Text="{Binding CustomThemePath}" />
|
||||
<Button Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Margin="10,10,0,0"
|
||||
Command="{ReflectionBinding BrowseTheme}"
|
||||
ToolTip.Tip="{locale:Locale CustomThemeBrowseTooltip}"
|
||||
Content="{locale:Locale ButtonBrowse}" />
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Margin="0,10,0,0"
|
||||
Grid.Row="2"
|
||||
Text="{locale:Locale SettingsTabGeneralThemeBaseStyle}" />
|
||||
<ComboBox VerticalAlignment="Center"
|
||||
Margin="0,10,0,0"
|
||||
Grid.Column="1"
|
||||
Grid.Row="2"
|
||||
MinWidth="100"
|
||||
SelectedIndex="{Binding BaseStyleIndex}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeBaseStyleLight}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeBaseStyleDark}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer Name="InputPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Padding="0,0,2,0"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel Margin="4" Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox Margin="5,0"
|
||||
ToolTip.Tip="{locale:Locale DockModeToggleTooltip}"
|
||||
IsChecked="{Binding EnableDockedMode}">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabInputEnableDockedMode}" />
|
||||
</CheckBox>
|
||||
<CheckBox Margin="5,0"
|
||||
ToolTip.Tip="{locale:Locale DirectKeyboardTooltip}"
|
||||
IsChecked="{Binding EnableKeyboard}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabInputDirectKeyboardAccess}" />
|
||||
</CheckBox>
|
||||
<CheckBox Margin="5,0"
|
||||
ToolTip.Tip="{locale:Locale DirectMouseTooltip}"
|
||||
IsChecked="{Binding EnableMouse}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabInputDirectMouseAccess}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<window:ControllerSettingsWindow Name="ControllerSettings" Margin="0,0,0,0" MinHeight="600" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer Name="HotkeysPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel Margin="10,5" Orientation="Vertical" Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabHotkeysHotkeys}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleVsyncHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ToggleVsync, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysScreenshotHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.Screenshot, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysShowUiHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ShowUi, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysPauseHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.Pause, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleMuteHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ToggleMute, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleUpHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ResScaleUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleDownHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.ResScaleDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeUpHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.VolumeUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeDownHotkey}" Width="230" />
|
||||
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||
<TextBlock
|
||||
Text="{Binding KeyboardHotkeys.VolumeDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||
TextAlignment="Center" />
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer Name="SystemPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemCore}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemSystemRegion}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding Region}"
|
||||
ToolTip.Tip="{locale:Locale RegionTooltip}"
|
||||
HorizontalContentAlignment="Left"
|
||||
Width="350">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionJapan}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionUSA}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionEurope}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionAustralia}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionChina}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionKorea}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionTaiwan}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguage}"
|
||||
ToolTip.Tip="{locale:Locale LanguageTooltip}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding Language}"
|
||||
ToolTip.Tip="{locale:Locale LanguageTooltip}"
|
||||
HorizontalContentAlignment="Left"
|
||||
Width="350">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageJapanese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageAmericanEnglish}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageFrench}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageGerman}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageItalian}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageSpanish}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageChinese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageKorean}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageDutch}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguagePortuguese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageRussian}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageTaiwanese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageBritishEnglish}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageCanadianFrench}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageLatinAmericanSpanish}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageSimplifiedChinese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageTraditionalChinese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemSystemLanguageBrazilianPortuguese}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemSystemTimeZone}"
|
||||
ToolTip.Tip="{locale:Locale TimezoneTooltip}"
|
||||
Width="250" />
|
||||
<AutoCompleteBox
|
||||
Name="TimeZoneBox"
|
||||
Width="350"
|
||||
MaxDropDownHeight="500"
|
||||
FilterMode="Contains"
|
||||
Items="{Binding TimeZones}"
|
||||
SelectionChanged="TimeZoneBox_OnSelectionChanged"
|
||||
Text="{Binding Path=TimeZone, Mode=OneWay}"
|
||||
TextChanged="TimeZoneBox_OnTextChanged"
|
||||
ValueMemberBinding="{ReflectionBinding TzMultiBinding}"
|
||||
ToolTip.Tip="{locale:Locale TimezoneTooltip}" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemSystemTime}"
|
||||
ToolTip.Tip="{locale:Locale TimeTooltip}"
|
||||
Width="250"/>
|
||||
<DatePicker VerticalAlignment="Center" SelectedDate="{Binding DateOffset}"
|
||||
ToolTip.Tip="{locale:Locale TimeTooltip}"
|
||||
Width="350" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="250,0,0,10" Orientation="Horizontal">
|
||||
<TimePicker
|
||||
VerticalAlignment="Center"
|
||||
ClockIdentifier="24HourClock"
|
||||
SelectedTime="{Binding TimeOffset}"
|
||||
Width="350"
|
||||
ToolTip.Tip="{locale:Locale TimeTooltip}" />
|
||||
</StackPanel>
|
||||
<CheckBox IsChecked="{Binding EnableVsync}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnableVsync}"
|
||||
ToolTip.Tip="{locale:Locale VSyncToggleTooltip}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableFsIntegrityChecks}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnableFsIntegrityChecks}"
|
||||
ToolTip.Tip="{locale:Locale FsIntegrityToggleTooltip}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemHacks}" />
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemHacksNote}" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding ExpandDramSize}"
|
||||
ToolTip.Tip="{locale:Locale DRamTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemExpandDramSize}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding IgnoreMissingServices}"
|
||||
ToolTip.Tip="{locale:Locale IgnoreMissingServicesTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemIgnoreMissingServices}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer
|
||||
Name="CpuPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabCpuCache}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnablePptc}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnablePptc}"
|
||||
ToolTip.Tip="{locale:Locale PptcToggleTooltip}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabCpuMemory}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemMemoryManagerMode}"
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerTooltip}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding MemoryMode}"
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerTooltip}"
|
||||
HorizontalContentAlignment="Left"
|
||||
Width="350">
|
||||
<ComboBoxItem
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerSoftwareTooltip}">
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemMemoryManagerModeSoftware}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerHostTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemMemoryManagerModeHost}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem
|
||||
ToolTip.Tip="{locale:Locale MemoryManagerUnsafeTooltip}">
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabSystemMemoryManagerModeHostUnchecked}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer
|
||||
Name="GraphicsPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsAPI}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsBackend}"
|
||||
Width="250" />
|
||||
<ComboBox Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}"
|
||||
SelectedIndex="{Binding GraphicsBackendIndex}">
|
||||
<ComboBoxItem IsVisible="{Binding IsVulkanAvailable}">
|
||||
<TextBlock Text="Vulkan" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem IsEnabled="{Binding IsOpenGLAvailable}">
|
||||
<TextBlock Text="OpenGL" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" IsVisible="{Binding IsVulkanSelected}">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsPreferredGpu}"
|
||||
Width="250" />
|
||||
<ComboBox Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}"
|
||||
SelectedIndex="{Binding PreferredGpuIndex}"
|
||||
Items="{Binding AvailableGpus}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsFeatures}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnableShaderCache}"
|
||||
ToolTip.Tip="{locale:Locale ShaderCacheToggleTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsEnableShaderCache}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableTextureRecompression}"
|
||||
ToolTip.Tip="{locale:Locale SettingsEnableTextureRecompressionTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsEnableTextureRecompression}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableMacroHLE}"
|
||||
ToolTip.Tip="{locale:Locale SettingsEnableMacroHLETooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale ResolutionScaleTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsResolutionScale}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding ResolutionScale}"
|
||||
Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale ResolutionScaleTooltip}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScaleCustom}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScaleNative}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale2x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale3x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale4x}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
<ui:NumberBox
|
||||
Margin="10,0,0,0"
|
||||
ToolTip.Tip="{locale:Locale ResolutionScaleEntryTooltip}"
|
||||
MinWidth="150"
|
||||
SmallChange="0.1"
|
||||
LargeChange="1"
|
||||
SimpleNumberFormat="F2"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
IsVisible="{Binding IsCustomResolutionScaleActive}"
|
||||
Maximum="100"
|
||||
Minimum="0.1"
|
||||
Value="{Binding CustomResolutionScale}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale AnisotropyTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding MaxAnisotropy}"
|
||||
Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale AnisotropyTooltip}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabGraphicsAnisotropicFilteringAuto}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering2x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering4x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering8x}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering16x}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale AspectRatioTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsAspectRatio}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding AspectRatio}"
|
||||
Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale AspectRatioTooltip}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio4x3}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio16x9}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio16x10}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio21x9}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio32x9}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatioStretch}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale GraphicsBackendThreadingTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsBackendMultithreading}"
|
||||
Width="250" />
|
||||
<ComboBox Width="350"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale GalThreadingTooltip}"
|
||||
SelectedIndex="{Binding GraphicsBackendMultithreadingIndex}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale CommonAuto}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale CommonOff}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale CommonOn}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsDeveloperOptions}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale ShaderDumpPathTooltip}"
|
||||
Text="{locale:Locale SettingsTabGraphicsShaderDumpPath}"
|
||||
Width="250" />
|
||||
<TextBox Text="{Binding ShaderDumpPath}"
|
||||
Width="350"
|
||||
ToolTip.Tip="{locale:Locale ShaderDumpPathTooltip}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer
|
||||
Name="AudioPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabAudio}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemAudioBackend}"
|
||||
ToolTip.Tip="{locale:Locale AudioBackendTooltip}"
|
||||
Width="250" />
|
||||
<ComboBox SelectedIndex="{Binding AudioBackend}"
|
||||
Width="350"
|
||||
HorizontalContentAlignment="Left">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendDummy}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem IsEnabled="{Binding IsOpenAlEnabled}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendOpenAL}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem IsEnabled="{Binding IsSoundIoEnabled}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendSoundIO}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem IsEnabled="{Binding IsSDL2Enabled}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendSDL2}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabSystemAudioVolume}"
|
||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||
Width="250" />
|
||||
<ui:NumberBox Value="{Binding Volume}"
|
||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||
Width="350"
|
||||
SmallChange="1"
|
||||
LargeChange="10"
|
||||
SimpleNumberFormat="F0"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Minimum="0"
|
||||
Maximum="100" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||
<Slider Value="{Binding Volume}"
|
||||
Margin="250,0,0,0"
|
||||
ToolTip.Tip="{locale:Locale AudioVolumeTooltip}"
|
||||
Minimum="0"
|
||||
Maximum="100"
|
||||
SmallChange="5"
|
||||
TickFrequency="5"
|
||||
IsSnapToTickEnabled="True"
|
||||
LargeChange="10"
|
||||
Width="350" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer
|
||||
Name="NetworkPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabNetworkConnection}" />
|
||||
<CheckBox Margin="10,0,0,0" IsChecked="{Binding EnableInternetAccess}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabSystemEnableInternetAccess}"
|
||||
ToolTip.Tip="{locale:Locale EnableInternetAccessTooltip}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer
|
||||
Name="LoggingPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabLoggingLogging}" />
|
||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnableFileLog}"
|
||||
ToolTip.Tip="{locale:Locale FileLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableLoggingToFile}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableStub}"
|
||||
ToolTip.Tip="{locale:Locale StubLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableStubLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableInfo}"
|
||||
ToolTip.Tip="{locale:Locale InfoLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableInfoLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableWarn}"
|
||||
ToolTip.Tip="{locale:Locale WarnLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableWarningLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableError}"
|
||||
ToolTip.Tip="{locale:Locale ErrorLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableErrorLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableTrace}"
|
||||
ToolTip.Tip="{locale:Locale TraceLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableTraceLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableGuest}"
|
||||
ToolTip.Tip="{locale:Locale GuestLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableGuestLogs}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabLoggingDeveloperOptions}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnableDebug}"
|
||||
ToolTip.Tip="{locale:Locale DebugLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableDebugLogs}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableFsAccessLog}"
|
||||
ToolTip.Tip="{locale:Locale FileAccessLogTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingEnableFsAccessLogs}" />
|
||||
</CheckBox>
|
||||
<StackPanel Margin="0,10,0,0" Orientation="Horizontal" VerticalAlignment="Stretch">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip.Tip="{locale:Locale FSAccessLogModeTooltip}"
|
||||
Text="{locale:Locale SettingsTabLoggingFsGlobalAccessLogMode}"
|
||||
Width="285" />
|
||||
<ui:NumberBox
|
||||
Maximum="3"
|
||||
Minimum="0"
|
||||
Width="150"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
SmallChange="1"
|
||||
LargeChange="1"
|
||||
Value="{Binding FsGlobalAccessLogMode}" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,10,0,0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevel}"
|
||||
ToolTip.Tip="{locale:Locale OpenGlLogLevel}"
|
||||
Width="285" />
|
||||
<ComboBox SelectedIndex="{Binding OpenglDebugLevel}"
|
||||
Width="150"
|
||||
HorizontalContentAlignment="Left"
|
||||
ToolTip.Tip="{locale:Locale OpenGlLogLevel}">
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelNone}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelError}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock
|
||||
Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelPerformance}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelAll}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
<settings:SettingsUIView Name="UiPage" />
|
||||
<settings:SettingsInputView Name="InputPage" />
|
||||
<settings:SettingsHotkeysView Name="HotkeysPage" />
|
||||
<settings:SettingsSystemView Name="SystemPage" />
|
||||
<settings:SettingsCPUView Name="CpuPage" />
|
||||
<settings:SettingsGraphicsView Name="GraphicsPage" />
|
||||
<settings:SettingsAudioView Name="AudioPage" />
|
||||
<settings:SettingsNetworkView Name="NetworkPage" />
|
||||
<settings:SettingsLoggingView Name="LoggingPage" />
|
||||
</Grid>
|
||||
<ui:NavigationView Grid.Row="1"
|
||||
IsSettingsVisible="False"
|
||||
@@ -962,7 +102,7 @@
|
||||
Spacing="10"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right"
|
||||
ReverseOrder="{ReflectionBinding IsMacOS}">
|
||||
ReverseOrder="{Binding IsMacOS}">
|
||||
<Button
|
||||
HotKey="Enter"
|
||||
Classes="accent"
|
||||
|
@@ -1,49 +1,29 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using FluentAvalonia.Core;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Controls;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.Input;
|
||||
using Ryujinx.Input.Assigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
public partial class SettingsWindow : StyleableWindow
|
||||
{
|
||||
private ButtonKeyAssigner _currentAssigner;
|
||||
|
||||
internal SettingsViewModel ViewModel { get; set; }
|
||||
|
||||
public SettingsWindow(VirtualFileSystem virtualFileSystem, ContentManager contentManager)
|
||||
{
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.Settings]}";
|
||||
|
||||
ViewModel = new SettingsViewModel(virtualFileSystem, contentManager, this);
|
||||
ViewModel = new SettingsViewModel(virtualFileSystem, contentManager);
|
||||
DataContext = ViewModel;
|
||||
|
||||
ViewModel.CloseWindow += Close;
|
||||
ViewModel.SaveSettingsEvent += SaveSettings;
|
||||
|
||||
InitializeComponent();
|
||||
Load();
|
||||
|
||||
FuncMultiValueConverter<string, string> converter = new(parts => string.Format("{0} {1} {2}", parts.ToArray()).Trim());
|
||||
MultiBinding tzMultiBinding = new() { Converter = converter };
|
||||
tzMultiBinding.Bindings.Add(new Binding("UtcDifference"));
|
||||
tzMultiBinding.Bindings.Add(new Binding("Location"));
|
||||
tzMultiBinding.Bindings.Add(new Binding("Abbreviation"));
|
||||
|
||||
TimeZoneBox.ValueMemberBinding = tzMultiBinding;
|
||||
}
|
||||
|
||||
public SettingsWindow()
|
||||
@@ -55,6 +35,16 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
Load();
|
||||
}
|
||||
|
||||
public void SaveSettings()
|
||||
{
|
||||
InputPage.ControllerSettings?.SaveCurrentProfile();
|
||||
|
||||
if (Owner is MainWindow window && ViewModel.DirectoryChanged)
|
||||
{
|
||||
window.ViewModel.LoadApplications();
|
||||
}
|
||||
}
|
||||
|
||||
private void Load()
|
||||
{
|
||||
Pages.Children.Clear();
|
||||
@@ -62,152 +52,52 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
NavPanel.SelectedItem = NavPanel.MenuItems.ElementAt(0);
|
||||
}
|
||||
|
||||
private void Button_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is ToggleButton button)
|
||||
{
|
||||
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_currentAssigner == null && (bool)button.IsChecked)
|
||||
{
|
||||
_currentAssigner = new ButtonKeyAssigner(button);
|
||||
|
||||
FocusManager.Instance.Focus(this, NavigationMethod.Pointer);
|
||||
|
||||
PointerPressed += MouseClick;
|
||||
|
||||
IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad(ViewModel.AvaloniaKeyboardDriver.GamepadsIds[0]);
|
||||
IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
|
||||
|
||||
_currentAssigner.GetInputAndAssign(assigner);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_currentAssigner != null)
|
||||
{
|
||||
ToggleButton oldButton = _currentAssigner.ToggledButton;
|
||||
|
||||
_currentAssigner.Cancel();
|
||||
_currentAssigner = null;
|
||||
|
||||
button.IsChecked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Button_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_currentAssigner?.Cancel();
|
||||
_currentAssigner = null;
|
||||
}
|
||||
|
||||
private void MouseClick(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
bool shouldUnbind = false;
|
||||
|
||||
if (e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed)
|
||||
{
|
||||
shouldUnbind = true;
|
||||
}
|
||||
|
||||
_currentAssigner?.Cancel(shouldUnbind);
|
||||
|
||||
PointerPressed -= MouseClick;
|
||||
}
|
||||
|
||||
private void NavPanelOnSelectionChanged(object sender, NavigationViewSelectionChangedEventArgs e)
|
||||
{
|
||||
if (e.SelectedItem is NavigationViewItem navitem)
|
||||
if (e.SelectedItem is NavigationViewItem navItem && navItem.Tag is not null)
|
||||
{
|
||||
NavPanel.Content = navitem.Tag.ToString() switch
|
||||
switch (navItem.Tag.ToString())
|
||||
{
|
||||
"UiPage" => UiPage,
|
||||
"InputPage" => InputPage,
|
||||
"HotkeysPage" => HotkeysPage,
|
||||
"SystemPage" => SystemPage,
|
||||
"CpuPage" => CpuPage,
|
||||
"GraphicsPage" => GraphicsPage,
|
||||
"AudioPage" => AudioPage,
|
||||
"NetworkPage" => NetworkPage,
|
||||
"LoggingPage" => LoggingPage,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private async void AddButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string path = PathBox.Text;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.GameDirectories.Contains(path))
|
||||
{
|
||||
ViewModel.GameDirectories.Add(path);
|
||||
ViewModel.DirectoryChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = await new OpenFolderDialog().ShowAsync(this);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
ViewModel.GameDirectories.Add(path);
|
||||
ViewModel.DirectoryChanged = true;
|
||||
case "UiPage":
|
||||
UiPage.ViewModel = ViewModel;
|
||||
NavPanel.Content = UiPage;
|
||||
break;
|
||||
case "InputPage":
|
||||
NavPanel.Content = InputPage;
|
||||
break;
|
||||
case "HotkeysPage":
|
||||
NavPanel.Content = HotkeysPage;
|
||||
break;
|
||||
case "SystemPage":
|
||||
SystemPage.ViewModel = ViewModel;
|
||||
NavPanel.Content = SystemPage;
|
||||
break;
|
||||
case "CpuPage":
|
||||
NavPanel.Content = CpuPage;
|
||||
break;
|
||||
case "GraphicsPage":
|
||||
NavPanel.Content = GraphicsPage;
|
||||
break;
|
||||
case "AudioPage":
|
||||
NavPanel.Content = AudioPage;
|
||||
break;
|
||||
case "NetworkPage":
|
||||
NavPanel.Content = NetworkPage;
|
||||
break;
|
||||
case "LoggingPage":
|
||||
NavPanel.Content = LoggingPage;
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveButton_OnClick(object sender, RoutedEventArgs e)
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
int oldIndex = GameList.SelectedIndex;
|
||||
|
||||
foreach (string path in new List<string>(GameList.SelectedItems.Cast<string>()))
|
||||
{
|
||||
ViewModel.GameDirectories.Remove(path);
|
||||
ViewModel.DirectoryChanged = true;
|
||||
}
|
||||
|
||||
if (GameList.ItemCount > 0)
|
||||
{
|
||||
GameList.SelectedIndex = oldIndex < GameList.ItemCount ? oldIndex : 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (e.AddedItems != null && e.AddedItems.Count > 0)
|
||||
{
|
||||
if (e.AddedItems[0] is TimeZone timeZone)
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
ViewModel.ValidateAndSetTimeZone(timeZone.Location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TimeZoneBox_OnTextChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is AutoCompleteBox box)
|
||||
{
|
||||
if (box.SelectedItem != null && box.SelectedItem is TimeZone timeZone)
|
||||
{
|
||||
ViewModel.ValidateAndSetTimeZone(timeZone.Location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
ControllerSettings.Dispose();
|
||||
|
||||
_currentAssigner?.Cancel();
|
||||
_currentAssigner = null;
|
||||
|
||||
base.OnClosed(e);
|
||||
HotkeysPage.Dispose();
|
||||
InputPage.Dispose();
|
||||
base.OnClosing(e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -35,5 +35,27 @@ namespace Ryujinx.Cpu
|
||||
/// <param name="address">Address of the region to be invalidated</param>
|
||||
/// <param name="size">Size of the region to be invalidated</param>
|
||||
void InvalidateCacheRegion(ulong address, ulong size);
|
||||
|
||||
/// <summary>
|
||||
/// Loads cached code from disk for a given application.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the execution engine is recompiling guest code, this can be used to load cached code from disk.
|
||||
/// </remarks>
|
||||
/// <param name="titleIdText">Title ID of the application in padded hex form</param>
|
||||
/// <param name="displayVersion">Version of the application</param>
|
||||
/// <param name="enabled">True if the cache should be loaded from disk if it exists, false otherwise</param>
|
||||
/// <returns>Disk cache load progress reporter and manager</returns>
|
||||
IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled);
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that code has been loaded into guest memory, and that it might be executed in the future.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Some execution engines might use this information to cache recompiled code on disk or to ensure it can be executed.
|
||||
/// </remarks>
|
||||
/// <param name="address">CPU virtual address where the code starts</param>
|
||||
/// <param name="size">Size of the code range in bytes</param>
|
||||
void PrepareCodeRange(ulong address, ulong size);
|
||||
}
|
||||
}
|
||||
|
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);
|
||||
}
|
||||
|
||||
/// <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.Account;
|
||||
using LibHac.Common;
|
||||
@@ -14,8 +13,8 @@ using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.Loaders.Executables;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
@@ -67,6 +66,8 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
public string TitleIdText => TitleId.ToString("x16");
|
||||
|
||||
public IDiskCacheLoadState DiskCacheLoadState { get; private set; }
|
||||
|
||||
public ApplicationLoader(Switch device)
|
||||
{
|
||||
_device = device;
|
||||
@@ -94,7 +95,7 @@ namespace Ryujinx.HLE.HOS
|
||||
EnsureSaveData(new ApplicationId(TitleId));
|
||||
}
|
||||
|
||||
LoadExeFs(codeFs, metaData);
|
||||
LoadExeFs(codeFs, string.Empty, metaData);
|
||||
}
|
||||
|
||||
public static (Nca main, Nca patch, Nca control) GetGameData(VirtualFileSystem fileSystem, PartitionFileSystem pfs, int programIndex)
|
||||
@@ -302,12 +303,6 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
public void LoadServiceNca(string ncaFile)
|
||||
{
|
||||
// Disable PPTC here as it does not support multiple processes running.
|
||||
// TODO: This should be eventually removed and it should stop using global state and
|
||||
// instead manage the cache per process.
|
||||
Ptc.Close();
|
||||
PtcProfiler.Stop();
|
||||
|
||||
FileStream file = new FileStream(ncaFile, FileMode.Open, FileAccess.Read);
|
||||
Nca mainNca = new Nca(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false));
|
||||
|
||||
@@ -369,16 +364,12 @@ namespace Ryujinx.HLE.HOS
|
||||
// Collect the nsos, ignoring ones that aren't used.
|
||||
NsoExecutable[] programs = nsos.Where(x => x != null).ToArray();
|
||||
|
||||
MemoryManagerMode memoryManagerMode = _device.Configuration.MemoryManagerMode;
|
||||
|
||||
if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))
|
||||
{
|
||||
memoryManagerMode = MemoryManagerMode.SoftwarePageTable;
|
||||
}
|
||||
string displayVersion = _device.System.ContentManager.GetCurrentFirmwareVersion().VersionString;
|
||||
bool usePtc = _device.System.EnablePtc;
|
||||
|
||||
metaData.GetNpdm(out Npdm npdm).ThrowIfFailure();
|
||||
ProgramInfo programInfo = new ProgramInfo(in npdm, allowCodeMemoryForJit: false);
|
||||
ProgramLoader.LoadNsos(_device.System.KernelContext, out _, metaData, programInfo, executables: programs);
|
||||
ProgramInfo programInfo = new ProgramInfo(in npdm, displayVersion, usePtc, allowCodeMemoryForJit: false);
|
||||
ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: programs);
|
||||
|
||||
string titleIdText = npdm.Aci.Value.ProgramId.Value.ToString("x16");
|
||||
bool titleIs64Bit = (npdm.Meta.Value.Flags & 1) != 0;
|
||||
@@ -477,9 +468,11 @@ namespace Ryujinx.HLE.HOS
|
||||
_device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath(),
|
||||
_device.Configuration.VirtualFileSystem.ModLoader.GetSdModsBasePath());
|
||||
|
||||
string displayVersion = string.Empty;
|
||||
|
||||
if (controlNca != null)
|
||||
{
|
||||
ReadControlData(_device, controlNca, ref _controlData, ref _titleName, ref _displayVersion);
|
||||
ReadControlData(_device, controlNca, ref _controlData, ref _titleName, ref displayVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -493,9 +486,11 @@ namespace Ryujinx.HLE.HOS
|
||||
string dummyTitleName = "";
|
||||
BlitStruct<ApplicationControlProperty> dummyControl = new BlitStruct<ApplicationControlProperty>(1);
|
||||
|
||||
ReadControlData(_device, updateProgram0ControlNca, ref dummyControl, ref dummyTitleName, ref _displayVersion);
|
||||
ReadControlData(_device, updateProgram0ControlNca, ref dummyControl, ref dummyTitleName, ref displayVersion);
|
||||
}
|
||||
|
||||
_displayVersion = displayVersion;
|
||||
|
||||
if (dataStorage == null)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Loader, "No RomFS found in NCA");
|
||||
@@ -515,7 +510,7 @@ namespace Ryujinx.HLE.HOS
|
||||
EnsureSaveData(new ApplicationId(TitleId & ~0xFul));
|
||||
}
|
||||
|
||||
LoadExeFs(codeFs, metaData);
|
||||
LoadExeFs(codeFs, displayVersion, metaData);
|
||||
|
||||
Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {TitleName} v{DisplayVersion} [{TitleIdText}] [{(TitleIs64Bit ? "64-bit" : "32-bit")}]");
|
||||
}
|
||||
@@ -584,7 +579,7 @@ namespace Ryujinx.HLE.HOS
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadExeFs(IFileSystem codeFs, MetaLoader metaData = null, bool isHomebrew = false)
|
||||
private void LoadExeFs(IFileSystem codeFs, string displayVersion, MetaLoader metaData = null, bool isHomebrew = false)
|
||||
{
|
||||
if (_device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs))
|
||||
{
|
||||
@@ -649,23 +644,23 @@ namespace Ryujinx.HLE.HOS
|
||||
memoryManagerMode = MemoryManagerMode.SoftwarePageTable;
|
||||
}
|
||||
|
||||
Ptc.Initialize(TitleIdText, DisplayVersion, usePtc, memoryManagerMode);
|
||||
|
||||
// We allow it for nx-hbloader because it can be used to launch homebrew.
|
||||
bool allowCodeMemoryForJit = TitleId == 0x010000000000100DUL || isHomebrew;
|
||||
|
||||
metaData.GetNpdm(out Npdm npdm).ThrowIfFailure();
|
||||
ProgramInfo programInfo = new ProgramInfo(in npdm, allowCodeMemoryForJit);
|
||||
ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, programInfo, executables: programs);
|
||||
ProgramInfo programInfo = new ProgramInfo(in npdm, displayVersion, usePtc, allowCodeMemoryForJit);
|
||||
ProgramLoadResult result = ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: programs);
|
||||
|
||||
_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)
|
||||
{
|
||||
MetaLoader metaData = GetDefaultNpdm();
|
||||
metaData.GetNpdm(out Npdm npdm).ThrowIfFailure();
|
||||
ProgramInfo programInfo = new ProgramInfo(in npdm, allowCodeMemoryForJit: true);
|
||||
ProgramInfo programInfo = new ProgramInfo(in npdm, string.Empty, diskCacheEnabled: false, allowCodeMemoryForJit: true);
|
||||
|
||||
bool isNro = Path.GetExtension(filePath).ToLower() == ".nro";
|
||||
|
||||
@@ -761,9 +756,11 @@ namespace Ryujinx.HLE.HOS
|
||||
Graphics.Gpu.GraphicsConfig.TitleId = null;
|
||||
_device.Gpu.HostInitalized.Set();
|
||||
|
||||
ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, programInfo, executables: executable);
|
||||
ProgramLoadResult result = ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: executable);
|
||||
|
||||
_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()
|
||||
|
@@ -6,7 +6,17 @@ using Ryujinx.Memory;
|
||||
|
||||
namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
class ArmProcessContext<T> : IProcessContext where T : class, IVirtualMemoryManagerTracked, IMemoryManager
|
||||
interface IArmProcessContext : IProcessContext
|
||||
{
|
||||
IDiskCacheLoadState Initialize(
|
||||
string titleIdText,
|
||||
string displayVersion,
|
||||
bool diskCacheEnabled,
|
||||
ulong codeAddress,
|
||||
ulong codeSize);
|
||||
}
|
||||
|
||||
class ArmProcessContext<T> : IArmProcessContext where T : class, IVirtualMemoryManagerTracked, IMemoryManager
|
||||
{
|
||||
private readonly ulong _pid;
|
||||
private readonly GpuContext _gpuContext;
|
||||
@@ -40,6 +50,17 @@ namespace Ryujinx.HLE.HOS
|
||||
_cpuContext.Execute(context, codeAddress);
|
||||
}
|
||||
|
||||
public IDiskCacheLoadState Initialize(
|
||||
string titleIdText,
|
||||
string displayVersion,
|
||||
bool diskCacheEnabled,
|
||||
ulong codeAddress,
|
||||
ulong codeSize)
|
||||
{
|
||||
_cpuContext.PrepareCodeRange(codeAddress, codeSize);
|
||||
return _cpuContext.LoadDiskCache(titleIdText, displayVersion, diskCacheEnabled);
|
||||
}
|
||||
|
||||
public void InvalidateCacheRegion(ulong address, ulong size)
|
||||
{
|
||||
_cpuContext.InvalidateCacheRegion(address, size);
|
||||
|
@@ -13,11 +13,30 @@ namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
private readonly ICpuEngine _cpuEngine;
|
||||
private readonly GpuContext _gpu;
|
||||
private readonly string _titleIdText;
|
||||
private readonly string _displayVersion;
|
||||
private readonly bool _diskCacheEnabled;
|
||||
private readonly ulong _codeAddress;
|
||||
private readonly ulong _codeSize;
|
||||
|
||||
public ArmProcessContextFactory(ICpuEngine cpuEngine, GpuContext gpu)
|
||||
public IDiskCacheLoadState DiskCacheLoadState { get; private set; }
|
||||
|
||||
public ArmProcessContextFactory(
|
||||
ICpuEngine cpuEngine,
|
||||
GpuContext gpu,
|
||||
string titleIdText,
|
||||
string displayVersion,
|
||||
bool diskCacheEnabled,
|
||||
ulong codeAddress,
|
||||
ulong codeSize)
|
||||
{
|
||||
_cpuEngine = cpuEngine;
|
||||
_gpu = gpu;
|
||||
_titleIdText = titleIdText;
|
||||
_displayVersion = displayVersion;
|
||||
_diskCacheEnabled = diskCacheEnabled;
|
||||
_codeAddress = codeAddress;
|
||||
_codeSize = codeSize;
|
||||
}
|
||||
|
||||
public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit)
|
||||
@@ -29,21 +48,29 @@ namespace Ryujinx.HLE.HOS
|
||||
mode = MemoryManagerMode.SoftwarePageTable;
|
||||
}
|
||||
|
||||
IArmProcessContext processContext;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case MemoryManagerMode.SoftwarePageTable:
|
||||
var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
|
||||
return new ArmProcessContext<MemoryManager>(pid, _cpuEngine, _gpu, memoryManager, for64Bit);
|
||||
processContext = new ArmProcessContext<MemoryManager>(pid, _cpuEngine, _gpu, memoryManager, for64Bit);
|
||||
break;
|
||||
|
||||
case MemoryManagerMode.HostMapped:
|
||||
case MemoryManagerMode.HostMappedUnsafe:
|
||||
bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe;
|
||||
var memoryManagerHostMapped = new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler);
|
||||
return new ArmProcessContext<MemoryManagerHostMapped>(pid, _cpuEngine, _gpu, memoryManagerHostMapped, for64Bit);
|
||||
processContext = new ArmProcessContext<MemoryManagerHostMapped>(pid, _cpuEngine, _gpu, memoryManagerHostMapped, for64Bit);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
DiskCacheLoadState = processContext.Initialize(_titleIdText, _displayVersion, _diskCacheEnabled, _codeAddress, _codeSize);
|
||||
|
||||
return processContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -44,7 +44,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
||||
|
||||
public void ScheduleFutureInvocation(IKFutureSchedulerObject schedulerObj, long timeout)
|
||||
{
|
||||
long timePoint = PerformanceCounter.ElapsedTicks + ConvertNanosecondsToHostTicks(timeout);
|
||||
long startTime = PerformanceCounter.ElapsedTicks;
|
||||
long timePoint = startTime + ConvertNanosecondsToHostTicks(timeout);
|
||||
|
||||
if (timePoint < startTime)
|
||||
{
|
||||
timePoint = long.MaxValue;
|
||||
}
|
||||
|
||||
lock (_context.CriticalSection.Lock)
|
||||
{
|
||||
|
@@ -1,9 +1,9 @@
|
||||
using ARMeilleure.Translation.PTC;
|
||||
using LibHac.Loader;
|
||||
using LibHac.Ncm;
|
||||
using LibHac.Util;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
@@ -21,16 +21,40 @@ namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
public string Name;
|
||||
public ulong ProgramId;
|
||||
public bool AllowCodeMemoryForJit;
|
||||
public readonly string TitleIdText;
|
||||
public readonly string DisplayVersion;
|
||||
public readonly bool DiskCacheEnabled;
|
||||
public readonly bool AllowCodeMemoryForJit;
|
||||
|
||||
public ProgramInfo(in Npdm npdm, bool allowCodeMemoryForJit)
|
||||
public ProgramInfo(in Npdm npdm, string displayVersion, bool diskCacheEnabled, bool allowCodeMemoryForJit)
|
||||
{
|
||||
ulong programId = npdm.Aci.Value.ProgramId.Value;
|
||||
|
||||
Name = StringUtils.Utf8ZToString(npdm.Meta.Value.ProgramName);
|
||||
ProgramId = npdm.Aci.Value.ProgramId.Value;
|
||||
ProgramId = programId;
|
||||
TitleIdText = programId.ToString("x16");
|
||||
DisplayVersion = displayVersion;
|
||||
DiskCacheEnabled = diskCacheEnabled;
|
||||
AllowCodeMemoryForJit = allowCodeMemoryForJit;
|
||||
}
|
||||
}
|
||||
|
||||
struct ProgramLoadResult
|
||||
{
|
||||
public static ProgramLoadResult Failed => new ProgramLoadResult(false, null, null);
|
||||
|
||||
public readonly bool Success;
|
||||
public readonly ProcessTamperInfo TamperInfo;
|
||||
public readonly IDiskCacheLoadState DiskCacheLoadState;
|
||||
|
||||
public ProgramLoadResult(bool success, ProcessTamperInfo tamperInfo, IDiskCacheLoadState diskCacheLoadState)
|
||||
{
|
||||
Success = success;
|
||||
TamperInfo = tamperInfo;
|
||||
DiskCacheLoadState = diskCacheLoadState;
|
||||
}
|
||||
}
|
||||
|
||||
static class ProgramLoader
|
||||
{
|
||||
private const bool AslrEnabled = true;
|
||||
@@ -102,7 +126,14 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
KProcess process = new KProcess(context);
|
||||
|
||||
var processContextFactory = new ArmProcessContextFactory(context.Device.System.CpuEngine, context.Device.Gpu);
|
||||
var processContextFactory = new ArmProcessContextFactory(
|
||||
context.Device.System.CpuEngine,
|
||||
context.Device.Gpu,
|
||||
string.Empty,
|
||||
string.Empty,
|
||||
false,
|
||||
codeAddress,
|
||||
codeSize);
|
||||
|
||||
result = process.InitializeKip(
|
||||
creationInfo,
|
||||
@@ -144,9 +175,8 @@ namespace Ryujinx.HLE.HOS
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool LoadNsos(
|
||||
public static ProgramLoadResult LoadNsos(
|
||||
KernelContext context,
|
||||
out ProcessTamperInfo tamperInfo,
|
||||
MetaLoader metaData,
|
||||
ProgramInfo programInfo,
|
||||
byte[] arguments = null,
|
||||
@@ -156,8 +186,7 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
tamperInfo = null;
|
||||
return false;
|
||||
return ProgramLoadResult.Failed;
|
||||
}
|
||||
|
||||
ref readonly var meta = ref npdm.Meta.Value;
|
||||
@@ -212,9 +241,6 @@ namespace Ryujinx.HLE.HOS
|
||||
}
|
||||
}
|
||||
|
||||
PtcProfiler.StaticCodeStart = codeStart;
|
||||
PtcProfiler.StaticCodeSize = (ulong)codeSize;
|
||||
|
||||
int codePagesCount = (int)(codeSize / KPageTableBase.PageSize);
|
||||
|
||||
int personalMmHeapPagesCount = (int)(meta.SystemResourceSize / KPageTableBase.PageSize);
|
||||
@@ -263,9 +289,7 @@ namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Loader, $"Process initialization failed setting resource limit values.");
|
||||
|
||||
tamperInfo = null;
|
||||
|
||||
return false;
|
||||
return ProgramLoadResult.Failed;
|
||||
}
|
||||
|
||||
KProcess process = new KProcess(context, programInfo.AllowCodeMemoryForJit);
|
||||
@@ -276,12 +300,17 @@ namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Loader, $"Process initialization failed due to invalid ACID flags.");
|
||||
|
||||
tamperInfo = null;
|
||||
|
||||
return false;
|
||||
return ProgramLoadResult.Failed;
|
||||
}
|
||||
|
||||
var processContextFactory = new ArmProcessContextFactory(context.Device.System.CpuEngine, context.Device.Gpu);
|
||||
var processContextFactory = new ArmProcessContextFactory(
|
||||
context.Device.System.CpuEngine,
|
||||
context.Device.Gpu,
|
||||
programInfo.TitleIdText,
|
||||
programInfo.DisplayVersion,
|
||||
programInfo.DiskCacheEnabled,
|
||||
codeStart,
|
||||
codeSize);
|
||||
|
||||
result = process.Initialize(
|
||||
creationInfo,
|
||||
@@ -294,9 +323,7 @@ namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
|
||||
|
||||
tamperInfo = null;
|
||||
|
||||
return false;
|
||||
return ProgramLoadResult.Failed;
|
||||
}
|
||||
|
||||
for (int index = 0; index < executables.Length; index++)
|
||||
@@ -309,9 +336,7 @@ namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
|
||||
|
||||
tamperInfo = null;
|
||||
|
||||
return false;
|
||||
return ProgramLoadResult.Failed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,9 +348,7 @@ namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Loader, $"Process start returned error \"{result}\".");
|
||||
|
||||
tamperInfo = null;
|
||||
|
||||
return false;
|
||||
return ProgramLoadResult.Failed;
|
||||
}
|
||||
|
||||
context.Processes.TryAdd(process.Pid, process);
|
||||
@@ -333,10 +356,15 @@ namespace Ryujinx.HLE.HOS
|
||||
// Keep the build ids because the tamper machine uses them to know which process to associate a
|
||||
// tamper to and also keep the starting address of each executable inside a process because some
|
||||
// memory modifications are relative to this address.
|
||||
tamperInfo = new ProcessTamperInfo(process, buildIds, nsoBase, process.MemoryManager.HeapRegionStart,
|
||||
process.MemoryManager.AliasRegionStart, process.MemoryManager.CodeRegionStart);
|
||||
ProcessTamperInfo tamperInfo = new ProcessTamperInfo(
|
||||
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)
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using ARMeilleure.Translation;
|
||||
using ARMeilleure.Translation.PTC;
|
||||
using CommandLine;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using Ryujinx.Audio.Backends.SDL2;
|
||||
@@ -12,6 +11,7 @@ using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.SystemInterop;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.GAL.Multithreading;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
@@ -447,8 +447,11 @@ namespace Ryujinx.Headless.SDL2
|
||||
|
||||
private static void SetupProgressHandler()
|
||||
{
|
||||
Ptc.PtcStateChanged -= ProgressHandler;
|
||||
Ptc.PtcStateChanged += ProgressHandler;
|
||||
if (_emulationContext.Application.DiskCacheLoadState != null)
|
||||
{
|
||||
_emulationContext.Application.DiskCacheLoadState.StateChanged -= ProgressHandler;
|
||||
_emulationContext.Application.DiskCacheLoadState.StateChanged += ProgressHandler;
|
||||
}
|
||||
|
||||
_emulationContext.Gpu.ShaderCacheStateChanged -= ProgressHandler;
|
||||
_emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler;
|
||||
@@ -460,7 +463,7 @@ namespace Ryujinx.Headless.SDL2
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case PtcLoadingState ptcState:
|
||||
case LoadState ptcState:
|
||||
label = $"PTC : {current}/{total}";
|
||||
break;
|
||||
case ShaderCacheState shaderCacheState:
|
||||
@@ -563,9 +566,6 @@ namespace Ryujinx.Headless.SDL2
|
||||
|
||||
_window.Execute();
|
||||
|
||||
Ptc.Close();
|
||||
PtcProfiler.Stop();
|
||||
|
||||
_emulationContext.Dispose();
|
||||
_window.Dispose();
|
||||
|
||||
|
@@ -100,6 +100,14 @@ namespace Ryujinx.Horizon.Common
|
||||
}
|
||||
}
|
||||
|
||||
public void AbortOnFailureUnless(Result result, Result result2)
|
||||
{
|
||||
if (this != Success && this != result && this != result2)
|
||||
{
|
||||
ThrowInvalidResult();
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowInvalidResult()
|
||||
{
|
||||
throw new InvalidResultException(this);
|
||||
@@ -115,4 +123,4 @@ namespace Ryujinx.Horizon.Common
|
||||
return PrintableResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -51,7 +51,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc
|
||||
{
|
||||
Result result = ReplyImpl(sessionHandle, messageBuffer);
|
||||
|
||||
result.AbortUnless(KernelResult.TimedOut, KernelResult.PortRemoteClosed);
|
||||
result.AbortOnFailureUnless(KernelResult.TimedOut, KernelResult.PortRemoteClosed);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
@@ -86,4 +86,4 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,12 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
|
||||
<IsRoslynComponent>true</IsRoslynComponent>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -14,7 +11,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp"/>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@@ -79,6 +79,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spv.Generator", "Spv.Generator\Spv.Generator.csproj", "{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.LocaleGenerator", "Ryujinx.Ui.LocaleGenerator\Ryujinx.Ui.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Common", "Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj", "{77F96ECE-4952-42DB-A528-DED25572A573}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "Ryujinx.Horizon\Ryujinx.Horizon.csproj", "{AF34127A-3A92-43E5-8496-14960A50B1F1}"
|
||||
@@ -231,6 +233,10 @@ Global
|
||||
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
@@ -1,4 +1,3 @@
|
||||
using ARMeilleure.Translation.PTC;
|
||||
using Gtk;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
@@ -308,9 +307,6 @@ namespace Ryujinx
|
||||
|
||||
private static void ProcessUnhandledException(Exception ex, bool isTerminating)
|
||||
{
|
||||
Ptc.Close();
|
||||
PtcProfiler.Stop();
|
||||
|
||||
string message = $"Unhandled exception caught: {ex}";
|
||||
|
||||
Logger.Error?.PrintMsg(LogClass.Application, message);
|
||||
@@ -330,9 +326,6 @@ namespace Ryujinx
|
||||
{
|
||||
DiscordIntegrationModule.Exit();
|
||||
|
||||
Ptc.Dispose();
|
||||
PtcProfiler.Dispose();
|
||||
|
||||
Logger.Shutdown();
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using ARMeilleure.Translation;
|
||||
using ARMeilleure.Translation.PTC;
|
||||
using Gtk;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common.Keys;
|
||||
@@ -16,6 +15,7 @@ using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.SystemInterop;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.GAL.Multithreading;
|
||||
using Ryujinx.Graphics.OpenGL;
|
||||
@@ -46,7 +46,6 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using GUI = Gtk.Builder.ObjectAttribute;
|
||||
using PtcLoadingState = ARMeilleure.Translation.PTC.PtcLoadingState;
|
||||
using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
|
||||
|
||||
namespace Ryujinx.Ui
|
||||
@@ -588,8 +587,11 @@ namespace Ryujinx.Ui
|
||||
|
||||
private void SetupProgressUiHandlers()
|
||||
{
|
||||
Ptc.PtcStateChanged -= ProgressHandler;
|
||||
Ptc.PtcStateChanged += ProgressHandler;
|
||||
if (_emulationContext.Application.DiskCacheLoadState != null)
|
||||
{
|
||||
_emulationContext.Application.DiskCacheLoadState.StateChanged -= ProgressHandler;
|
||||
_emulationContext.Application.DiskCacheLoadState.StateChanged += ProgressHandler;
|
||||
}
|
||||
|
||||
_emulationContext.Gpu.ShaderCacheStateChanged -= ProgressHandler;
|
||||
_emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler;
|
||||
@@ -602,8 +604,8 @@ namespace Ryujinx.Ui
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case PtcLoadingState ptcState:
|
||||
visible = ptcState != PtcLoadingState.Loaded;
|
||||
case LoadState ptcState:
|
||||
visible = ptcState != LoadState.Loaded;
|
||||
label = $"PTC : {current}/{total}";
|
||||
break;
|
||||
case ShaderCacheLoadingState shaderCacheState:
|
||||
@@ -705,8 +707,6 @@ namespace Ryujinx.Ui
|
||||
|
||||
UpdateGraphicsConfig();
|
||||
|
||||
SetupProgressUiHandlers();
|
||||
|
||||
SystemVersion firmwareVersion = _contentManager.GetCurrentFirmwareVersion();
|
||||
|
||||
bool isDirectory = Directory.Exists(path);
|
||||
@@ -841,6 +841,8 @@ namespace Ryujinx.Ui
|
||||
return;
|
||||
}
|
||||
|
||||
SetupProgressUiHandlers();
|
||||
|
||||
_currentEmulatedGamePath = path;
|
||||
|
||||
_deviceExitStatus.Reset();
|
||||
@@ -967,9 +969,6 @@ namespace Ryujinx.Ui
|
||||
|
||||
RendererWidget.Start();
|
||||
|
||||
Ptc.Close();
|
||||
PtcProfiler.Stop();
|
||||
|
||||
_emulationContext.Dispose();
|
||||
_deviceExitStatus.Set();
|
||||
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using ARMeilleure.Translation;
|
||||
using ARMeilleure.Translation.PTC;
|
||||
using Gdk;
|
||||
using Gtk;
|
||||
using Ryujinx.Common;
|
||||
@@ -519,7 +518,7 @@ namespace Ryujinx.Ui
|
||||
_gpuCancellationTokenSource.Cancel();
|
||||
|
||||
_isStopped = true;
|
||||
|
||||
|
||||
if (_isActive)
|
||||
{
|
||||
_isActive = false;
|
||||
@@ -585,7 +584,7 @@ namespace Ryujinx.Ui
|
||||
{
|
||||
if (!ParentWindow.State.HasFlag(WindowState.Fullscreen))
|
||||
{
|
||||
Ptc.Continue();
|
||||
Device.Application.DiskCacheLoadState?.Cancel();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
Reference in New Issue
Block a user