Implement changes from gdkchan/buffer-sharing-rebased

Co-authored-by: gdkchan <gab.dark.100@gmail.com>
Co-authored-by: Alula <6276139+alula@users.noreply.github.com>
This commit is contained in:
Jacobwasbeast
2025-02-06 03:48:54 -06:00
parent d1da937fce
commit 3ca8618f5f
53 changed files with 1388 additions and 294 deletions

View File

@@ -24,7 +24,7 @@ namespace Ryujinx.HLE.HOS
private readonly ICpuContext _cpuContext;
private T _memoryManager;
public IVirtualMemoryManager AddressSpace => _memoryManager;
public IVirtualMemoryManagerTracked AddressSpace => _memoryManager;
public ulong AddressSpaceSize { get; }

View File

@@ -75,7 +75,7 @@ namespace Ryujinx.HLE.HOS
internal ServerBase TimeServer { get; private set; }
internal ServerBase ViServer { get; private set; }
internal ServerBase ViServerM { get; private set; }
internal ServerBase ViServerS { get; private set; }
internal ViServer ViServerS { get; private set; }
internal ServerBase LdnServer { get; private set; }
internal KSharedMemory HidSharedMem { get; private set; }
@@ -254,7 +254,7 @@ namespace Ryujinx.HLE.HOS
TimeServer = new ServerBase(KernelContext, "TimeServer");
ViServer = new ServerBase(KernelContext, "ViServerU");
ViServerM = new ServerBase(KernelContext, "ViServerM");
ViServerS = new ServerBase(KernelContext, "ViServerS");
ViServerS = new ViServer(KernelContext, "ViServerS");
LdnServer = new ServerBase(KernelContext, "LdnServer");
StartNewServices();

View File

@@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
interface IProcessContext : IDisposable
{
IVirtualMemoryManager AddressSpace { get; }
IVirtualMemoryManagerTracked AddressSpace { get; }
ulong AddressSpaceSize { get; }

View File

@@ -86,7 +86,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
private IProcessContextFactory _contextFactory;
public IProcessContext Context { get; private set; }
public IVirtualMemoryManager CpuMemory => Context.AddressSpace;
public IVirtualMemoryManagerTracked CpuMemory => Context.AddressSpace;
public HleProcessDebugger Debugger { get; private set; }

View File

@@ -6,11 +6,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
class ProcessContext : IProcessContext
{
public IVirtualMemoryManager AddressSpace { get; }
public IVirtualMemoryManagerTracked AddressSpace { get; }
public ulong AddressSpaceSize { get; }
public ProcessContext(IVirtualMemoryManager asManager, ulong addressSpaceSize)
public ProcessContext(IVirtualMemoryManagerTracked asManager, ulong addressSpaceSize)
{
AddressSpace = asManager;
AddressSpaceSize = addressSpaceSize;

View File

@@ -102,5 +102,26 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
return ResultCode.Success;
}
[CommandCmif(22)]
// AcquireLastApplicationCaptureSharedBuffer() -> (b8, u32)
public ResultCode AcquireLastApplicationCaptureSharedBuffer(ServiceCtx context)
{
context.ResponseData.Write(1);
context.ResponseData.Write(context.Device.System.ViServerS.GetApplicationLastPresentedFrameHandle(context.Device.Gpu));
return ResultCode.Success;
}
[CommandCmif(26)]
// AcquireCallerAppletCaptureSharedBuffer() -> (b8, u32)
public ResultCode AcquireCallerAppletCaptureSharedBuffer(ServiceCtx context)
{
// TODO: How does the handling for applets differ from the one for applications?
context.ResponseData.Write(1);
context.ResponseData.Write(context.Device.System.ViServerS.GetApplicationLastPresentedFrameHandle(context.Device.Gpu));
return ResultCode.Success;
}
}
}

View File

