Implement Surface Flinger shared layers.

Co-authored-by: Alula <6276139+alula@users.noreply.github.com>
This commit is contained in:
Jacobwasbeast 2025-02-07 04:27:01 -06:00
parent e2a5e69f4c
commit 965fb9dd5f
5 changed files with 53 additions and 63 deletions

View File

@ -114,6 +114,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
}
[CommandCmif(26)]
// AcquireCallerAppletCaptureSharedBuffer() -> (b8, u32)
public ResultCode AcquireCallerAppletCaptureSharedBuffer(ServiceCtx context)
{
@ -123,5 +124,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
return ResultCode.Success;
}
[CommandCmif(27)]
public ResultCode ReleaseCallerAppletCaptureSharedBuffer(ServiceCtx context)
{
context.ResponseData.Write(2);
return ResultCode.Success;
}
}
}

View File

@ -225,7 +225,6 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
public ResultCode CreateManagedDisplayLayer(ServiceCtx context)
{
context.Device.System.SurfaceFlinger.CreateLayer(out long layerId, _pid);
context.Device.System.SurfaceFlinger.SetRenderLayer(layerId);
context.ResponseData.Write(layerId);
@ -236,9 +235,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
// IsSystemBufferSharingEnabled()
public ResultCode IsSystemBufferSharingEnabled(ServiceCtx context)
{
// NOTE: Service checks a private field and return an error if the SystemBufferSharing is disabled.
// todo check if we're not an AppletId.Application
// TODO: Implement this once we have a way to check if we're not an AppletId.Application
return ResultCode.Success;
}

View File

@ -4,6 +4,7 @@ using Ryujinx.Common.Logging;
using Ryujinx.Common.PreciseSleep;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
using System;
using System.Collections.Generic;
@ -38,8 +39,6 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
private readonly Lock _lock = new();
public long RenderLayerId { get; private set; }
private class Layer
{
public int ProducerBinderId;
@ -60,7 +59,6 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
_device = device;
_layers = new Dictionary<long, Layer>();
RenderLayerId = 0;
_composerThread = new Thread(HandleComposition)
{
@ -239,34 +237,12 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
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;
}
}
public void SetRenderLayer(long layerId)
{
lock (_lock)
{
RenderLayerId = layerId;
}
}
private Layer GetLayerByIdLocked(long layerId)
{
foreach (KeyValuePair<long, Layer> pair in _layers)
@ -360,41 +336,55 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
lock (_lock)
{
// TODO: support multilayers (& multidisplay ?)
if (RenderLayerId == 0)
foreach (var (layerId, layer) in _layers)
{
return;
}
Layer layer = GetLayerByIdLocked(RenderLayerId);
Status acquireStatus = layer.Consumer.AcquireBuffer(out BufferItem item, 0);
if (acquireStatus == Status.Success)
{
if (_device.VSyncMode == VSyncMode.Unbounded)
if (layer.State == LayerState.NotInitialized || layer.State == LayerState.ManagedClosed)
continue;
if (_device.System.KernelContext.Processes.TryGetValue(layer.Owner, out var process))
{
if (_swapInterval != 0)
if (process.State == ProcessState.Exiting || process.State == ProcessState.Exited)
{
UpdateSwapInterval(0);
_vSyncMode = _device.VSyncMode;
HOSBinderDriverServer.UnregisterBinderObject(layer.ProducerBinderId);
if (_layers.Remove(layerId))
{
CloseLayer(layerId, layer);
}
continue;
}
}
else if (_device.VSyncMode != _vSyncMode)
Status acquireStatus = layer.Consumer.AcquireBuffer(out BufferItem item, 0);
if (acquireStatus == Status.Success)
{
UpdateSwapInterval(_device.VSyncMode == VSyncMode.Unbounded ? 0 : item.SwapInterval);
_vSyncMode = _device.VSyncMode;
}
else if (item.SwapInterval != _swapInterval || _device.TargetVSyncInterval != _targetVSyncInterval)
{
UpdateSwapInterval(item.SwapInterval);
}
if (_device.VSyncMode == VSyncMode.Unbounded)
{
if (_swapInterval != 0)
{
UpdateSwapInterval(0);
_vSyncMode = _device.VSyncMode;
}
}
else if (_device.VSyncMode != _vSyncMode)
{
UpdateSwapInterval(_device.VSyncMode == VSyncMode.Unbounded ? 0 : item.SwapInterval);
_vSyncMode = _device.VSyncMode;
}
else if (item.SwapInterval != _swapInterval || _device.TargetVSyncInterval != _targetVSyncInterval)
{
UpdateSwapInterval(item.SwapInterval);
}
PostFrameBuffer(layer, item);
}
else if (acquireStatus != Status.NoBufferAvailaible && acquireStatus != Status.InvalidOperation)
{
throw new InvalidOperationException();
PostFrameBuffer(layer, item);
}
else if (acquireStatus != Status.NoBufferAvailaible && acquireStatus != Status.InvalidOperation)
{
Logger.Warning?.Print(LogClass.SurfaceFlinger, $"Failed to acquire buffer for layer {layerId} (status: {acquireStatus})");
continue;
}
}
}
}

View File

@ -40,7 +40,6 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService
ulong pid = context.Device.System.AppletState.AppletResourceUserIds.GetData<ulong>((int)appletResourceUserId);
context.Device.System.SurfaceFlinger.CreateLayer(out long layerId, pid);
context.Device.System.SurfaceFlinger.SetRenderLayer(layerId);
context.ResponseData.Write(layerId);

View File

@ -248,8 +248,6 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
return result;
}
context.Device.System.SurfaceFlinger.SetRenderLayer(layerId);
using Parcel parcel = new(0x28, 0x4);
parcel.WriteObject(producer, "dispdrv\0");
@ -285,9 +283,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
// TODO: support multi display.
IBinder producer = context.Device.System.SurfaceFlinger.CreateLayer(out long layerId, 0, LayerState.Stray);
context.Device.System.SurfaceFlinger.SetRenderLayer(layerId);
using Parcel parcel = new(0x28, 0x4);
parcel.WriteObject(producer, "dispdrv\0");