diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2018-04-25 23:11:26 -0300 |
|---|---|---|
| committer | gdkchan <gab.dark.100@gmail.com> | 2018-04-25 23:12:26 -0300 |
| commit | a38a72b0622f89897bdcd01b6d00ea6bc142c34f (patch) | |
| tree | 2025cdddaa7ef6769ac69c51eeede0924ffcba5f /Ryujinx.Core | |
| parent | 211f7f69db4d84b82caa3ee62d4ecdfbbd95604d (diff) | |
Some small sync primitive fixes, logging fixes, started to implement the 2D engine on the GPU, fixed DrawArrays, implemented a few more shader instructions, made a start on nvdrv refactor, etc...
Diffstat (limited to 'Ryujinx.Core')
| -rw-r--r-- | Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs | 154 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Ipc/IpcMessage.cs | 30 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Kernel/SvcHandler.cs | 2 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs | 52 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs | 27 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Services/Nv/NvChNvMap.cs | 31 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Services/Nv/NvMap.cs | 7 |
7 files changed, 212 insertions, 91 deletions
diff --git a/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs b/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs index c601d522..1c35b23c 100644 --- a/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs +++ b/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs @@ -14,23 +14,23 @@ namespace Ryujinx.Core.OsHle.Handles { public KThread Thread { get; private set; } - public ManualResetEvent SyncWaitEvent { get; private set; } - public AutoResetEvent SchedWaitEvent { get; private set; } + public bool IsActive { get; set; } - public bool Active { get; set; } - - public int SyncTimeout { get; set; } + public AutoResetEvent WaitSync { get; private set; } + public ManualResetEvent WaitActivity { get; private set; } + public AutoResetEvent WaitSched { get; private set; } public SchedulerThread(KThread Thread) { this.Thread = Thread; - SyncWaitEvent = new ManualResetEvent(true); - SchedWaitEvent = new AutoResetEvent(false); + IsActive = true; + + WaitSync = new AutoResetEvent(false); - Active = true; + WaitActivity = new ManualResetEvent(true); - SyncTimeout = 0; + WaitSched = new AutoResetEvent(false); } public void Dispose() @@ -42,8 +42,11 @@ namespace Ryujinx.Core.OsHle.Handles { if (Disposing) { - SyncWaitEvent.Dispose(); - SchedWaitEvent.Dispose(); + WaitSync.Dispose(); + + WaitActivity.Dispose(); + + WaitSched.Dispose(); } } } @@ -206,67 +209,56 @@ namespace Ryujinx.Core.OsHle.Handles throw new InvalidOperationException(); } - SchedThread.Active = Active; + SchedThread.IsActive = Active; - UpdateSyncWaitEvent(SchedThread); - - WaitIfNeeded(SchedThread); + if (Active) + { + SchedThread.WaitActivity.Set(); + } + else + { + SchedThread.WaitActivity.Reset(); + } } - public bool EnterWait(KThread Thread, int Timeout = -1) + public void EnterWait(KThread Thread) { if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) { throw new InvalidOperationException(); } - SchedThread.SyncTimeout = Timeout; + Suspend(Thread.ProcessorId); - UpdateSyncWaitEvent(SchedThread); + SchedThread.WaitSync.WaitOne(); - return WaitIfNeeded(SchedThread); + TryResumingExecution(SchedThread); } - public void WakeUp(KThread Thread) + public bool EnterWait(KThread Thread, int Timeout) { if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) { throw new InvalidOperationException(); } - SchedThread.SyncTimeout = 0; + Suspend(Thread.ProcessorId); - UpdateSyncWaitEvent(SchedThread); + bool Result = SchedThread.WaitSync.WaitOne(Timeout); - WaitIfNeeded(SchedThread); - } + TryResumingExecution(SchedThread); - private void UpdateSyncWaitEvent(SchedulerThread SchedThread) - { - if (SchedThread.Active && SchedThread.SyncTimeout == 0) - { - SchedThread.SyncWaitEvent.Set(); - } - else - { - SchedThread.SyncWaitEvent.Reset(); - } + return Result; } - private bool WaitIfNeeded(SchedulerThread SchedThread) + public void WakeUp(KThread Thread) { - KThread Thread = SchedThread.Thread; - - if (!IsActive(SchedThread) && Thread.Thread.IsCurrentThread()) - { - Suspend(Thread.ProcessorId); - - return Resume(Thread); - } - else + if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) { - return false; + throw new InvalidOperationException(); } + + SchedThread.WaitSync.Set(); } public void Suspend(int ProcessorId) @@ -292,53 +284,52 @@ namespace Ryujinx.Core.OsHle.Handles { PrintDbgThreadInfo(Thread, "yielded execution."); - lock (SchedLock) + if (IsActive(Thread)) { - SchedulerThread SchedThread = WaitingToRun[Thread.ProcessorId].Pop(Thread.ActualPriority); - - if (IsActive(Thread) && SchedThread == null) + lock (SchedLock) { - PrintDbgThreadInfo(Thread, "resumed because theres nothing better to run."); + SchedulerThread SchedThread = WaitingToRun[Thread.ProcessorId].Pop(Thread.ActualPriority); - return; - } + if (SchedThread == null) + { + PrintDbgThreadInfo(Thread, "resumed because theres nothing better to run."); - if (SchedThread != null) - { - RunThread(SchedThread); + return; + } + + if (SchedThread != null) + { + RunThread(SchedThread); + } } } + else + { + //Just stop running the thread if it's not active, + //and run whatever is waiting to run with the higuest priority. + Suspend(Thread.ProcessorId); + } Resume(Thread); } - public bool Resume(KThread Thread) + public void Resume(KThread Thread) { if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) { throw new InvalidOperationException(); } - return TryResumingExecution(SchedThread); + TryResumingExecution(SchedThread); } - private bool TryResumingExecution(SchedulerThread SchedThread) + private void TryResumingExecution(SchedulerThread SchedThread) { KThread Thread = SchedThread.Thread; - if (!SchedThread.Active || SchedThread.SyncTimeout != 0) - { - PrintDbgThreadInfo(Thread, "entering inactive wait state..."); - } - - bool Result = false; - - if (SchedThread.SyncTimeout != 0) - { - Result = SchedThread.SyncWaitEvent.WaitOne(SchedThread.SyncTimeout); + PrintDbgThreadInfo(Thread, "trying to resume..."); - SchedThread.SyncTimeout = 0; - } + SchedThread.WaitActivity.WaitOne(); lock (SchedLock) { @@ -346,7 +337,7 @@ namespace Ryujinx.Core.OsHle.Handles { PrintDbgThreadInfo(Thread, "resuming execution..."); - return Result; + return; } WaitingToRun[Thread.ProcessorId].Push(SchedThread); @@ -354,18 +345,16 @@ namespace Ryujinx.Core.OsHle.Handles PrintDbgThreadInfo(Thread, "entering wait state..."); } - SchedThread.SchedWaitEvent.WaitOne(); + SchedThread.WaitSched.WaitOne(); PrintDbgThreadInfo(Thread, "resuming execution..."); - - return Result; } private void RunThread(SchedulerThread SchedThread) { if (!SchedThread.Thread.Thread.Execute()) { - SchedThread.SchedWaitEvent.Set(); + SchedThread.WaitSched.Set(); } else { @@ -380,21 +369,16 @@ namespace Ryujinx.Core.OsHle.Handles throw new InvalidOperationException(); } - return IsActive(SchedThread); - } - - private bool IsActive(SchedulerThread SchedThread) - { - return SchedThread.Active && SchedThread.SyncTimeout == 0; + return SchedThread.IsActive; } private void PrintDbgThreadInfo(KThread Thread, string Message) { Log.PrintDebug(LogClass.KernelScheduler, "(" + - "ThreadId: " + Thread.ThreadId + ", " + - "ProcessorId: " + Thread.ProcessorId + ", " + - "ActualPriority: " + Thread.ActualPriority + ", " + - "WantedPriority: " + Thread.WantedPriority + ") " + Message); + "ThreadId = " + Thread.ThreadId + ", " + + "ProcessorId = " + Thread.ProcessorId + ", " + + "ActualPriority = " + Thread.ActualPriority + ", " + + "WantedPriority = " + Thread.WantedPriority + ") " + Message); } public void Dispose() diff --git a/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs b/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs index 4c4fa56e..d81f44bd 100644 --- a/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs +++ b/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs @@ -198,5 +198,35 @@ namespace Ryujinx.Core.OsHle.Ipc return -1; } + + public long GetBufferType0x21Position() + { + if (PtrBuff.Count > 0 && PtrBuff[0].Position != 0) + { + return PtrBuff[0].Position; + } + + if (SendBuff.Count > 0) + { + return SendBuff[0].Position; + } + + return 0; + } + + public long GetBufferType0x22Position() + { + if (RecvListBuff.Count > 0 && RecvListBuff[0].Position != 0) + { + return RecvListBuff[0].Position; + } + + if (ReceiveBuff.Count > 0) + { + return ReceiveBuff[0].Position; + } + + return 0; + } } } diff --git a/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs b/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs index da7dce89..e855b77d 100644 --- a/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs +++ b/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs @@ -86,6 +86,8 @@ namespace Ryujinx.Core.OsHle.Kernel if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func)) { + Ns.Log.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} called."); + Func(ThreadState); Ns.Log.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} ended."); diff --git a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs index d5593e02..ec109b2d 100644 --- a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs +++ b/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs @@ -18,6 +18,11 @@ namespace Ryujinx.Core.OsHle.Kernel long MutexAddress = (long)ThreadState.X1; int WaitThreadHandle = (int)ThreadState.X2; + Ns.Log.PrintDebug(LogClass.KernelSvc, + "OwnerThreadHandle = " + OwnerThreadHandle.ToString("x8") + ", " + + "MutexAddress = " + MutexAddress .ToString("x16") + ", " + + "WaitThreadHandle = " + WaitThreadHandle .ToString("x8")); + if (IsPointingInsideKernel(MutexAddress)) { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!"); @@ -38,6 +43,8 @@ namespace Ryujinx.Core.OsHle.Kernel KThread OwnerThread = Process.HandleTable.GetData<KThread>(OwnerThreadHandle); + Ns.Log.PrintDebug(LogClass.KernelSvc, "lock tid: " + OwnerThread.ThreadId.ToString()); + if (OwnerThread == null) { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid owner thread handle 0x{OwnerThreadHandle:x8}!"); @@ -69,6 +76,8 @@ namespace Ryujinx.Core.OsHle.Kernel { long MutexAddress = (long)ThreadState.X0; + Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexAddress = " + MutexAddress.ToString("x16")); + if (IsPointingInsideKernel(MutexAddress)) { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!"); @@ -102,6 +111,12 @@ namespace Ryujinx.Core.OsHle.Kernel int ThreadHandle = (int)ThreadState.X2; ulong Timeout = ThreadState.X3; + Ns.Log.PrintDebug(LogClass.KernelSvc, + "OwnerThreadHandle = " + MutexAddress .ToString("x16") + ", " + + "MutexAddress = " + CondVarAddress.ToString("x16") + ", " + + "WaitThreadHandle = " + ThreadHandle .ToString("x8") + ", " + + "Timeout = " + Timeout .ToString("x16")); + if (IsPointingInsideKernel(MutexAddress)) { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!"); @@ -166,6 +181,8 @@ namespace Ryujinx.Core.OsHle.Kernel { int MutexValue = Process.Memory.ReadInt32(MutexAddress); + Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = " + MutexValue.ToString("x8")); + if (MutexValue != (OwnerThreadHandle | MutexHasListenersMask)) { return; @@ -176,7 +193,7 @@ namespace Ryujinx.Core.OsHle.Kernel InsertWaitingMutexThread(OwnerThreadHandle, WaitThread); - Process.Scheduler.EnterWait(WaitThread); + Process.Scheduler.EnterWait(CurrThread); } private bool MutexUnlock(KThread CurrThread, long MutexAddress) @@ -199,8 +216,12 @@ namespace Ryujinx.Core.OsHle.Kernel OwnerThread = OwnerThread.NextMutexThread; } + UpdateMutexOwner(CurrThread, OwnerThread, MutexAddress); + CurrThread.NextMutexThread = null; + CurrThread.UpdatePriority(); + if (OwnerThread != null) { int HasListeners = OwnerThread.NextMutexThread != null ? MutexHasListenersMask : 0; @@ -284,7 +305,9 @@ namespace Ryujinx.Core.OsHle.Kernel } else { - return Process.Scheduler.EnterWait(WaitThread); + Process.Scheduler.EnterWait(WaitThread); + + return true; } } @@ -314,8 +337,6 @@ namespace Ryujinx.Core.OsHle.Kernel int MutexValue = Process.Memory.ReadInt32(CurrThread.MutexAddress); - MutexValue &= ~MutexHasListenersMask; - if (MutexValue == 0) { //Give the lock to this thread. @@ -325,15 +346,17 @@ namespace Ryujinx.Core.OsHle.Kernel CurrThread.MutexAddress = 0; CurrThread.CondVarAddress = 0; - CurrThread.MutexOwner = null; + CurrThread.MutexOwner?.UpdatePriority(); - CurrThread.UpdatePriority(); + CurrThread.MutexOwner = null; Process.Scheduler.WakeUp(CurrThread); } else { //Wait until the lock is released. + MutexValue &= ~MutexHasListenersMask; + InsertWaitingMutexThread(MutexValue, CurrThread); MutexValue |= MutexHasListenersMask; @@ -399,6 +422,23 @@ namespace Ryujinx.Core.OsHle.Kernel OwnerThread.UpdatePriority(); } + private void UpdateMutexOwner(KThread CurrThread, KThread NewOwner, long MutexAddress) + { + //Go through all threads waiting for the mutex, + //and update the MutexOwner field to point to the new owner. + CurrThread = CurrThread.NextMutexThread; + + while (CurrThread != null) + { + if (CurrThread.MutexAddress == MutexAddress) + { + CurrThread.MutexOwner = NewOwner; + } + + CurrThread = CurrThread.NextMutexThread; + } + } + private void AcquireMutexValue(long MutexAddress) { while (!Process.Memory.AcquireAddress(MutexAddress)) diff --git a/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs b/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs index 10d63894..f41a98d0 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs @@ -44,6 +44,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv { { ("/dev/nvhost-as-gpu", 0x4101), NvGpuAsIoctlBindChannel }, { ("/dev/nvhost-as-gpu", 0x4102), NvGpuAsIoctlAllocSpace }, + { ("/dev/nvhost-as-gpu", 0x4105), NvGpuAsIoctlUnmap }, { ("/dev/nvhost-as-gpu", 0x4106), NvGpuAsIoctlMapBufferEx }, { ("/dev/nvhost-as-gpu", 0x4108), NvGpuAsIoctlGetVaRegions }, { ("/dev/nvhost-as-gpu", 0x4109), NvGpuAsIoctlInitializeEx }, @@ -201,6 +202,19 @@ namespace Ryujinx.Core.OsHle.Services.Nv return 0; } + private long NvGpuAsIoctlUnmap(ServiceCtx Context) + { + long Position = Context.Request.GetSendBuffPtr(); + + MemReader Reader = new MemReader(Context.Memory, Position); + + long Offset = Reader.ReadInt64(); + + Context.Ns.Gpu.MemoryMgr.Unmap(Offset, 0x10000); + + return 0; + } + private long NvGpuAsIoctlMapBufferEx(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -319,6 +333,19 @@ namespace Ryujinx.Core.OsHle.Services.Nv int Padding = Reader.ReadInt32(); int Offset = Reader.ReadInt32(); int Pages = Reader.ReadInt32(); + + NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle); + + if (Map == null) + { + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"invalid NvMap Handle {Handle}!"); + + return -1; //TODO: Corrent error code. + } + + Context.Ns.Gpu.MapMemory(Map.CpuAddress, + (long)(uint)Offset << 16, + (long)(uint)Pages << 16); } //TODO diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvChNvMap.cs b/Ryujinx.Core/OsHle/Services/Nv/NvChNvMap.cs new file mode 100644 index 00000000..9ea3ae6e --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvChNvMap.cs @@ -0,0 +1,31 @@ +using System.Collections.Concurrent; + +namespace Ryujinx.Core.OsHle.Services.Nv +{ + class NvChNvMap + { + private static ConcurrentDictionary<Process, IdDictionary> NvMaps; + + public void Create(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + long OutputPosition = Context.Request.GetBufferType0x22Position(); + + int Size = Context.Memory.ReadInt32(InputPosition); + + int Handle = AddNvMap(Context, new NvMap(Size)); + + Context.Memory.WriteInt32(OutputPosition, Handle); + } + + private int AddNvMap(ServiceCtx Context, NvMap Map) + { + return NvMaps[Context.Process].Add(Map); + } + + public NvMap GetNvMap(ServiceCtx Context, int Handle) + { + return NvMaps[Context.Process].GetData<NvMap>(Handle); + } + } +}
\ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs index f3dd1f47..570cef68 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs @@ -9,5 +9,12 @@ namespace Ryujinx.Core.OsHle.Services.Nv public int Kind; public long CpuAddress; public long GpuAddress; + + public NvMap() { } + + public NvMap(int Size) + { + this.Size = Size; + } } }
\ No newline at end of file |