@@ -238,16 +238,27 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
{
// NOTE: Service checks a private field and return an error if the SystemBufferSharing is disabled.
return ResultCode.NotImplemented;
// todo check if we're not an AppletId.Application
return ResultCode.Success;
}
[CommandCmif(42)] // 4.0.0+
// GetSystemSharedLayerHandle() -> (nn::vi::fbshare::SharedBufferHandle, nn::vi::fbshare::SharedLayerHandle)
public ResultCode GetSystemSharedLayerHandle(ServiceCtx context)
{
context.ResponseData.Write((ulong)context.Device.System.ViServerS.GetSharedBufferNvMapId());
context.ResponseData.Write(context.Device.System.ViServerS.GetSharedLayerId());
return ResultCode.Success;
}
[CommandCmif(44)] // 10.0.0+
// CreateManagedDisplaySeparableLayer() -> (u64, u64)
public ResultCode CreateManagedDisplaySeparableLayer(ServiceCtx context)
{
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.Device.System.SurfaceFlinger.SetRenderLayer(displayLayerId);
context.ResponseData.Write(displayLayerId);
context.ResponseData.Write(recordingLayerId);

View File

@@ -1,3 +1,4 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Threading;
@@ -105,6 +106,26 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
return ResultCode.Success;
}
[CommandCmif(6)]
// SetRequirementPreset(u32)
public ResultCode SetRequirementPreset(ServiceCtx context)
{
Logger.Stub?.PrintStub(LogClass.ServiceNifm);
return ResultCode.Success;
}
[CommandCmif(9)]
// SetNetworkProfileId(nn::util::Uuid)
public ResultCode SetNetworkProfileId(ServiceCtx context)
{
UInt128 uuid = context.RequestData.ReadStruct<UInt128>();
Logger.Stub?.PrintStub(LogClass.ServiceNifm, new { uuid });
return ResultCode.Success;
}
[CommandCmif(11)]
// SetConnectionConfirmationOption(i8)
public ResultCode SetConnectionConfirmationOption(ServiceCtx context)
@@ -142,5 +163,38 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
return ResultCode.Success;
}
[CommandCmif(23)]
// SetKeptInSleep(bool)
public ResultCode SetKeptInSleep(ServiceCtx context)
{
bool keptInSleep = context.RequestData.ReadBoolean();
Logger.Stub?.PrintStub(LogClass.ServiceNifm, new { keptInSleep });
return ResultCode.Success;
}
[CommandCmif(24)]
// RegisterSocketDescriptor(s32)
public ResultCode RegisterSocketDescriptor(ServiceCtx context)
{
int socketDescriptor = context.RequestData.ReadInt32();
Logger.Stub?.PrintStub(LogClass.ServiceNifm, new { socketDescriptor });
return ResultCode.Success;
}
[CommandCmif(25)]
// UnregisterSocketDescriptor(s32)
public ResultCode UnregisterSocketDescriptor(ServiceCtx context)
{
int socketDescriptor = context.RequestData.ReadInt32();
Logger.Stub?.PrintStub(LogClass.ServiceNifm, new { socketDescriptor });
return ResultCode.Success;
}
}
}

View File

@@ -245,8 +245,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
}
}
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, arguments.NvMapHandle);
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(arguments.NvMapHandle);
if (map == null)
{
Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid NvMap handle 0x{arguments.NvMapHandle:x8}!");
@@ -282,7 +282,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
{
if (_asContext.ValidateFixedBuffer(arguments.Offset, size, pageSize))
{
_asContext.Gmm.Map(physicalAddress, arguments.Offset, size, (PteKind)arguments.Kind);
Map(physicalAddress, arguments.Offset, size, (PteKind)arguments.Kind, map.OwnerPid);
}
else
{
@@ -301,7 +301,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
_memoryAllocator.AllocateRange(va, size, freeAddressStartPosition);
}
_asContext.Gmm.Map(physicalAddress, va, size, (PteKind)arguments.Kind);
Map(physicalAddress, va, size, (PteKind)arguments.Kind, map.OwnerPid);
arguments.Offset = va;
}
@@ -380,8 +380,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
ulong mapOffs = (ulong)argument.MapOffset << 16;
PteKind kind = (PteKind)argument.Kind;
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, nvmapHandle);
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(nvmapHandle);
if (map == null)
{
Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid NvMap handle 0x{nvmapHandle:x8}!");
@@ -389,13 +389,25 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
return NvInternalResult.InvalidInput;
}
gmm.Map(mapOffs + map.Address, gpuVa, size, kind);
Map(mapOffs + map.Address, gpuVa, size, kind, map.OwnerPid);
}
}
return NvInternalResult.Success;
}
private void Map(ulong pa, ulong va, ulong size, PteKind kind, ulong ownerPid)
{
if (Owner == ownerPid)
{
_asContext.Gmm.Map(pa, va, size, kind);
}
else
{
_asContext.Gmm.MapForeign(pa, va, size, kind, ownerPid);
}
}
public override void Close() { }
}
}

