mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-07-24 15:37:10 +02:00
NvServices refactoring (#120)
* Initial implementation of NvMap/NvHostCtrl * More work on NvHostCtrl * Refactoring of nvservices, move GPU Vmm, make Vmm per-process, refactor most gpu devices, move Gpu to Core, fix CbBind * Implement GetGpuTime, support CancelSynchronization, fix issue on InsertWaitingMutex, proper double buffering support (again, not working properly for commercial games, only hb) * Try to fix perf regression reading/writing textures, moved syncpts and events to a UserCtx class, delete global state when the process exits, other minor tweaks * Remove now unused code, add comment about probably wrong result codes
This commit is contained in:
parent
4419e8d6b4
commit
34037701c7
75 changed files with 2472 additions and 1440 deletions
|
@ -7,6 +7,8 @@ namespace Ryujinx.Core.OsHle.Kernel
|
|||
public const int InvalidMemRange = 110;
|
||||
public const int InvalidHandle = 114;
|
||||
public const int Timeout = 117;
|
||||
public const int Canceled = 118;
|
||||
public const int CountOutOfRange = 119;
|
||||
public const int InvalidInfo = 120;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,8 @@ using Ryujinx.Core.Logging;
|
|||
using Ryujinx.Core.OsHle.Handles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Kernel
|
||||
{
|
||||
|
@ -18,12 +20,16 @@ namespace Ryujinx.Core.OsHle.Kernel
|
|||
private Process Process;
|
||||
private AMemory Memory;
|
||||
|
||||
private ConcurrentDictionary<KThread, AutoResetEvent> SyncWaits;
|
||||
|
||||
private object CondVarLock;
|
||||
|
||||
private HashSet<(HSharedMem, long)> MappedSharedMems;
|
||||
|
||||
private ulong CurrentHeapSize;
|
||||
|
||||
private const uint SelfHandle = 0xffff8001;
|
||||
|
||||
private static Random Rng;
|
||||
|
||||
public SvcHandler(Switch Ns, Process Process)
|
||||
|
@ -51,6 +57,7 @@ namespace Ryujinx.Core.OsHle.Kernel
|
|||
{ 0x16, SvcCloseHandle },
|
||||
{ 0x17, SvcResetSignal },
|
||||
{ 0x18, SvcWaitSynchronization },
|
||||
{ 0x19, SvcCancelSynchronization },
|
||||
{ 0x1a, SvcArbitrateLock },
|
||||
{ 0x1b, SvcArbitrateUnlock },
|
||||
{ 0x1c, SvcWaitProcessWideKeyAtomic },
|
||||
|
@ -70,6 +77,8 @@ namespace Ryujinx.Core.OsHle.Kernel
|
|||
this.Process = Process;
|
||||
this.Memory = Process.Memory;
|
||||
|
||||
SyncWaits = new ConcurrentDictionary<KThread, AutoResetEvent>();
|
||||
|
||||
CondVarLock = new object();
|
||||
|
||||
MappedSharedMems = new HashSet<(HSharedMem, long)>();
|
||||
|
@ -100,6 +109,18 @@ namespace Ryujinx.Core.OsHle.Kernel
|
|||
}
|
||||
}
|
||||
|
||||
private KThread GetThread(long Tpidr, int Handle)
|
||||
{
|
||||
if ((uint)Handle == SelfHandle)
|
||||
{
|
||||
return Process.GetThread(Tpidr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Process.HandleTable.GetData<KThread>(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Ryujinx.Core.OsHle.Kernel
|
|||
|
||||
if (Obj == null)
|
||||
{
|
||||
Ns.Log.PrintWarning(LogClass.KernelSvc, $"Tried to CloseHandle on invalid handle 0x{Handle:x8}!");
|
||||
Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
|
@ -88,9 +88,21 @@ namespace Ryujinx.Core.OsHle.Kernel
|
|||
int HandlesCount = (int)ThreadState.X2;
|
||||
ulong Timeout = ThreadState.X3;
|
||||
|
||||
Ns.Log.PrintDebug(LogClass.KernelSvc,
|
||||
"HandlesPtr = " + HandlesPtr .ToString("x16") + ", " +
|
||||
"HandlesCount = " + HandlesCount.ToString("x8") + ", " +
|
||||
"Timeout = " + Timeout .ToString("x16"));
|
||||
|
||||
if ((uint)HandlesCount > 0x40)
|
||||
{
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.CountOutOfRange);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
|
||||
|
||||
WaitHandle[] Handles = new WaitHandle[HandlesCount];
|
||||
WaitHandle[] Handles = new WaitHandle[HandlesCount + 1];
|
||||
|
||||
for (int Index = 0; Index < HandlesCount; Index++)
|
||||
{
|
||||
|
@ -110,34 +122,73 @@ namespace Ryujinx.Core.OsHle.Kernel
|
|||
Handles[Index] = SyncObj.WaitEvent;
|
||||
}
|
||||
|
||||
Process.Scheduler.Suspend(CurrThread.ProcessorId);
|
||||
|
||||
int HandleIndex;
|
||||
|
||||
ulong Result = 0;
|
||||
|
||||
if (Timeout != ulong.MaxValue)
|
||||
using (AutoResetEvent WaitEvent = new AutoResetEvent(false))
|
||||
{
|
||||
HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout));
|
||||
if (!SyncWaits.TryAdd(CurrThread, WaitEvent))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Handles[HandlesCount] = WaitEvent;
|
||||
|
||||
Process.Scheduler.Suspend(CurrThread.ProcessorId);
|
||||
|
||||
int HandleIndex;
|
||||
|
||||
ulong Result = 0;
|
||||
|
||||
if (Timeout != ulong.MaxValue)
|
||||
{
|
||||
HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout));
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleIndex = WaitHandle.WaitAny(Handles);
|
||||
}
|
||||
|
||||
if (HandleIndex == WaitHandle.WaitTimeout)
|
||||
{
|
||||
Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||
}
|
||||
else if (HandleIndex == HandlesCount)
|
||||
{
|
||||
Result = MakeError(ErrorModule.Kernel, KernelErr.Canceled);
|
||||
}
|
||||
|
||||
SyncWaits.TryRemove(CurrThread, out _);
|
||||
|
||||
Process.Scheduler.Resume(CurrThread);
|
||||
|
||||
ThreadState.X0 = Result;
|
||||
|
||||
if (Result == 0)
|
||||
{
|
||||
ThreadState.X1 = (ulong)HandleIndex;
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
private void SvcCancelSynchronization(AThreadState ThreadState)
|
||||
{
|
||||
int ThreadHandle = (int)ThreadState.X0;
|
||||
|
||||
KThread Thread = GetThread(ThreadState.Tpidr, ThreadHandle);
|
||||
|
||||
if (Thread == null)
|
||||
{
|
||||
HandleIndex = WaitHandle.WaitAny(Handles);
|
||||
Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Process.Scheduler.Resume(CurrThread);
|
||||
|
||||
ThreadState.X0 = Result;
|
||||
|
||||
if (Result == 0)
|
||||
if (SyncWaits.TryRemove(Thread, out AutoResetEvent WaitEvent))
|
||||
{
|
||||
ThreadState.X1 = (ulong)HandleIndex;
|
||||
WaitEvent.Set();
|
||||
}
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
}
|
||||
|
||||
private void SvcGetSystemTick(AThreadState ThreadState)
|
||||
|
@ -190,13 +241,13 @@ namespace Ryujinx.Core.OsHle.Kernel
|
|||
|
||||
IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr);
|
||||
|
||||
IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr);
|
||||
long Result = IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr);
|
||||
|
||||
Thread.Yield();
|
||||
|
||||
Process.Scheduler.Resume(CurrThread);
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -191,6 +191,8 @@ namespace Ryujinx.Core.OsHle.Kernel
|
|||
|
||||
InsertWaitingMutexThread(OwnerThreadHandle, WaitThread);
|
||||
|
||||
Ns.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state...");
|
||||
|
||||
Process.Scheduler.EnterWait(CurrThread);
|
||||
}
|
||||
|
||||
|
@ -297,6 +299,8 @@ namespace Ryujinx.Core.OsHle.Kernel
|
|||
}
|
||||
}
|
||||
|
||||
Ns.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state...");
|
||||
|
||||
if (Timeout != ulong.MaxValue)
|
||||
{
|
||||
return Process.Scheduler.EnterWait(WaitThread, NsTimeConverter.GetTimeMs(Timeout));
|
||||
|
@ -407,7 +411,7 @@ namespace Ryujinx.Core.OsHle.Kernel
|
|||
|
||||
if (CurrThread != WaitThread)
|
||||
{
|
||||
if (WaitThread.NextCondVarThread != null)
|
||||
if (WaitThread.NextMutexThread != null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue