IPC refactor part 2: Use ReplyAndReceive on HLE services and remove special handling from kernel (#1458)

* IPC refactor part 2: Use ReplyAndReceive on HLE services and remove special handling from kernel

* Fix for applet transfer memory + some nits

* Keep handles if possible to avoid server handle table exhaustion

* Fix IPC ZeroFill bug

* am: Correctly implement CreateManagedDisplayLayer and implement CreateManagedDisplaySeparableLayer

CreateManagedDisplaySeparableLayer is requires since 10.x+ when appletResourceUserId != 0

* Make it exit properly

* Make ServiceNotImplementedException show the full message again

* Allow yielding execution to avoid starving other threads

* Only wait if active

* Merge IVirtualMemoryManager and IAddressSpaceManager

* Fix Ro loading data from the wrong process

Co-authored-by: Thog <me@thog.eu>
This commit is contained in:
gdkchan 2020-12-01 20:23:43 -03:00 committed by GitHub
parent 461c24092a
commit cf6cd71488
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
115 changed files with 2356 additions and 1088 deletions

View file

@ -1,15 +1,15 @@
using Ryujinx.HLE.HOS.Kernel.Process;
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
class BufferQueue
static class BufferQueue
{
public static void CreateBufferQueue(Switch device, KProcess process, out BufferQueueProducer producer, out BufferQueueConsumer consumer)
public static BufferQueueCore CreateBufferQueue(Switch device, long pid, out BufferQueueProducer producer, out BufferQueueConsumer consumer)
{
BufferQueueCore core = new BufferQueueCore(device, process);
BufferQueueCore core = new BufferQueueCore(device, pid);
producer = new BufferQueueProducer(core);
consumer = new BufferQueueConsumer(core);
return core;
}
}
}

View file

@ -1,5 +1,5 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
using System;
@ -40,11 +40,13 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
private KEvent _waitBufferFreeEvent;
private KEvent _frameAvailableEvent;
public KProcess Owner { get; }
public long Owner { get; }
public bool Active { get; private set; }
public const int BufferHistoryArraySize = 8;
public BufferQueueCore(Switch device, KProcess process)
public BufferQueueCore(Switch device, long pid)
{
Slots = new BufferSlotArray();
IsAbandoned = false;
@ -70,7 +72,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
_waitBufferFreeEvent = new KEvent(device.System.KernelContext);
_frameAvailableEvent = new KEvent(device.System.KernelContext);
Owner = process;
Owner = pid;
Active = true;
BufferHistory = new BufferInfo[BufferHistoryArraySize];
EnableExternalEvent = true;
@ -162,6 +166,16 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}
}
public void PrepareForExit()
{
lock (Lock)
{
Active = false;
Monitor.PulseAll(Lock);
}
}
// TODO: Find an accurate way to handle a regular condvar here as this will wake up unwanted threads in some edge cases.
public void SignalDequeueEvent()
{
@ -170,7 +184,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public void WaitDequeueEvent()
{
Monitor.Wait(Lock);
Monitor.Exit(Lock);
KernelStatic.YieldUntilCompletion(WaitForLock);
Monitor.Enter(Lock);
}
public void SignalIsAllocatingEvent()
@ -180,7 +198,22 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public void WaitIsAllocatingEvent()
{
Monitor.Wait(Lock);
Monitor.Exit(Lock);
KernelStatic.YieldUntilCompletion(WaitForLock);
Monitor.Enter(Lock);
}
private void WaitForLock()
{
lock (Lock)
{
if (Active)
{
Monitor.Wait(Lock);
}
}
}
public void FreeBufferLocked(int slot)

View file

@ -816,6 +816,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}
Core.WaitDequeueEvent();
if (!Core.Active)
{
break;
}
}
}

View file

@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
abstract class IHOSBinderDriver : IpcService
{
public IHOSBinderDriver() {}
public IHOSBinderDriver() { }
[Command(0)]
// TransactParcel(s32, u32, u32, buffer<unknown, 5, 0>) -> buffer<unknown, 6, 0>

View file

@ -1,10 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
using Ryujinx.HLE.HOS.Services.Nv.Types;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@ -40,7 +37,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public int ProducerBinderId;
public IGraphicBufferProducer Producer;
public BufferItemConsumer Consumer;
public KProcess Owner;
public BufferQueueCore Core;
public long Owner;
}
private class TextureCallbackInformation
@ -84,7 +82,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}
}
public IGraphicBufferProducer OpenLayer(KProcess process, long layerId)
public IGraphicBufferProducer OpenLayer(long pid, long layerId)
{
bool needCreate;
@ -95,13 +93,13 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
if (needCreate)
{
CreateLayerFromId(process, layerId);
CreateLayerFromId(pid, layerId);
}
return GetProducerByLayerId(layerId);
}
public IGraphicBufferProducer CreateLayer(KProcess process, out long layerId)
public IGraphicBufferProducer CreateLayer(long pid, out long layerId)
{
layerId = 1;
@ -116,25 +114,26 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}
}
CreateLayerFromId(process, layerId);
CreateLayerFromId(pid, layerId);
return GetProducerByLayerId(layerId);
}
private void CreateLayerFromId(KProcess process, long layerId)
private void CreateLayerFromId(long pid, long layerId)
{
lock (Lock)
{
Logger.Info?.Print(LogClass.SurfaceFlinger, $"Creating layer {layerId}");
BufferQueue.CreateBufferQueue(_device, process, out BufferQueueProducer producer, out BufferQueueConsumer consumer);
BufferQueueCore core = BufferQueue.CreateBufferQueue(_device, pid, out BufferQueueProducer producer, out BufferQueueConsumer consumer);
_layers.Add(layerId, new Layer
{
ProducerBinderId = HOSBinderDriverServer.RegisterBinderObject(producer),
Producer = producer,
Consumer = new BufferItemConsumer(_device, consumer, 0, -1, false, this),
Owner = process
Core = core,
Owner = pid
});
LastId = layerId;
@ -345,6 +344,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public void Dispose()
{
_isRunning = false;
foreach (Layer layer in _layers.Values)
{
layer.Core.PrepareForExit();
}
}
public void OnFrameAvailable(ref BufferItem item)

View file

@ -42,23 +42,23 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
Buffer = parcel.ReadUnmanagedType<NvGraphicBuffer>();
}
public void IncrementNvMapHandleRefCount(KProcess process)
public void IncrementNvMapHandleRefCount(long pid)
{
NvMapDeviceFile.IncrementMapRefCount(process, Buffer.NvMapId);
NvMapDeviceFile.IncrementMapRefCount(pid, Buffer.NvMapId);
for (int i = 0; i < Buffer.Surfaces.Length; i++)
{
NvMapDeviceFile.IncrementMapRefCount(process, Buffer.Surfaces[i].NvMapHandle);
NvMapDeviceFile.IncrementMapRefCount(pid, Buffer.Surfaces[i].NvMapHandle);
}
}
public void DecrementNvMapHandleRefCount(KProcess process)
public void DecrementNvMapHandleRefCount(long pid)
{
NvMapDeviceFile.DecrementMapRefCount(process, Buffer.NvMapId);
NvMapDeviceFile.DecrementMapRefCount(pid, Buffer.NvMapId);
for (int i = 0; i < Buffer.Surfaces.Length; i++)
{
NvMapDeviceFile.DecrementMapRefCount(process, Buffer.Surfaces[i].NvMapHandle);
NvMapDeviceFile.DecrementMapRefCount(pid, Buffer.Surfaces[i].NvMapHandle);
}
}