View File

@@ -167,8 +167,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
foreach (CommandBuffer commandBuffer in commandBuffers)
{
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBuffer.Mem);
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(commandBuffer.Mem);
ReadOnlySpan<byte> data = _memory.GetSpan(map.Address + commandBuffer.Offset, commandBuffer.WordsCount * 4);
_host1xContext.Host1x.Submit(MemoryMarshal.Cast<byte, int>(data), _contextId);
@@ -237,8 +237,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
foreach (ref CommandBufferHandle commandBufferEntry in commandBufferEntries)
{
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBufferEntry.MapHandle);
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(commandBufferEntry.MapHandle);
if (map == null)
{
Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid handle 0x{commandBufferEntry.MapHandle:x8}!");
@@ -279,8 +279,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
foreach (ref CommandBufferHandle commandBufferEntry in commandBufferEntries)
{
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBufferEntry.MapHandle);
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(commandBufferEntry.MapHandle);
if (map == null)
{
Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid handle 0x{commandBufferEntry.MapHandle:x8}!");

View File

@@ -71,8 +71,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
uint size = BitUtils.AlignUp(arguments.Size, (uint)MemoryManager.PageSize);
arguments.Handle = CreateHandleFromMap(new NvMapHandle(size));
arguments.Handle = CreateHandleFromMap(new NvMapHandle(size) { OwnerPid = Owner });
Logger.Debug?.Print(LogClass.ServiceNv, $"Created map {arguments.Handle} with size 0x{size:x8}!");
return NvInternalResult.Success;
@@ -80,8 +80,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
private NvInternalResult FromId(ref NvMapFromId arguments)
{
NvMapHandle map = GetMapFromHandle(Owner, arguments.Id);
NvMapHandle map = GetMapFromHandle(arguments.Id);
if (map == null)
{
Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid handle 0x{arguments.Handle:x8}!");
@@ -98,8 +98,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
private NvInternalResult Alloc(ref NvMapAlloc arguments)
{
NvMapHandle map = GetMapFromHandle(Owner, arguments.Handle);
NvMapHandle map = GetMapFromHandle(arguments.Handle);
if (map == null)
{
Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid handle 0x{arguments.Handle:x8}!");
@@ -152,8 +152,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
private NvInternalResult Free(ref NvMapFree arguments)
{
NvMapHandle map = GetMapFromHandle(Owner, arguments.Handle);
NvMapHandle map = GetMapFromHandle(arguments.Handle);
if (map == null)
{
Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid handle 0x{arguments.Handle:x8}!");
@@ -179,8 +179,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
private NvInternalResult Param(ref NvMapParam arguments)
{
NvMapHandle map = GetMapFromHandle(Owner, arguments.Handle);
NvMapHandle map = GetMapFromHandle(arguments.Handle);
if (map == null)
{
Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid handle 0x{arguments.Handle:x8}!");
@@ -217,8 +217,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
private NvInternalResult GetId(ref NvMapGetId arguments)
{
NvMapHandle map = GetMapFromHandle(Owner, arguments.Handle);
NvMapHandle map = GetMapFromHandle(arguments.Handle);
if (map == null)
{
Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid handle 0x{arguments.Handle:x8}!");
@@ -237,25 +237,30 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
// _maps.TryRemove(GetOwner(), out _);
}
private int CreateHandleFromMap(NvMapHandle map)
public static int CreateMap(ulong pid, ulong address, uint size)
{
return CreateHandleFromMap(new NvMapHandle(size) { Address = address, OwnerPid = pid });
}
private static int CreateHandleFromMap(NvMapHandle map)
{
return _maps.Add(map);
}
private static bool DeleteMapWithHandle(ulong pid, int handle)
private static bool DeleteMapWithHandle(int handle)
{
return _maps.Delete(handle) != null;
}
public static void IncrementMapRefCount(ulong pid, int handle)
{
GetMapFromHandle(pid, handle)?.IncrementRefCount();
GetMapFromHandle(handle)?.IncrementRefCount();
}
public static bool DecrementMapRefCount(ulong pid, int handle)
{
NvMapHandle map = GetMapFromHandle(pid, handle);
NvMapHandle map = GetMapFromHandle(handle);
if (map == null)
{
return false;
@@ -263,8 +268,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
if (map.DecrementRefCount() <= 0)
{
DeleteMapWithHandle(pid, handle);
DeleteMapWithHandle(handle);
Logger.Debug?.Print(LogClass.ServiceNv, $"Deleted map {handle}!");
return true;
@@ -275,7 +280,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
}
}
public static NvMapHandle GetMapFromHandle(ulong pid, int handle)
public static NvMapHandle GetMapFromHandle(int handle)
{
return _maps.Get(handle);
}

View File

@@ -14,7 +14,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
public ulong Address;
public bool Allocated;
public ulong DmaMapAddress;
public ulong OwnerPid;
private long _dupes;
public NvMapHandle()

View File

@@ -172,6 +172,15 @@ namespace Ryujinx.HLE.HOS.Services
{
ServerLoop();
}
protected virtual ulong CalculateRequiredHeapSize()
{
return 0UL;
}
protected virtual void CustomInit(KernelContext context, ulong pid, ulong heapAddress)
{
}
private void ServerLoop()
{
@@ -196,10 +205,14 @@ namespace Ryujinx.HLE.HOS.Services
Result result = _selfProcess.HandleTable.GenerateHandle(_wakeEvent.ReadableEvent, out _wakeHandle);
InitDone.Set();
ulong heapSize = CalculateRequiredHeapSize() + PointerBufferSize;
ulong messagePtr = _selfThread.TlsAddress;
_context.Syscall.SetHeapSize(out ulong heapAddr, 0x200000);
_context.Syscall.SetHeapSize(out ulong heapAddr, BitUtils.AlignUp(heapSize, 0x200000UL));
CustomInit(_context, _selfProcess.Pid, heapAddr + PointerBufferSize);
_selfProcess.CpuMemory.Write(messagePtr + 0x0, 0);
_selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10);
_selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48));

View File

@@ -413,8 +413,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
ulong bufferOffset = (ulong)item.GraphicBuffer.Object.Buffer.Surfaces[0].Offset;
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(layer.Owner, nvMapHandle);
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(nvMapHandle);
ulong frameBufferAddress = map.Address + bufferOffset;
Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat);

View File

@@ -1,3 +1,4 @@
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
@@ -36,6 +37,6 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public int PlanesCount;
[FieldOffset(0x34)]
public NvGraphicBufferSurfaceArray Surfaces;
public Array3<NvGraphicBufferSurface> Surfaces;
}
}

View File

@@ -1,4 +1,11 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.SurfaceFlinger;
using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService.Types.Fbshare;
using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService
{
@@ -7,6 +14,9 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService
#pragma warning disable IDE0052 // Remove unread private member
private readonly IApplicationDisplayService _applicationDisplayService;
#pragma warning restore IDE0052
private KEvent _sharedFramebufferAcquirableEvent;
private int _sharedFramebufferAcquirableEventHandle;
public ISystemDisplayService(IApplicationDisplayService applicationDisplayService)
{
@@ -57,5 +67,138 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService
return ResultCode.Success;
}
[CommandCmif(8225)] // 4.0.0+
// GetSharedBufferMemoryHandleId()
public ResultCode GetSharedBufferMemoryHandleId(ServiceCtx context)
{
context.ResponseData.Write((ulong)context.Device.System.ViServerS.GetSharedBufferNvMapId());
context.ResponseData.Write(context.Device.System.ViServerS.GetSharedBufferSize());
(ulong mapAddress, ulong mapSize) = context.Request.GetBufferType0x22();
context.Memory.Write(mapAddress, context.Device.System.ViServerS.GetSharedBufferMap());
return ResultCode.Success;
}
[CommandCmif(8250)] // 4.0.0+
// OpenSharedLayer(nn::vi::fbshare::SharedLayerHandle, nn::applet::AppletResourceUserId, pid)
public ResultCode OpenSharedLayer(ServiceCtx context)
{
long sharedLayerHandle = context.RequestData.ReadInt64();
long appletResourceUserId = context.RequestData.ReadInt64();
context.Device.System.ViServerS.OpenSharedLayer(sharedLayerHandle);
return ResultCode.Success;
}
[CommandCmif(8251)] // 4.0.0+
// CloseSharedLayer(nn::vi::fbshare::SharedLayerHandle)
public ResultCode CloseSharedLayer(ServiceCtx context)
{
long sharedLayerHandle = context.RequestData.ReadInt64();
context.Device.System.ViServerS.CloseSharedLayer(sharedLayerHandle);
return ResultCode.Success;
}
[CommandCmif(8252)] // 4.0.0+
// ConnectSharedLayer(nn::vi::fbshare::SharedLayerHandle)
public ResultCode ConnectSharedLayer(ServiceCtx context)
{
long sharedLayerHandle = context.RequestData.ReadInt64();
context.Device.System.ViServerS.ConnectSharedLayer(sharedLayerHandle);
return ResultCode.Success;
}
[CommandCmif(8253)] // 4.0.0+
// DisconnectSharedLayer(nn::vi::fbshare::SharedLayerHandle)
public ResultCode DisconnectSharedLayer(ServiceCtx context)
{
long sharedLayerHandle = context.RequestData.ReadInt64();
context.Device.System.ViServerS.DisconnectSharedLayer(sharedLayerHandle);
return ResultCode.Success;
}
[CommandCmif(8254)] // 4.0.0+
// AcquireSharedFrameBuffer(nn::vi::fbshare::SharedLayerHandle) -> (nn::vi::native::NativeSync, nn::vi::fbshare::SharedLayerTextureIndexList, u64)
public ResultCode AcquireSharedFrameBuffer(ServiceCtx context)
{
long sharedLayerHandle = context.RequestData.ReadInt64();
int slot = context.Device.System.ViServerS.DequeueFrameBuffer(sharedLayerHandle, out AndroidFence fence);
var indexList = new SharedLayerTextureIndexList();
for (int i = 0; i < indexList.Indices.Length; i++)
{
indexList.Indices[i] = context.Device.System.ViServerS.GetFrameBufferMapIndex(i);
}
context.ResponseData.WriteStruct(fence);
context.ResponseData.WriteStruct(indexList);
context.ResponseData.Write(0); // Padding
context.ResponseData.Write((ulong)slot);
return ResultCode.Success;
}
[CommandCmif(8255)] // 4.0.0+
// PresentSharedFrameBuffer(nn::vi::native::NativeSync, nn::vi::CropRegion, u32, u32, nn::vi::fbshare::SharedLayerHandle, u64)
public ResultCode PresentSharedFrameBuffer(ServiceCtx context)
{
AndroidFence nativeSync = context.RequestData.ReadStruct<AndroidFence>();
Rect cropRegion = context.RequestData.ReadStruct<Rect>();
NativeWindowTransform transform = (NativeWindowTransform)context.RequestData.ReadUInt32();
int swapInterval = context.RequestData.ReadInt32();
int padding = context.RequestData.ReadInt32();
long sharedLayerHandle = context.RequestData.ReadInt64();
ulong slot = context.RequestData.ReadUInt64();
context.Device.System.ViServerS.QueueFrameBuffer(sharedLayerHandle, (int)slot, cropRegion, transform, swapInterval, nativeSync);
return ResultCode.Success;
}
[CommandCmif(8256)] // 4.0.0+
// GetSharedFrameBufferAcquirableEvent(nn::vi::fbshare::SharedLayerHandle) -> handle<copy>
public ResultCode GetSharedFrameBufferAcquirableEvent(ServiceCtx context)
{
if (_sharedFramebufferAcquirableEventHandle == 0)
{
_sharedFramebufferAcquirableEvent = new KEvent(context.Device.System.KernelContext);
_sharedFramebufferAcquirableEvent.WritableEvent.Signal();
if (context.Process.HandleTable.GenerateHandle(_sharedFramebufferAcquirableEvent.ReadableEvent, out _sharedFramebufferAcquirableEventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_sharedFramebufferAcquirableEventHandle);
return ResultCode.Success;
}
[CommandCmif(8258)] // 5.0.0+
// CancelSharedFrameBuffer(nn::vi::fbshare::SharedLayerHandle, u64)
public ResultCode CancelSharedFrameBuffer(ServiceCtx context)
{
long sharedLayerHandle = context.RequestData.ReadInt64();
ulong slot = context.RequestData.ReadUInt64();
context.Device.System.ViServerS.CancelFrameBuffer(sharedLayerHandle, (int)slot);
return ResultCode.Success;
}
}
}

View File

@@ -0,0 +1,11 @@
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService.Types.Fbshare
{
[StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x4)]
struct SharedLayerTextureIndexList
{
public Array4<int> Indices;
}
}

View File

@@ -0,0 +1,19 @@
using Ryujinx.Common.Memory;
namespace Ryujinx.HLE.HOS.Services.Vi.Types
{
struct SharedBufferMap
{
public struct Entry
{
public ulong Offset;
public ulong Size;
public uint Width;
public uint Height;
}
public int Count;
public int Padding;
public Array16<Entry> SharedBuffers;
}
}

View File

@@ -0,0 +1,234 @@
using Ryujinx.Common;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
using Ryujinx.HLE.HOS.Services.SurfaceFlinger;
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
using Ryujinx.HLE.HOS.Services.Vi.Types;
using System.Runtime.CompilerServices;
namespace Ryujinx.HLE.HOS.Services
{
class ViServer : ServerBase
{
private const int TotalFramebuffers = 16;
private SurfaceFlinger.SurfaceFlinger _surfaceFlinger;
private readonly uint _fbWidth;
private readonly uint _fbHeight;
private readonly PixelFormat _fbFormat;
private readonly int _fbUsage;
private readonly uint _fbCount;
private uint _fbSlotsRequested;
private ulong _pid;
private ulong _fbsBaseAddress;
private int _bufferNvMapId;
private SharedBufferMap _bufferMap;
private long _sharedLayerId;
public ViServer(KernelContext context, string name) : base(context, name)
{
_fbWidth = 1280;
_fbHeight = 720;
_fbFormat = PixelFormat.Rgba8888;
_fbUsage = 0x100 | 0x200 | 0x800;
_fbCount = 4;
}
protected override ulong CalculateRequiredHeapSize()
{
return GetSharedBufferSize();
}
protected override void CustomInit(KernelContext context, ulong pid, ulong heapAddress)
{
_pid = pid;
_fbsBaseAddress = heapAddress;
context.Device.Gpu.RegisterProcess(pid, KernelStatic.GetCurrentProcess().CpuMemory);
ulong bufferSize = CalculateFramebufferSize();
ulong totalSize = bufferSize * TotalFramebuffers;
KernelStatic.GetCurrentProcess().CpuMemory.Fill(heapAddress, totalSize, 0xff);
int mapId = NvMapDeviceFile.CreateMap(pid, heapAddress, (uint)totalSize);
_bufferNvMapId = mapId;
_bufferMap.Count = TotalFramebuffers;
ulong offset = 0;
for (int i = 0; i < TotalFramebuffers; i++)
{
_bufferMap.SharedBuffers[i].Offset = offset;
_bufferMap.SharedBuffers[i].Size = bufferSize;
_bufferMap.SharedBuffers[i].Width = _fbWidth;
_bufferMap.SharedBuffers[i].Height = _fbHeight;
offset += bufferSize;
}
_surfaceFlinger = context.Device.System.SurfaceFlinger;
_surfaceFlinger.CreateLayer(out _sharedLayerId, pid);
}
public void OpenSharedLayer(long layerId)
{
_surfaceFlinger.OpenLayer(_pid, layerId, out _);
}
public void CloseSharedLayer(long layerId)
{
_surfaceFlinger.CloseLayer(layerId);
}
public void ConnectSharedLayer(long layerId)
{
var producer = _surfaceFlinger.GetProducerByLayerId(layerId);
producer.Connect(null, NativeWindowApi.NVN, false, out var output);
GraphicBuffer graphicBuffer = new GraphicBuffer();
int gobHeightLog2 = 4;
int blockHeight = 8 * (1 << gobHeightLog2);
uint widthAlignedBytes = BitUtils.AlignUp(_fbWidth * 4, 64u);
uint widthAligned = widthAlignedBytes / 4;
uint heightAligned = BitUtils.AlignUp(_fbHeight, (uint)blockHeight);
uint totalSize = widthAlignedBytes * heightAligned;
graphicBuffer.Header.Magic = 0x47424652;
graphicBuffer.Header.Width = (int)_fbWidth;
graphicBuffer.Header.Height = (int)_fbHeight;
graphicBuffer.Header.Stride = (int)widthAligned;
graphicBuffer.Header.Format = _fbFormat;
graphicBuffer.Header.Usage = _fbUsage;
graphicBuffer.Header.IntsCount = (Unsafe.SizeOf<GraphicBuffer>() - Unsafe.SizeOf<GraphicBufferHeader>()) / sizeof(int);
graphicBuffer.Buffer.NvMapId = _bufferNvMapId;
graphicBuffer.Buffer.Magic = unchecked((int)0xDAFFCAFF);
graphicBuffer.Buffer.Pid = 42;
graphicBuffer.Buffer.Usage = _fbUsage;
graphicBuffer.Buffer.PixelFormat = (int)_fbFormat;
graphicBuffer.Buffer.ExternalPixelFormat = (int)_fbFormat;
graphicBuffer.Buffer.Stride = (int)widthAligned;
graphicBuffer.Buffer.FrameBufferSize = (int)totalSize;
graphicBuffer.Buffer.PlanesCount = 1;
graphicBuffer.Buffer.Surfaces[0].Width = _fbWidth;
graphicBuffer.Buffer.Surfaces[0].Height = _fbHeight;
graphicBuffer.Buffer.Surfaces[0].ColorFormat = ColorFormat.A8B8G8R8;
graphicBuffer.Buffer.Surfaces[0].Layout = 3; // Block linear
graphicBuffer.Buffer.Surfaces[0].Pitch = (int)widthAlignedBytes;
graphicBuffer.Buffer.Surfaces[0].Kind = 0xfe; // Generic 16Bx2
graphicBuffer.Buffer.Surfaces[0].BlockHeightLog2 = gobHeightLog2;
graphicBuffer.Buffer.Surfaces[0].Size = (int)totalSize;
for (int slot = 0; slot < _fbCount; slot++)
{
graphicBuffer.Buffer.Surfaces[0].Offset = slot * (int)totalSize;
producer.SetPreallocatedBuffer(slot, new AndroidStrongPointer<GraphicBuffer>(graphicBuffer));
}
_fbSlotsRequested = 0;
}
public void DisconnectSharedLayer(long layerId)
{
var producer = _surfaceFlinger.GetProducerByLayerId(layerId);
producer.Disconnect(NativeWindowApi.NVN);
}
public int DequeueFrameBuffer(long layerId, out AndroidFence fence)
{
var producer = _surfaceFlinger.GetProducerByLayerId(layerId);
Status status = producer.DequeueBuffer(out int slot, out fence, false, _fbWidth, _fbHeight, _fbFormat, (uint)_fbUsage);
if (status == Status.Success)
{
if ((_fbSlotsRequested & (1u << slot)) == 0)
{
status = producer.RequestBuffer(slot, out _);
if (status != Status.Success)
{
producer.CancelBuffer(slot, ref fence);
}
_fbSlotsRequested |= 1u << slot;
}
}
return slot;
}
public void QueueFrameBuffer(long layerId, int slot, Rect crop, NativeWindowTransform transform, int swapInterval, AndroidFence fence)
{
var producer = _surfaceFlinger.GetProducerByLayerId(layerId);
var input = new IGraphicBufferProducer.QueueBufferInput();
input.Crop = crop;
input.Transform = transform;
input.SwapInterval = swapInterval;
input.Fence = fence;
Status status = producer.QueueBuffer(slot, ref input, out _);
}
public void CancelFrameBuffer(long layerId, int slot)
{
var producer = _surfaceFlinger.GetProducerByLayerId(layerId);
AndroidFence fence = default;
producer.CancelBuffer(slot, ref fence);
}
public int GetFrameBufferMapIndex(int index)
{
return (uint)index < _fbCount ? index : 0;
}
public int GetSharedBufferNvMapId()
{
return _bufferNvMapId;
}
public ulong GetSharedBufferSize()
{
return CalculateFramebufferSize() * TotalFramebuffers;
}
public long GetSharedLayerId()
{
return _sharedLayerId;
}
private ulong CalculateFramebufferSize()
{
// Each GOB dimension is 512 bytes x 8 lines.
// Assume 16 GOBs, for a total of 16 x 8 = 128 lines.
return BitUtils.AlignUp(_fbWidth * 4, 512u) * BitUtils.AlignUp(_fbHeight, 128u);
}
public SharedBufferMap GetSharedBufferMap()
{
return _bufferMap;
}
public int GetApplicationLastPresentedFrameHandle(GpuContext gpuContext)
{
var texture = gpuContext.Window.GetLastPresentedData();
var selfAs = KernelStatic.GetProcessByPid(_pid).CpuMemory;
int fbIndex = (int)_fbCount; // Place it after all our frame buffers.
selfAs.Write(_fbsBaseAddress + _bufferMap.SharedBuffers[fbIndex].Offset, texture.Data);
return fbIndex;
}
}
}