diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs index 2af80f6ef5..d6e34d21d1 100644 --- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs @@ -217,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys // CreateManagedDisplayLayer() -> u64 public ResultCode CreateManagedDisplayLayer(ServiceCtx context) { - context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long layerId); + context.Device.System.SurfaceFlinger.CreateLayer(out long layerId, _pid); context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); context.ResponseData.Write(layerId); @@ -238,8 +238,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys // CreateManagedDisplaySeparableLayer() -> (u64, u64) public ResultCode CreateManagedDisplaySeparableLayer(ServiceCtx context) { - context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long displayLayerId); - context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long recordingLayerId); + context.Device.System.SurfaceFlinger.CreateLayer(out long displayLayerId, _pid); + context.Device.System.SurfaceFlinger.CreateLayer(out long recordingLayerId, _pid); context.Device.System.SurfaceFlinger.SetRenderLayer(displayLayerId); context.ResponseData.Write(displayLayerId); diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/LayerState.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/LayerState.cs new file mode 100644 index 0000000000..5f014e13a3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/LayerState.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger +{ + enum LayerState + { + NotInitialized, + ManagedClosed, + ManagedOpened, + Stray + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs index be2e15bd3c..8fa2790565 100644 --- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs +++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs @@ -11,6 +11,8 @@ using System.Threading; namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger { + using ResultCode = Ryujinx.HLE.HOS.Services.Vi.ResultCode; + class SurfaceFlinger : IConsumerListener, IDisposable { private const int TargetFps = 60; @@ -45,6 +47,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger public BufferItemConsumer Consumer; public BufferQueueCore Core; public ulong Owner; + public LayerState State; } private class TextureCallbackInformation @@ -92,24 +95,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger } } - public IGraphicBufferProducer OpenLayer(ulong pid, long layerId) - { - bool needCreate; - - lock (Lock) - { - needCreate = GetLayerByIdLocked(layerId) == null; - } - - if (needCreate) - { - CreateLayerFromId(pid, layerId); - } - - return GetProducerByLayerId(layerId); - } - - public IGraphicBufferProducer CreateLayer(ulong pid, out long layerId) + public IGraphicBufferProducer CreateLayer(out long layerId, ulong pid, LayerState initialState = LayerState.ManagedClosed) { layerId = 1; @@ -124,12 +110,12 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger } } - CreateLayerFromId(pid, layerId); + CreateLayerFromId(pid, layerId, initialState); return GetProducerByLayerId(layerId); } - private void CreateLayerFromId(ulong pid, long layerId) + private void CreateLayerFromId(ulong pid, long layerId, LayerState initialState) { lock (Lock) { @@ -148,39 +134,129 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger Producer = producer, Consumer = new BufferItemConsumer(_device, consumer, 0, -1, false, this), Core = core, - Owner = pid + Owner = pid, + State = initialState }); } } - public bool CloseLayer(long layerId) + public ResultCode OpenLayer(ulong pid, long layerId, out IBinder producer) + { + Layer layer = GetLayerByIdLocked(layerId); + + if (layer == null || layer.State != LayerState.ManagedClosed) + { + producer = null; + + return ResultCode.InvalidArguments; + } + + layer.State = LayerState.ManagedOpened; + producer = layer.Producer; + + return ResultCode.Success; + } + + public ResultCode CloseLayer(long layerId) { lock (Lock) { Layer layer = GetLayerByIdLocked(layerId); - if (layer != null) + if (layer == null) { - HOSBinderDriverServer.UnregisterBinderObject(layer.ProducerBinderId); + Logger.Error?.Print(LogClass.SurfaceFlinger, $"Failed to close layer {layerId}"); + + return ResultCode.InvalidValue; } - bool removed = _layers.Remove(layerId); + CloseLayer(layerId, layer); - // If the layer was removed and the current in use, we need to change the current layer in use. - if (removed && RenderLayerId == layerId) + return ResultCode.Success; + } + } + + public ResultCode DestroyManagedLayer(long layerId) + { + lock (Lock) + { + Layer layer = GetLayerByIdLocked(layerId); + + if (layer == null) { - // If no layer is availaible, reset to default value. - if (_layers.Count == 0) - { - SetRenderLayer(0); - } - else - { - SetRenderLayer(_layers.Last().Key); - } + Logger.Error?.Print(LogClass.SurfaceFlinger, $"Failed to destroy managed layer {layerId} (not found)"); + + return ResultCode.InvalidValue; } - return removed; + if (layer.State != LayerState.ManagedClosed && layer.State != LayerState.ManagedOpened) + { + Logger.Error?.Print(LogClass.SurfaceFlinger, $"Failed to destroy managed layer {layerId} (permission denied)"); + + return ResultCode.PermissionDenied; + } + + HOSBinderDriverServer.UnregisterBinderObject(layer.ProducerBinderId); + + if (_layers.Remove(layerId) && layer.State == LayerState.ManagedOpened) + { + CloseLayer(layerId, layer); + } + + return ResultCode.Success; + } + } + + public ResultCode DestroyStrayLayer(long layerId) + { + lock (Lock) + { + Layer layer = GetLayerByIdLocked(layerId); + + if (layer == null) + { + Logger.Error?.Print(LogClass.SurfaceFlinger, $"Failed to destroy stray layer {layerId} (not found)"); + + return ResultCode.InvalidValue; + } + + if (layer.State != LayerState.Stray) + { + Logger.Error?.Print(LogClass.SurfaceFlinger, $"Failed to destroy stray layer {layerId} (permission denied)"); + + return ResultCode.PermissionDenied; + } + + HOSBinderDriverServer.UnregisterBinderObject(layer.ProducerBinderId); + + if (_layers.Remove(layerId)) + { + CloseLayer(layerId, layer); + } + + return ResultCode.Success; + } + } + + private void CloseLayer(long layerId, Layer layer) + { + // If the layer was removed and the current in use, we need to change the current layer in use. + if (RenderLayerId == layerId) + { + // If no layer is availaible, reset to default value. + if (_layers.Count == 0) + { + SetRenderLayer(0); + } + else + { + SetRenderLayer(_layers.Last().Key); + } + } + + if (layer.State == LayerState.ManagedOpened) + { + layer.State = LayerState.ManagedClosed; } } diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs index 096c7a30e9..f40a053c6c 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs @@ -35,7 +35,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService ulong pid = context.Device.System.AppletState.AppletResourceUserIds.GetData((int)appletResourceUserId); - context.Device.System.SurfaceFlinger.CreateLayer(pid, out long layerId); + context.Device.System.SurfaceFlinger.CreateLayer(out long layerId, pid); context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); context.ResponseData.Write(layerId); @@ -49,9 +49,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService { long layerId = context.RequestData.ReadInt64(); - context.Device.System.SurfaceFlinger.CloseLayer(layerId); - - return ResultCode.Success; + return context.Device.System.SurfaceFlinger.DestroyManagedLayer(layerId); } [CommandHipc(2012)] // 7.0.0+ diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs index da55c116be..640e8be4aa 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs @@ -237,7 +237,12 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService long userId = context.RequestData.ReadInt64(); ulong parcelPtr = context.Request.ReceiveBuff[0].Position; - IBinder producer = context.Device.System.SurfaceFlinger.OpenLayer(context.Request.HandleDesc.PId, layerId); + ResultCode result = context.Device.System.SurfaceFlinger.OpenLayer(context.Request.HandleDesc.PId, layerId, out IBinder producer); + + if (result != ResultCode.Success) + { + return result; + } context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); @@ -260,9 +265,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService { long layerId = context.RequestData.ReadInt64(); - context.Device.System.SurfaceFlinger.CloseLayer(layerId); - - return ResultCode.Success; + return context.Device.System.SurfaceFlinger.CloseLayer(layerId); } [CommandHipc(2030)] @@ -275,7 +278,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService ulong parcelPtr = context.Request.ReceiveBuff[0].Position; // TODO: support multi display. - IBinder producer = context.Device.System.SurfaceFlinger.CreateLayer(0, out long layerId); + IBinder producer = context.Device.System.SurfaceFlinger.CreateLayer(out long layerId, 0, LayerState.Stray); context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); @@ -299,9 +302,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService { long layerId = context.RequestData.ReadInt64(); - context.Device.System.SurfaceFlinger.CloseLayer(layerId); - - return ResultCode.Success; + return context.Device.System.SurfaceFlinger.DestroyStrayLayer(layerId); } [CommandHipc(2101)]