mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-06-12 15:29:15 +00:00
Compare commits
13 Commits
Canary-1.3
...
09d4bfe6d8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09d4bfe6d8 | ||
|
|
5ed94c365b | ||
|
|
fef93a453a | ||
|
|
2274a32813 | ||
|
|
34190c9184 | ||
|
|
18501d01f3 | ||
|
|
6780ff0d8a | ||
|
|
3cc02ebaef | ||
|
|
6938265651 | ||
|
|
f6328ebb69 | ||
|
|
445924102e | ||
|
|
cf72e189b7 | ||
|
|
8bd290cc57 |
@@ -168,7 +168,7 @@ namespace ARMeilleure.Common
|
|||||||
{
|
{
|
||||||
_allocated.Dispose();
|
_allocated.Dispose();
|
||||||
|
|
||||||
foreach (IntPtr page in _pages.Values)
|
foreach (nint page in _pages.Values)
|
||||||
{
|
{
|
||||||
NativeAllocator.Instance.Free((void*)page);
|
NativeAllocator.Instance.Free((void*)page);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,12 +44,12 @@ namespace Ryujinx.Audio.Backends.Apple
|
|||||||
|
|
||||||
int result = AudioQueueNewOutput(
|
int result = AudioQueueNewOutput(
|
||||||
ref format,
|
ref format,
|
||||||
IntPtr.Zero,
|
nint.Zero,
|
||||||
IntPtr.Zero,
|
nint.Zero,
|
||||||
IntPtr.Zero,
|
nint.Zero,
|
||||||
IntPtr.Zero,
|
nint.Zero,
|
||||||
0,
|
0,
|
||||||
out IntPtr testQueue);
|
out nint testQueue);
|
||||||
|
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
{
|
{
|
||||||
@@ -95,12 +95,12 @@ namespace Ryujinx.Audio.Backends.Apple
|
|||||||
GetAudioFormat(SampleFormat.PcmInt16, Constants.TargetSampleRate, 2);
|
GetAudioFormat(SampleFormat.PcmInt16, Constants.TargetSampleRate, 2);
|
||||||
int result = AudioQueueNewOutput(
|
int result = AudioQueueNewOutput(
|
||||||
ref format,
|
ref format,
|
||||||
IntPtr.Zero,
|
nint.Zero,
|
||||||
IntPtr.Zero,
|
nint.Zero,
|
||||||
IntPtr.Zero,
|
nint.Zero,
|
||||||
IntPtr.Zero,
|
nint.Zero,
|
||||||
0,
|
0,
|
||||||
out IntPtr testQueue);
|
out nint testQueue);
|
||||||
|
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
{
|
{
|
||||||
@@ -110,8 +110,9 @@ namespace Ryujinx.Audio.Backends.Apple
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Audio, $"Failed to check if AudioToolbox is supported: {e.Message}\n{e.StackTrace}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
using Ryujinx.Audio.Backends.Common;
|
using Ryujinx.Audio.Backends.Common;
|
||||||
using Ryujinx.Audio.Common;
|
using Ryujinx.Audio.Common;
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using Ryujinx.Audio.Backends.Apple.Native;
|
|
||||||
using static Ryujinx.Audio.Backends.Apple.Native.AudioToolbox;
|
using static Ryujinx.Audio.Backends.Apple.Native.AudioToolbox;
|
||||||
using static Ryujinx.Audio.Backends.Apple.AppleHardwareDeviceDriver;
|
|
||||||
|
|
||||||
namespace Ryujinx.Audio.Backends.Apple
|
namespace Ryujinx.Audio.Backends.Apple
|
||||||
{
|
{
|
||||||
@@ -27,8 +24,8 @@ namespace Ryujinx.Audio.Backends.Apple
|
|||||||
private readonly AudioQueueOutputCallback _callbackDelegate;
|
private readonly AudioQueueOutputCallback _callbackDelegate;
|
||||||
private readonly GCHandle _gcHandle;
|
private readonly GCHandle _gcHandle;
|
||||||
|
|
||||||
private IntPtr _audioQueue;
|
private nint _audioQueue;
|
||||||
private readonly IntPtr[] _audioQueueBuffers = new IntPtr[NumBuffers];
|
private readonly nint[] _audioQueueBuffers = new nint[NumBuffers];
|
||||||
private readonly int[] _bufferBytesFilled = new int[NumBuffers];
|
private readonly int[] _bufferBytesFilled = new int[NumBuffers];
|
||||||
|
|
||||||
private readonly int _bytesPerFrame;
|
private readonly int _bytesPerFrame;
|
||||||
@@ -41,9 +38,9 @@ namespace Ryujinx.Audio.Backends.Apple
|
|||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
private delegate void AudioQueueOutputCallback(
|
private delegate void AudioQueueOutputCallback(
|
||||||
IntPtr userData,
|
nint userData,
|
||||||
IntPtr audioQueue,
|
nint audioQueue,
|
||||||
IntPtr buffer);
|
nint buffer);
|
||||||
|
|
||||||
public AppleHardwareDeviceSession(
|
public AppleHardwareDeviceSession(
|
||||||
AppleHardwareDeviceDriver driver,
|
AppleHardwareDeviceDriver driver,
|
||||||
@@ -72,15 +69,15 @@ namespace Ryujinx.Audio.Backends.Apple
|
|||||||
RequestedSampleRate,
|
RequestedSampleRate,
|
||||||
RequestedChannelCount);
|
RequestedChannelCount);
|
||||||
|
|
||||||
IntPtr callbackPtr = Marshal.GetFunctionPointerForDelegate(_callbackDelegate);
|
nint callbackPtr = Marshal.GetFunctionPointerForDelegate(_callbackDelegate);
|
||||||
IntPtr userData = GCHandle.ToIntPtr(_gcHandle);
|
nint userData = GCHandle.ToIntPtr(_gcHandle);
|
||||||
|
|
||||||
int result = AudioQueueNewOutput(
|
int result = AudioQueueNewOutput(
|
||||||
ref format,
|
ref format,
|
||||||
callbackPtr,
|
callbackPtr,
|
||||||
userData,
|
userData,
|
||||||
IntPtr.Zero,
|
nint.Zero,
|
||||||
IntPtr.Zero,
|
nint.Zero,
|
||||||
0,
|
0,
|
||||||
out _audioQueue);
|
out _audioQueue);
|
||||||
|
|
||||||
@@ -102,7 +99,7 @@ namespace Ryujinx.Audio.Backends.Apple
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void PrimeBuffer(IntPtr bufferPtr, int bufferIndex)
|
private unsafe void PrimeBuffer(nint bufferPtr, int bufferIndex)
|
||||||
{
|
{
|
||||||
AudioQueueBuffer* buffer = (AudioQueueBuffer*)bufferPtr;
|
AudioQueueBuffer* buffer = (AudioQueueBuffer*)bufferPtr;
|
||||||
|
|
||||||
@@ -126,12 +123,12 @@ namespace Ryujinx.Audio.Backends.Apple
|
|||||||
buffer->AudioDataByteSize = (uint)capacityBytes;
|
buffer->AudioDataByteSize = (uint)capacityBytes;
|
||||||
_bufferBytesFilled[bufferIndex] = bytesToRead;
|
_bufferBytesFilled[bufferIndex] = bytesToRead;
|
||||||
|
|
||||||
AudioQueueEnqueueBuffer(_audioQueue, bufferPtr, 0, IntPtr.Zero);
|
AudioQueueEnqueueBuffer(_audioQueue, bufferPtr, 0, nint.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OutputCallback(IntPtr userData, IntPtr audioQueue, IntPtr bufferPtr)
|
private void OutputCallback(nint userData, nint audioQueue, nint bufferPtr)
|
||||||
{
|
{
|
||||||
if (!_started || bufferPtr == IntPtr.Zero)
|
if (!_started || bufferPtr == nint.Zero)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int bufferIndex = Array.IndexOf(_audioQueueBuffers, bufferPtr);
|
int bufferIndex = Array.IndexOf(_audioQueueBuffers, bufferPtr);
|
||||||
@@ -176,7 +173,7 @@ namespace Ryujinx.Audio.Backends.Apple
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void ApplyVolume(IntPtr dataPtr, int byteSize)
|
private unsafe void ApplyVolume(nint dataPtr, int byteSize)
|
||||||
{
|
{
|
||||||
float volume = Math.Clamp(_volume * _driver.Volume, 0f, 1f);
|
float volume = Math.Clamp(_volume * _driver.Volume, 0f, 1f);
|
||||||
if (volume >= 0.999f)
|
if (volume >= 0.999f)
|
||||||
@@ -226,7 +223,7 @@ namespace Ryujinx.Audio.Backends.Apple
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_started = true;
|
_started = true;
|
||||||
AudioQueueStart(_audioQueue, IntPtr.Zero);
|
AudioQueueStart(_audioQueue, nint.Zero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,11 +262,11 @@ namespace Ryujinx.Audio.Backends.Apple
|
|||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
|
|
||||||
if (_audioQueue != IntPtr.Zero)
|
if (_audioQueue != nint.Zero)
|
||||||
{
|
{
|
||||||
AudioQueueStop(_audioQueue, true);
|
AudioQueueStop(_audioQueue, true);
|
||||||
AudioQueueDispose(_audioQueue, true);
|
AudioQueueDispose(_audioQueue, true);
|
||||||
_audioQueue = IntPtr.Zero;
|
_audioQueue = nint.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_gcHandle.IsAllocated)
|
if (_gcHandle.IsAllocated)
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
|
|||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
int* frameCountPtr = &nativeFrameCount;
|
int* frameCountPtr = &nativeFrameCount;
|
||||||
IntPtr* arenasPtr = &arenas;
|
nint* arenasPtr = &arenas;
|
||||||
CheckError(soundio_outstream_begin_write(_context, (nint)arenasPtr, (nint)frameCountPtr));
|
CheckError(soundio_outstream_begin_write(_context, (nint)arenasPtr, (nint)frameCountPtr));
|
||||||
|
|
||||||
frameCount = *frameCountPtr;
|
frameCount = *frameCountPtr;
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ namespace ARMeilleure.Common
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base address for the page.
|
/// Base address for the page.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly IntPtr Address;
|
public readonly nint Address;
|
||||||
|
|
||||||
public AddressTablePage(bool isSparse, IntPtr address)
|
public AddressTablePage(bool isSparse, nint address)
|
||||||
{
|
{
|
||||||
IsSparse = isSparse;
|
IsSparse = isSparse;
|
||||||
Address = address;
|
Address = address;
|
||||||
@@ -47,20 +47,20 @@ namespace ARMeilleure.Common
|
|||||||
public readonly SparseMemoryBlock Block;
|
public readonly SparseMemoryBlock Block;
|
||||||
private readonly TrackingEventDelegate _trackingEvent;
|
private readonly TrackingEventDelegate _trackingEvent;
|
||||||
|
|
||||||
public TableSparseBlock(ulong size, Action<IntPtr> ensureMapped, PageInitDelegate pageInit)
|
public TableSparseBlock(ulong size, Action<nint> ensureMapped, PageInitDelegate pageInit)
|
||||||
{
|
{
|
||||||
SparseMemoryBlock block = new(size, pageInit, null);
|
SparseMemoryBlock block = new(size, pageInit, null);
|
||||||
|
|
||||||
_trackingEvent = (address, size, write) =>
|
_trackingEvent = (address, size, write) =>
|
||||||
{
|
{
|
||||||
ulong pointer = (ulong)block.Block.Pointer + address;
|
ulong pointer = (ulong)block.Block.Pointer + address;
|
||||||
ensureMapped((IntPtr)pointer);
|
ensureMapped((nint)pointer);
|
||||||
return pointer;
|
return pointer;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool added = NativeSignalHandler.AddTrackedRegion(
|
bool added = NativeSignalHandler.AddTrackedRegion(
|
||||||
(nuint)block.Block.Pointer,
|
(nuint)block.Block.Pointer,
|
||||||
(nuint)(block.Block.Pointer + (IntPtr)block.Block.Size),
|
(nuint)(block.Block.Pointer + (nint)block.Block.Size),
|
||||||
Marshal.GetFunctionPointerForDelegate(_trackingEvent));
|
Marshal.GetFunctionPointerForDelegate(_trackingEvent));
|
||||||
|
|
||||||
if (!added)
|
if (!added)
|
||||||
@@ -116,7 +116,7 @@ namespace ARMeilleure.Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IntPtr Base
|
public nint Base
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@@ -124,7 +124,7 @@ namespace ARMeilleure.Common
|
|||||||
|
|
||||||
lock (_pages)
|
lock (_pages)
|
||||||
{
|
{
|
||||||
return (IntPtr)GetRootPage();
|
return (nint)GetRootPage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,7 +240,7 @@ namespace ARMeilleure.Common
|
|||||||
|
|
||||||
long index = Levels[^1].GetValue(address);
|
long index = Levels[^1].GetValue(address);
|
||||||
|
|
||||||
EnsureMapped((IntPtr)(page + index));
|
EnsureMapped((nint)(page + index));
|
||||||
|
|
||||||
return ref page[index];
|
return ref page[index];
|
||||||
}
|
}
|
||||||
@@ -284,7 +284,7 @@ namespace ARMeilleure.Common
|
|||||||
/// Ensure the given pointer is mapped in any overlapping sparse reservations.
|
/// Ensure the given pointer is mapped in any overlapping sparse reservations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ptr">Pointer to be mapped</param>
|
/// <param name="ptr">Pointer to be mapped</param>
|
||||||
private void EnsureMapped(IntPtr ptr)
|
private void EnsureMapped(nint ptr)
|
||||||
{
|
{
|
||||||
if (Sparse)
|
if (Sparse)
|
||||||
{
|
{
|
||||||
@@ -299,7 +299,7 @@ namespace ARMeilleure.Common
|
|||||||
{
|
{
|
||||||
SparseMemoryBlock sparse = reserved.Block;
|
SparseMemoryBlock sparse = reserved.Block;
|
||||||
|
|
||||||
if (ptr >= sparse.Block.Pointer && ptr < sparse.Block.Pointer + (IntPtr)sparse.Block.Size)
|
if (ptr >= sparse.Block.Pointer && ptr < sparse.Block.Pointer + (nint)sparse.Block.Size)
|
||||||
{
|
{
|
||||||
sparse.EnsureMapped((ulong)(ptr - sparse.Block.Pointer));
|
sparse.EnsureMapped((ulong)(ptr - sparse.Block.Pointer));
|
||||||
|
|
||||||
@@ -319,15 +319,15 @@ namespace ARMeilleure.Common
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="level">Level to get the fill value for</param>
|
/// <param name="level">Level to get the fill value for</param>
|
||||||
/// <returns>The fill value</returns>
|
/// <returns>The fill value</returns>
|
||||||
private IntPtr GetFillValue(int level)
|
private nint GetFillValue(int level)
|
||||||
{
|
{
|
||||||
if (_fillBottomLevel != null && level == Levels.Length - 2)
|
if (_fillBottomLevel != null && level == Levels.Length - 2)
|
||||||
{
|
{
|
||||||
return (IntPtr)_fillBottomLevelPtr;
|
return (nint)_fillBottomLevelPtr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return IntPtr.Zero;
|
return nint.Zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,7 +379,7 @@ namespace ARMeilleure.Common
|
|||||||
/// <param name="fill">Fill value</param>
|
/// <param name="fill">Fill value</param>
|
||||||
/// <param name="leaf"><see langword="true"/> if leaf; otherwise <see langword="false"/></param>
|
/// <param name="leaf"><see langword="true"/> if leaf; otherwise <see langword="false"/></param>
|
||||||
/// <returns>Allocated block</returns>
|
/// <returns>Allocated block</returns>
|
||||||
private IntPtr Allocate<T>(int length, T fill, bool leaf) where T : unmanaged
|
private nint Allocate<T>(int length, T fill, bool leaf) where T : unmanaged
|
||||||
{
|
{
|
||||||
int size = sizeof(T) * length;
|
int size = sizeof(T) * length;
|
||||||
|
|
||||||
@@ -405,7 +405,7 @@ namespace ARMeilleure.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
page = new AddressTablePage(true, block.Block.Pointer + (IntPtr)_sparseReservedOffset);
|
page = new AddressTablePage(true, block.Block.Pointer + (nint)_sparseReservedOffset);
|
||||||
|
|
||||||
_sparseReservedOffset += (ulong)size;
|
_sparseReservedOffset += (ulong)size;
|
||||||
|
|
||||||
@@ -413,7 +413,7 @@ namespace ARMeilleure.Common
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IntPtr address = (IntPtr)NativeAllocator.Instance.Allocate((uint)size);
|
nint address = (nint)NativeAllocator.Instance.Allocate((uint)size);
|
||||||
page = new AddressTablePage(false, address);
|
page = new AddressTablePage(false, address);
|
||||||
|
|
||||||
Span<T> span = new((void*)page.Address, length);
|
Span<T> span = new((void*)page.Address, length);
|
||||||
|
|||||||
@@ -658,7 +658,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
bool canImport = Storage.Info.IsLinear && Storage.Info.Stride >= Storage.Info.Width * Storage.Info.FormatInfo.BytesPerPixel;
|
bool canImport = Storage.Info.IsLinear && Storage.Info.Stride >= Storage.Info.Width * Storage.Info.FormatInfo.BytesPerPixel;
|
||||||
|
|
||||||
IntPtr hostPointer = canImport ? _physicalMemory.GetHostPointer(Storage.Range) : 0;
|
nint hostPointer = canImport ? _physicalMemory.GetHostPointer(Storage.Range) : 0;
|
||||||
|
|
||||||
if (hostPointer != 0 && _context.Renderer.PrepareHostMapping(hostPointer, Storage.Size))
|
if (hostPointer != 0 && _context.Renderer.PrepareHostMapping(hostPointer, Storage.Size))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -114,7 +115,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
cbs.AddDependant(this);
|
cbs.AddDependant(this);
|
||||||
|
|
||||||
// We need to add a dependency on the command buffer to all objects this object
|
// We need to add a dependency on the command buffer to all objects this object
|
||||||
// references aswell.
|
// references as well.
|
||||||
if (_referencedObjs != null)
|
if (_referencedObjs != null)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _referencedObjs.Length; i++)
|
for (int i = 0; i < _referencedObjs.Length; i++)
|
||||||
@@ -176,6 +177,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This can somehow become -1.
|
||||||
|
// Logger.Info?.PrintMsg(LogClass.Gpu, $"_referenceCount: {_referenceCount}");
|
||||||
Debug.Assert(_referenceCount >= 0);
|
Debug.Assert(_referenceCount >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
|||||||
|
|
||||||
public static void Initialize()
|
public static void Initialize()
|
||||||
{
|
{
|
||||||
IntPtr configSize = (nint)Marshal.SizeOf<MVKConfiguration>();
|
nint configSize = (nint)Marshal.SizeOf<MVKConfiguration>();
|
||||||
|
|
||||||
vkGetMoltenVKConfigurationMVK(nint.Zero, out MVKConfiguration config, configSize);
|
vkGetMoltenVKConfigurationMVK(nint.Zero, out MVKConfiguration config, configSize);
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
enabledExtensions = enabledExtensions.Append(ExtDebugUtils.ExtensionName).ToArray();
|
enabledExtensions = enabledExtensions.Append(ExtDebugUtils.ExtensionName).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
IntPtr appName = Marshal.StringToHGlobalAnsi(AppName);
|
nint appName = Marshal.StringToHGlobalAnsi(AppName);
|
||||||
|
|
||||||
ApplicationInfo applicationInfo = new()
|
ApplicationInfo applicationInfo = new()
|
||||||
{
|
{
|
||||||
@@ -166,7 +166,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
internal static DeviceInfo[] GetSuitablePhysicalDevices(Vk api)
|
internal static DeviceInfo[] GetSuitablePhysicalDevices(Vk api)
|
||||||
{
|
{
|
||||||
IntPtr appName = Marshal.StringToHGlobalAnsi(AppName);
|
nint appName = Marshal.StringToHGlobalAnsi(AppName);
|
||||||
|
|
||||||
ApplicationInfo applicationInfo = new()
|
ApplicationInfo applicationInfo = new()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1059,7 +1059,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool AreKeysAlredyPresent(string pathToCheck)
|
public static bool AreKeysAlreadyPresent(string pathToCheck)
|
||||||
{
|
{
|
||||||
string[] fileNames = ["prod.keys", "title.keys", "console.keys", "dev.keys"];
|
string[] fileNames = ["prod.keys", "title.keys", "console.keys", "dev.keys"];
|
||||||
foreach (string file in fileNames)
|
foreach (string file in fileNames)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
|||||||
|
|
||||||
public bool Blocking { get => Socket.Blocking; set => Socket.Blocking = value; }
|
public bool Blocking { get => Socket.Blocking; set => Socket.Blocking = value; }
|
||||||
|
|
||||||
public nint Handle => IntPtr.Zero;
|
public nint Handle => nint.Zero;
|
||||||
|
|
||||||
public IPEndPoint RemoteEndPoint => Socket.RemoteEndPoint as IPEndPoint;
|
public IPEndPoint RemoteEndPoint => Socket.RemoteEndPoint as IPEndPoint;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using Ryujinx.HLE.Loaders.Executables;
|
|||||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
@@ -27,10 +28,15 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
|
|
||||||
private ulong _latestPid;
|
private ulong _latestPid;
|
||||||
|
|
||||||
public ProcessResult ActiveApplication
|
public ProcessResult? ActiveApplication
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
return _processesByPid.GetValueOrDefault(_latestPid);
|
||||||
|
|
||||||
|
// Using this if statement locks up the UI and prevents a new game from loading.
|
||||||
|
// Haven't quite deduced why yet.
|
||||||
|
|
||||||
if (!_processesByPid.TryGetValue(_latestPid, out ProcessResult value))
|
if (!_processesByPid.TryGetValue(_latestPid, out ProcessResult value))
|
||||||
throw new RyujinxException(
|
throw new RyujinxException(
|
||||||
$"The HLE Process map did not have a process with ID {_latestPid}. Are you missing firmware?");
|
$"The HLE Process map did not have a process with ID {_latestPid}. Are you missing firmware?");
|
||||||
@@ -144,7 +150,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
public bool LoadUnpackedNca(string exeFsDirPath, string romFsPath = null)
|
public bool LoadUnpackedNca(string exeFsDirPath, string romFsPath = null)
|
||||||
{
|
{
|
||||||
ProcessResult processResult = new LocalFileSystem(exeFsDirPath).Load(_device, romFsPath);
|
ProcessResult processResult = new LocalFileSystem(exeFsDirPath).Load(_device, romFsPath);
|
||||||
|
|
||||||
if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult))
|
if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult))
|
||||||
{
|
{
|
||||||
if (processResult.Start(_device))
|
if (processResult.Start(_device))
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using LibHac.Ns;
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.HOS.SystemState;
|
using Ryujinx.HLE.HOS.SystemState;
|
||||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
|
||||||
using Ryujinx.Horizon.Common;
|
using Ryujinx.Horizon.Common;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Loaders.Processes
|
namespace Ryujinx.HLE.Loaders.Processes
|
||||||
@@ -52,6 +51,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
|
|
||||||
if (metaLoader is not null)
|
if (metaLoader is not null)
|
||||||
{
|
{
|
||||||
|
Logger.Info?.Print(LogClass.Application,$"metaLoader: {metaLoader}");
|
||||||
ulong programId = metaLoader.ProgramId;
|
ulong programId = metaLoader.ProgramId;
|
||||||
|
|
||||||
Name = ApplicationControlProperties.Title[(int)titleLanguage].NameString.ToString();
|
Name = ApplicationControlProperties.Title[(int)titleLanguage].NameString.ToString();
|
||||||
@@ -71,8 +71,15 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
ProgramId = programId;
|
ProgramId = programId;
|
||||||
ProgramIdText = $"{programId:x16}";
|
ProgramIdText = $"{programId:x16}";
|
||||||
Is64Bit = metaLoader.IsProgram64Bit;
|
Is64Bit = metaLoader.IsProgram64Bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application,$"metaLoader is null !!!");
|
||||||
|
ProcessId = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiskCacheEnabled = diskCacheEnabled;
|
DiskCacheEnabled = diskCacheEnabled;
|
||||||
AllowCodeMemoryForJit = allowCodeMemoryForJit;
|
AllowCodeMemoryForJit = allowCodeMemoryForJit;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
{
|
{
|
||||||
SplitForMap((ulong)location, (ulong)size, srcOffset);
|
SplitForMap((ulong)location, (ulong)size, srcOffset);
|
||||||
|
|
||||||
IntPtr ptr = WindowsApi.MapViewOfFile3(
|
nint ptr = WindowsApi.MapViewOfFile3(
|
||||||
sharedMemory,
|
sharedMemory,
|
||||||
WindowsApi.CurrentProcessHandle,
|
WindowsApi.CurrentProcessHandle,
|
||||||
location,
|
location,
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ namespace Ryujinx.Tests.Memory
|
|||||||
|
|
||||||
// Create some info to be used for managing the native writing loop.
|
// Create some info to be used for managing the native writing loop.
|
||||||
int stateSize = Unsafe.SizeOf<NativeWriteLoopState>();
|
int stateSize = Unsafe.SizeOf<NativeWriteLoopState>();
|
||||||
IntPtr statePtr = Marshal.AllocHGlobal(stateSize);
|
nint statePtr = Marshal.AllocHGlobal(stateSize);
|
||||||
Unsafe.InitBlockUnaligned((void*)statePtr, 0, (uint)stateSize);
|
Unsafe.InitBlockUnaligned((void*)statePtr, 0, (uint)stateSize);
|
||||||
|
|
||||||
ref NativeWriteLoopState writeLoopState = ref Unsafe.AsRef<NativeWriteLoopState>((void*)statePtr);
|
ref NativeWriteLoopState writeLoopState = ref Unsafe.AsRef<NativeWriteLoopState>((void*)statePtr);
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ using VSyncMode = Ryujinx.Common.Configuration.VSyncMode;
|
|||||||
|
|
||||||
namespace Ryujinx.Ava.Systems
|
namespace Ryujinx.Ava.Systems
|
||||||
{
|
{
|
||||||
internal class AppHost
|
internal class AppHost : IDisposable
|
||||||
{
|
{
|
||||||
private const int CursorHideIdleTime = 5; // Hide Cursor seconds.
|
private const int CursorHideIdleTime = 5; // Hide Cursor seconds.
|
||||||
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
||||||
@@ -438,7 +438,7 @@ namespace Ryujinx.Ava.Systems
|
|||||||
|
|
||||||
SaveBitmapAsPng(bitmapToSave, path);
|
SaveBitmapAsPng(bitmapToSave, path);
|
||||||
|
|
||||||
Logger.Notice.Print(LogClass.Application, $"Screenshot saved to {path}", "Screenshot");
|
Logger.Notice.Print(LogClass.Application, $"Screenshot saved to '{path}'.", "Screenshot");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -611,27 +611,40 @@ namespace Ryujinx.Ava.Systems
|
|||||||
|
|
||||||
_isActive = false;
|
_isActive = false;
|
||||||
|
|
||||||
// NOTE: The render loop is allowed to stay alive until the renderer itself is disposed, as it may handle resource dispose.
|
|
||||||
// We only need to wait for all commands submitted during the main gpu loop to be processed.
|
|
||||||
_gpuDoneEvent.WaitOne();
|
|
||||||
_gpuDoneEvent.Dispose();
|
|
||||||
|
|
||||||
DisplaySleep.Restore();
|
DisplaySleep.Restore();
|
||||||
|
|
||||||
NpadManager.Dispose();
|
NpadManager.Dispose();
|
||||||
TouchScreenManager.Dispose();
|
TouchScreenManager.Dispose();
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
|
// NOTE: The render loop is allowed to stay alive until the renderer itself is disposed, as it may handle resource dispose.
|
||||||
|
// We only need to wait for all commands submitted during the main gpu loop to be processed.
|
||||||
|
// If the GPU has no work and is cancelled, we need to handle that as well.
|
||||||
|
|
||||||
|
WaitHandle.WaitAny(new[] { _gpuDoneEvent, _gpuCancellationTokenSource.Token.WaitHandle });
|
||||||
|
_gpuCancellationTokenSource.Dispose();
|
||||||
|
|
||||||
|
// Waiting for work to be finished before we dispose.
|
||||||
|
if (_renderingStarted)
|
||||||
|
{
|
||||||
|
Device.Gpu.WaitUntilGpuReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
_gpuDoneEvent.Dispose();
|
||||||
|
|
||||||
DisposeGpu();
|
DisposeGpu();
|
||||||
|
|
||||||
AppExit?.Invoke(this, EventArgs.Empty);
|
AppExit?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Dispose()
|
// MUST be public to inherit from IDisposable
|
||||||
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (Device.Processes != null)
|
if (Device.Processes != null)
|
||||||
MainWindowViewModel.UpdateGameMetadata(Device.Processes.ActiveApplication.ProgramIdText, _playTimer.Elapsed);
|
{
|
||||||
|
MainWindowViewModel.UpdateGameMetadata(Device.Processes.ActiveApplication?.ProgramIdText,
|
||||||
|
_playTimer.Elapsed);
|
||||||
|
}
|
||||||
|
|
||||||
ConfigurationState.Instance.System.IgnoreMissingServices.Event -= UpdateIgnoreMissingServicesState;
|
ConfigurationState.Instance.System.IgnoreMissingServices.Event -= UpdateIgnoreMissingServicesState;
|
||||||
ConfigurationState.Instance.Graphics.AspectRatio.Event -= UpdateAspectRatioState;
|
ConfigurationState.Instance.Graphics.AspectRatio.Event -= UpdateAspectRatioState;
|
||||||
ConfigurationState.Instance.System.EnableDockedMode.Event -= UpdateDockedModeState;
|
ConfigurationState.Instance.System.EnableDockedMode.Event -= UpdateDockedModeState;
|
||||||
@@ -646,7 +659,6 @@ namespace Ryujinx.Ava.Systems
|
|||||||
_topLevel.PointerExited -= TopLevel_PointerExited;
|
_topLevel.PointerExited -= TopLevel_PointerExited;
|
||||||
|
|
||||||
_gpuCancellationTokenSource.Cancel();
|
_gpuCancellationTokenSource.Cancel();
|
||||||
_gpuCancellationTokenSource.Dispose();
|
|
||||||
|
|
||||||
_chrono.Stop();
|
_chrono.Stop();
|
||||||
_playTimer.Stop();
|
_playTimer.Stop();
|
||||||
@@ -672,6 +684,12 @@ namespace Ryujinx.Ava.Systems
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// No use waiting on something that never started work
|
||||||
|
if (_renderingStarted)
|
||||||
|
{
|
||||||
|
Device.Gpu.WaitUntilGpuReady();
|
||||||
|
}
|
||||||
|
|
||||||
Device.DisposeGpu();
|
Device.DisposeGpu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -686,7 +704,7 @@ namespace Ryujinx.Ava.Systems
|
|||||||
_cursorState = CursorStates.ForceChangeCursor;
|
_cursorState = CursorStates.ForceChangeCursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> LoadGuestApplication(BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
public async Task LoadGuestApplication(CancellationTokenSource cts, BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||||
{
|
{
|
||||||
DiscordIntegrationModule.GuestAppStartedAt = Timestamps.Now;
|
DiscordIntegrationModule.GuestAppStartedAt = Timestamps.Now;
|
||||||
|
|
||||||
@@ -715,7 +733,8 @@ namespace Ryujinx.Ava.Systems
|
|||||||
await UserErrorDialog.ShowUserErrorDialog(userError);
|
await UserErrorDialog.ShowUserErrorDialog(userError);
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
cts.Cancel();
|
||||||
|
throw new OperationCanceledException(cts.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -724,10 +743,11 @@ namespace Ryujinx.Ava.Systems
|
|||||||
await UserErrorDialog.ShowUserErrorDialog(userError);
|
await UserErrorDialog.ShowUserErrorDialog(userError);
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
cts.Cancel();
|
||||||
|
throw new OperationCanceledException(cts.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell the user that we installed a firmware for them.
|
// Tell the user that we installed firmware for them.
|
||||||
if (userError is UserError.NoFirmware)
|
if (userError is UserError.NoFirmware)
|
||||||
{
|
{
|
||||||
firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||||
@@ -747,7 +767,8 @@ namespace Ryujinx.Ava.Systems
|
|||||||
await UserErrorDialog.ShowUserErrorDialog(userError);
|
await UserErrorDialog.ShowUserErrorDialog(userError);
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
cts.Cancel();
|
||||||
|
throw new OperationCanceledException(cts.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -762,7 +783,8 @@ namespace Ryujinx.Ava.Systems
|
|||||||
{
|
{
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
cts.Cancel();
|
||||||
|
throw new OperationCanceledException(cts.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Directory.Exists(ApplicationPath))
|
else if (Directory.Exists(ApplicationPath))
|
||||||
@@ -782,20 +804,24 @@ namespace Ryujinx.Ava.Systems
|
|||||||
|
|
||||||
if (!Device.LoadCart(ApplicationPath, romFsFiles[0]))
|
if (!Device.LoadCart(ApplicationPath, romFsFiles[0]))
|
||||||
{
|
{
|
||||||
|
await ContentDialogHelper.CreateErrorDialog(
|
||||||
|
"Please specify an unpacked game directory with a valid exefs or NSO/NRO.");
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
cts.Cancel();
|
||||||
|
throw new OperationCanceledException(cts.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Info?.Print(LogClass.Application, "Loading as cart WITHOUT RomFS.");
|
Logger.Info?.Print(LogClass.Application, "Loading as cart WITHOUT RomFS.");
|
||||||
|
|
||||||
if (!Device.LoadCart(ApplicationPath))
|
if (!Device.LoadCart(ApplicationPath))
|
||||||
{
|
{
|
||||||
|
await ContentDialogHelper.CreateErrorDialog(
|
||||||
|
"Please specify an unpacked game directory with a valid exefs or NSO/NRO.");
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
cts.Cancel();
|
||||||
return false;
|
throw new OperationCanceledException(cts.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -813,7 +839,8 @@ namespace Ryujinx.Ava.Systems
|
|||||||
{
|
{
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
cts.Cancel();
|
||||||
|
throw new OperationCanceledException(cts.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -826,7 +853,8 @@ namespace Ryujinx.Ava.Systems
|
|||||||
{
|
{
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
cts.Cancel();
|
||||||
|
throw new OperationCanceledException(cts.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -840,7 +868,8 @@ namespace Ryujinx.Ava.Systems
|
|||||||
{
|
{
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
cts.Cancel();
|
||||||
|
throw new OperationCanceledException(cts.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -855,7 +884,8 @@ namespace Ryujinx.Ava.Systems
|
|||||||
{
|
{
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
cts.Cancel();
|
||||||
|
throw new OperationCanceledException(cts.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ArgumentOutOfRangeException)
|
catch (ArgumentOutOfRangeException)
|
||||||
@@ -864,7 +894,8 @@ namespace Ryujinx.Ava.Systems
|
|||||||
|
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
cts.Cancel();
|
||||||
|
throw new OperationCanceledException(cts.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -873,19 +904,18 @@ namespace Ryujinx.Ava.Systems
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file.");
|
Logger.Warning?.Print(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NSO/NRO file.");
|
||||||
|
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
cts.Cancel();
|
||||||
|
throw new OperationCanceledException(cts.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText,
|
ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText,
|
||||||
appMetadata => appMetadata.UpdatePreGame()
|
appMetadata => appMetadata.UpdatePreGame()
|
||||||
);
|
);
|
||||||
_playTimer.Start();
|
_playTimer.Start();
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Resume()
|
internal void Resume()
|
||||||
@@ -895,7 +925,7 @@ namespace Ryujinx.Ava.Systems
|
|||||||
_viewModel.IsPaused = false;
|
_viewModel.IsPaused = false;
|
||||||
_playTimer.Start();
|
_playTimer.Start();
|
||||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowOldUI);
|
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowOldUI);
|
||||||
Logger.Info?.Print(LogClass.Emulation, "Emulation was resumed");
|
Logger.Info?.Print(LogClass.Emulation, "Emulation was resumed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Pause()
|
internal void Pause()
|
||||||
@@ -905,7 +935,7 @@ namespace Ryujinx.Ava.Systems
|
|||||||
_viewModel.IsPaused = true;
|
_viewModel.IsPaused = true;
|
||||||
_playTimer.Stop();
|
_playTimer.Stop();
|
||||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowOldUI, LocaleManager.Instance[LocaleKeys.Paused]);
|
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowOldUI, LocaleManager.Instance[LocaleKeys.Paused]);
|
||||||
Logger.Info?.Print(LogClass.Emulation, "Emulation was paused");
|
Logger.Info?.Print(LogClass.Emulation, "Emulation was paused.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitEmulatedSwitch()
|
private void InitEmulatedSwitch()
|
||||||
@@ -1104,7 +1134,9 @@ namespace Ryujinx.Ava.Systems
|
|||||||
// Make sure all commands in the run loop are fully executed before leaving the loop.
|
// Make sure all commands in the run loop are fully executed before leaving the loop.
|
||||||
if (Device.Gpu.Renderer is ThreadedRenderer threaded)
|
if (Device.Gpu.Renderer is ThreadedRenderer threaded)
|
||||||
{
|
{
|
||||||
|
Logger.Info?.PrintMsg(LogClass.Gpu, "Flushing threaded commands...");
|
||||||
threaded.FlushThreadedCommands();
|
threaded.FlushThreadedCommands();
|
||||||
|
Logger.Info?.PrintMsg(LogClass.Gpu, "Flushed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
_gpuDoneEvent.Set();
|
_gpuDoneEvent.Set();
|
||||||
|
|||||||
@@ -849,7 +849,8 @@ namespace Ryujinx.Ava.Systems.AppLibrary
|
|||||||
|
|
||||||
foreach (ApplicationData installedApplication in Applications.Items)
|
foreach (ApplicationData installedApplication in Applications.Items)
|
||||||
{
|
{
|
||||||
temporary += LoadAndSaveMetaData(installedApplication.IdString).TimePlayed;
|
// this should always exist... should...
|
||||||
|
temporary += LoadAndSaveMetaData(installedApplication.IdString).Value.TimePlayed;
|
||||||
}
|
}
|
||||||
|
|
||||||
TotalTimePlayed = temporary;
|
TotalTimePlayed = temporary;
|
||||||
@@ -1159,15 +1160,22 @@ namespace Ryujinx.Ava.Systems.AppLibrary
|
|||||||
ApplicationCountUpdated?.Invoke(null, e);
|
ApplicationCountUpdated?.Invoke(null, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ApplicationMetadata LoadAndSaveMetaData(string titleId, Action<ApplicationMetadata> modifyFunction = null)
|
public static Gommon.Optional<ApplicationMetadata> LoadAndSaveMetaData(string titleId, Action<ApplicationMetadata> modifyFunction = null)
|
||||||
{
|
{
|
||||||
|
if (titleId is null)
|
||||||
|
{
|
||||||
|
Logger.Warning?.PrintMsg(LogClass.Application, "Cannot save metadata because title ID is invalid.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
string metadataFolder = Path.Combine(AppDataManager.GamesDirPath, titleId, "gui");
|
string metadataFolder = Path.Combine(AppDataManager.GamesDirPath, titleId, "gui");
|
||||||
string metadataFile = Path.Combine(metadataFolder, "metadata.json");
|
string metadataFile = Path.Combine(metadataFolder, "metadata.json");
|
||||||
|
|
||||||
ApplicationMetadata appMetadata;
|
ApplicationMetadata appMetadata;
|
||||||
|
|
||||||
if (!File.Exists(metadataFile))
|
if (!File.Exists(metadataFile))
|
||||||
{
|
{
|
||||||
|
Logger.Info?.Print(LogClass.Application, $"Metadata file does not exist. Creating metadata for {titleId}...");
|
||||||
Directory.CreateDirectory(metadataFolder);
|
Directory.CreateDirectory(metadataFolder);
|
||||||
|
|
||||||
appMetadata = new ApplicationMetadata();
|
appMetadata = new ApplicationMetadata();
|
||||||
@@ -1177,12 +1185,12 @@ namespace Ryujinx.Ava.Systems.AppLibrary
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Logger.Debug?.Print(LogClass.Application, $"Deserializing metadata for {titleId}...");
|
||||||
appMetadata = JsonHelper.DeserializeFromFile(metadataFile, _serializerContext.ApplicationMetadata);
|
appMetadata = JsonHelper.DeserializeFromFile(metadataFile, _serializerContext.ApplicationMetadata);
|
||||||
}
|
}
|
||||||
catch (JsonException)
|
catch (JsonException)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, $"Failed to parse metadata json for {titleId}. Loading defaults.");
|
Logger.Warning?.Print(LogClass.Application, $"Failed to parse metadata json for {titleId}. Loading defaults.");
|
||||||
|
|
||||||
appMetadata = new ApplicationMetadata();
|
appMetadata = new ApplicationMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ namespace Ryujinx.Ava.Systems
|
|||||||
|
|
||||||
public static void Use(Optional<string> titleId)
|
public static void Use(Optional<string> titleId)
|
||||||
{
|
{
|
||||||
if (titleId.TryGet(out string tid))
|
if (titleId.TryGet(out string tid) && Switch.Shared.Processes.ActiveApplication is not null)
|
||||||
SwitchToPlayingState(
|
SwitchToPlayingState(
|
||||||
ApplicationLibrary.LoadAndSaveMetaData(tid),
|
ApplicationLibrary.LoadAndSaveMetaData(tid),
|
||||||
Switch.Shared.Processes.ActiveApplication
|
Switch.Shared.Processes.ActiveApplication
|
||||||
|
|||||||
@@ -57,8 +57,15 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ApplicationMetadata appMetadata = ApplicationLibrary.LoadAndSaveMetaData(TitleIdString);
|
Gommon.Optional<ApplicationMetadata> appMetadata = ApplicationLibrary.LoadAndSaveMetaData(TitleIdString);
|
||||||
Title = appMetadata.Title ?? TitleIdString;
|
if (appMetadata != null)
|
||||||
|
{
|
||||||
|
Title = appMetadata.Value.Title ?? TitleIdString;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Title = "<INVALID>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
|
|||||||
@@ -1029,7 +1029,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
string dialogMessage =
|
string dialogMessage =
|
||||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallMessage);
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallMessage);
|
||||||
|
|
||||||
if (ContentManager.AreKeysAlredyPresent(systemDirectory))
|
if (ContentManager.AreKeysAlreadyPresent(systemDirectory))
|
||||||
{
|
{
|
||||||
dialogMessage +=
|
dialogMessage +=
|
||||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys
|
||||||
@@ -1703,11 +1703,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
Logger.RestartTime();
|
Logger.RestartTime();
|
||||||
|
|
||||||
SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(application.Path,
|
|
||||||
ConfigurationState.Instance.System.Language, application.Id);
|
|
||||||
|
|
||||||
PrepareLoadScreen();
|
|
||||||
|
|
||||||
RendererHostControl = new RendererHost();
|
RendererHostControl = new RendererHost();
|
||||||
|
|
||||||
AppHost = new AppHost(
|
AppHost = new AppHost(
|
||||||
@@ -1721,18 +1716,34 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
UserChannelPersistence,
|
UserChannelPersistence,
|
||||||
this,
|
this,
|
||||||
TopLevel);
|
TopLevel);
|
||||||
|
|
||||||
|
CancellationTokenSource cts = new CancellationTokenSource();
|
||||||
|
|
||||||
if (!await AppHost.LoadGuestApplication(customNacpData))
|
try
|
||||||
{
|
{
|
||||||
|
await AppHost.LoadGuestApplication(cts, customNacpData);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException exception)
|
||||||
|
{
|
||||||
|
Logger.Info?.Print(LogClass.Application,
|
||||||
|
"LoadGuestApplication was interrupted !!! " + exception.Message);
|
||||||
AppHost.DisposeContext();
|
AppHost.DisposeContext();
|
||||||
AppHost = null;
|
AppHost = null;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
cts.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
CanUpdate = false;
|
CanUpdate = false;
|
||||||
|
|
||||||
application.Name ??= AppHost.Device.Processes.ActiveApplication.Name;
|
application.Name ??= AppHost.Device.Processes.ActiveApplication.Name;
|
||||||
|
|
||||||
|
SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(application.Path,
|
||||||
|
ConfigurationState.Instance.System.Language, application.Id);
|
||||||
|
|
||||||
|
PrepareLoadScreen();
|
||||||
|
|
||||||
LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, application.Name);
|
LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, application.Name);
|
||||||
|
|
||||||
@@ -1754,9 +1765,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
RendererHostControl.Focus();
|
RendererHostControl.Focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
public static void UpdateGameMetadata(string titleId, TimeSpan playTime)
|
public static void UpdateGameMetadata(string titleId, TimeSpan playTime)
|
||||||
=> ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata => appMetadata.UpdatePostGame(playTime));
|
=> ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata => appMetadata.UpdatePostGame(playTime));
|
||||||
|
|
||||||
public void RefreshFirmwareStatus()
|
public void RefreshFirmwareStatus()
|
||||||
{
|
{
|
||||||
SystemVersion version = null;
|
SystemVersion version = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user