From 73881fad1995e079eae3e728cb2f4c657886e476 Mon Sep 17 00:00:00 2001 From: Mary Date: Tue, 13 Apr 2021 02:56:16 +0200 Subject: [PATCH] Surface Flinger: Fix an oversight when closing a layer (#2192) * Surface Flinger: Fix an oversight when closing a layer As the title say. I also took the liberty of changing the logic on how we select the current layer being rendered to make it more explicit when opening and creating layers. NOTE: Found by Ac_k. * check for RenderLayerId and not the dictionary size This fix a possible race condition between the time you create a layer and set the one currently used for rendering --- .../SystemAppletProxy/ISelfController.cs | 5 ++- .../Services/SurfaceFlinger/SurfaceFlinger.cs | 37 +++++++++++++++---- .../IManagerDisplayService.cs | 1 + .../RootService/IApplicationDisplayService.cs | 4 ++ 4 files changed, 38 insertions(+), 9 deletions(-) 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 b2cc716028..7e0c7e64cd 100644 --- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs @@ -218,6 +218,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys public ResultCode CreateManagedDisplayLayer(ServiceCtx context) { context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long layerId); + context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); context.ResponseData.Write(layerId); @@ -228,9 +229,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys // CreateManagedDisplaySeparableLayer() -> (u64, u64) public ResultCode CreateManagedDisplaySeparableLayer(ServiceCtx context) { - // NOTE: first create the recoding layer and then the display one because right now Surface Flinger only use the last id. - context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long recordingLayerId); context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long displayLayerId); + context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long recordingLayerId); + context.Device.System.SurfaceFlinger.SetRenderLayer(displayLayerId); context.ResponseData.Write(displayLayerId); context.ResponseData.Write(recordingLayerId); diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs index 297acdda96..556e6a3b51 100644 --- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs +++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs @@ -7,6 +7,7 @@ using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Threading; namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger @@ -36,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger private readonly object Lock = new object(); - public long LastId { get; private set; } + public long RenderLayerId { get; private set; } private class Layer { @@ -57,7 +58,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger { _device = device; _layers = new Dictionary(); - LastId = 0; + RenderLayerId = 0; _composerThread = new Thread(HandleComposition) { @@ -150,8 +151,6 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger Core = core, Owner = pid }); - - LastId = layerId; } } @@ -166,7 +165,31 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger HOSBinderDriverServer.UnregisterBinderObject(layer.ProducerBinderId); } - return _layers.Remove(layerId); + bool removed = _layers.Remove(layerId); + + // If the layer was removed and the current in use, we need to change the current layer in use. + if (removed && RenderLayerId == layerId) + { + // If no layer is availaible, reset to default value. + if (_layers.Count == 0) + { + SetRenderLayer(0); + } + else + { + SetRenderLayer(_layers.Last().Key); + } + } + + return removed; + } + } + + public void SetRenderLayer(long layerId) + { + lock (Lock) + { + RenderLayerId = layerId; } } @@ -263,12 +286,12 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger lock (Lock) { // TODO: support multilayers (& multidisplay ?) - if (_layers.Count == 0) + if (RenderLayerId == 0) { return; } - Layer layer = GetLayerByIdLocked(LastId); + Layer layer = GetLayerByIdLocked(RenderLayerId); Status acquireStatus = layer.Consumer.AcquireBuffer(out BufferItem item, 0); diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs index 6b874722d2..4d3bef50bf 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs @@ -22,6 +22,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService long pid = context.Device.System.AppletState.AppletResourceUserIds.GetData((int)appletResourceUserId); context.Device.System.SurfaceFlinger.CreateLayer(pid, out long layerId); + context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); context.ResponseData.Write(layerId); diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs index b521ae927d..1620ef2163 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs @@ -126,6 +126,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService IBinder producer = context.Device.System.SurfaceFlinger.OpenLayer(context.Request.HandleDesc.PId, layerId); + context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); + Parcel parcel = new Parcel(0x28, 0x4); parcel.WriteObject(producer, "dispdrv\0"); @@ -164,6 +166,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService IBinder producer = context.Device.System.SurfaceFlinger.CreateLayer(0, out long layerId); + context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); + Parcel parcel = new Parcel(0x28, 0x4); parcel.WriteObject(producer, "dispdrv\0");