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:
234
src/Ryujinx.HLE/HOS/Services/Vi/ViServer.cs
Normal file
234
src/Ryujinx.HLE/HOS/Services/Vi/ViServer.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user