PersistentFlushBuffer + BackgroundResources
This commit is contained in:
parent
a638060dee
commit
30b50a99e4
3 changed files with 199 additions and 18 deletions
110
src/Ryujinx.Graphics.Metal/BackgroundResources.cs
Normal file
110
src/Ryujinx.Graphics.Metal/BackgroundResources.cs
Normal file
|
@ -0,0 +1,110 @@
|
|||
using SharpMetal.Metal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Graphics.Metal
|
||||
{
|
||||
[SupportedOSPlatform("macos")]
|
||||
class BackgroundResource : IDisposable
|
||||
{
|
||||
private readonly MetalRenderer _renderer;
|
||||
private readonly Pipeline _pipeline;
|
||||
|
||||
private CommandBufferPool _pool;
|
||||
private PersistentFlushBuffer _flushBuffer;
|
||||
|
||||
public BackgroundResource(MetalRenderer renderer, Pipeline pipeline)
|
||||
{
|
||||
_renderer = renderer;
|
||||
_pipeline = pipeline;
|
||||
}
|
||||
|
||||
public CommandBufferPool GetPool()
|
||||
{
|
||||
if (_pool == null)
|
||||
{
|
||||
MTLCommandQueue queue = _renderer.BackgroundQueue;
|
||||
_pool = new CommandBufferPool(queue.Device, queue);
|
||||
}
|
||||
|
||||
return _pool;
|
||||
}
|
||||
|
||||
public PersistentFlushBuffer GetFlushBuffer()
|
||||
{
|
||||
_flushBuffer ??= new PersistentFlushBuffer(_renderer, _pipeline);
|
||||
|
||||
return _flushBuffer;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_pool?.Dispose();
|
||||
_flushBuffer?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
class BackgroundResources : IDisposable
|
||||
{
|
||||
private readonly MetalRenderer _renderer;
|
||||
private readonly Pipeline _pipeline;
|
||||
|
||||
private readonly Dictionary<Thread, BackgroundResource> _resources;
|
||||
|
||||
public BackgroundResources(MetalRenderer renderer, Pipeline pipeline)
|
||||
{
|
||||
_renderer = renderer;
|
||||
_pipeline = pipeline;
|
||||
|
||||
_resources = new Dictionary<Thread, BackgroundResource>();
|
||||
}
|
||||
|
||||
private void Cleanup()
|
||||
{
|
||||
lock (_resources)
|
||||
{
|
||||
foreach (KeyValuePair<Thread, BackgroundResource> tuple in _resources)
|
||||
{
|
||||
if (!tuple.Key.IsAlive)
|
||||
{
|
||||
tuple.Value.Dispose();
|
||||
_resources.Remove(tuple.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BackgroundResource Get()
|
||||
{
|
||||
Thread thread = Thread.CurrentThread;
|
||||
|
||||
lock (_resources)
|
||||
{
|
||||
if (!_resources.TryGetValue(thread, out BackgroundResource resource))
|
||||
{
|
||||
Cleanup();
|
||||
|
||||
resource = new BackgroundResource(_renderer, _pipeline);
|
||||
|
||||
_resources[thread] = resource;
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (_resources)
|
||||
{
|
||||
foreach (var resource in _resources.Values)
|
||||
{
|
||||
resource.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,20 +17,21 @@ namespace Ryujinx.Graphics.Metal
|
|||
private readonly Func<CAMetalLayer> _getMetalLayer;
|
||||
|
||||
private Pipeline _pipeline;
|
||||
private HelperShader _helperShader;
|
||||
private BufferManager _bufferManager;
|
||||
private Window _window;
|
||||
private CommandBufferPool _commandBufferPool;
|
||||
|
||||
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
|
||||
public bool PreferThreading => true;
|
||||
|
||||
public IPipeline Pipeline => _pipeline;
|
||||
public IWindow Window => _window;
|
||||
public HelperShader HelperShader => _helperShader;
|
||||
public BufferManager BufferManager => _bufferManager;
|
||||
public CommandBufferPool CommandBufferPool => _commandBufferPool;
|
||||
public Action<Action> InterruptAction { get; private set; }
|
||||
public SyncManager SyncManager { get; private set; }
|
||||
|
||||
internal MTLCommandQueue BackgroundQueue { get; private set; }
|
||||
internal HelperShader HelperShader { get; private set; }
|
||||
internal BufferManager BufferManager { get; private set; }
|
||||
internal CommandBufferPool CommandBufferPool { get; private set; }
|
||||
internal BackgroundResources BackgroundResources { get; private set; }
|
||||
internal Action<Action> InterruptAction { get; private set; }
|
||||
internal SyncManager SyncManager { get; private set; }
|
||||
|
||||
public MetalRenderer(Func<CAMetalLayer> metalLayer)
|
||||
{
|
||||
|
@ -42,6 +43,8 @@ namespace Ryujinx.Graphics.Metal
|
|||
}
|
||||
|
||||
_queue = _device.NewCommandQueue(CommandBufferPool.MaxCommandBuffers);
|
||||
BackgroundQueue = _device.NewCommandQueue(CommandBufferPool.MaxCommandBuffers);
|
||||
|
||||
_getMetalLayer = metalLayer;
|
||||
}
|
||||
|
||||
|
@ -51,14 +54,15 @@ namespace Ryujinx.Graphics.Metal
|
|||
layer.Device = _device;
|
||||
layer.FramebufferOnly = false;
|
||||
|
||||
_commandBufferPool = new CommandBufferPool(_device, _queue);
|
||||
CommandBufferPool = new CommandBufferPool(_device, _queue);
|
||||
_window = new Window(this, layer);
|
||||
_pipeline = new Pipeline(_device, this, _queue);
|
||||
_bufferManager = new BufferManager(_device, this, _pipeline);
|
||||
BufferManager = new BufferManager(_device, this, _pipeline);
|
||||
|
||||
_pipeline.InitEncoderStateManager(_bufferManager);
|
||||
_pipeline.InitEncoderStateManager(BufferManager);
|
||||
|
||||
_helperShader = new HelperShader(_device, this, _pipeline);
|
||||
BackgroundResources = new BackgroundResources(this, _pipeline);
|
||||
HelperShader = new HelperShader(_device, this, _pipeline);
|
||||
SyncManager = new SyncManager(this);
|
||||
}
|
||||
|
||||
|
@ -69,12 +73,12 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
public BufferHandle CreateBuffer(int size, BufferAccess access)
|
||||
{
|
||||
return _bufferManager.CreateWithHandle(size);
|
||||
return BufferManager.CreateWithHandle(size);
|
||||
}
|
||||
|
||||
public BufferHandle CreateBuffer(IntPtr pointer, int size)
|
||||
{
|
||||
return _bufferManager.Create(pointer, size);
|
||||
return BufferManager.Create(pointer, size);
|
||||
}
|
||||
|
||||
public BufferHandle CreateBufferSparse(ReadOnlySpan<BufferRange> storageBuffers)
|
||||
|
@ -125,12 +129,12 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
public void DeleteBuffer(BufferHandle buffer)
|
||||
{
|
||||
_bufferManager.Delete(buffer);
|
||||
BufferManager.Delete(buffer);
|
||||
}
|
||||
|
||||
public PinnedSpan<byte> GetBufferData(BufferHandle buffer, int offset, int size)
|
||||
{
|
||||
return _bufferManager.GetData(buffer, offset, size);
|
||||
return BufferManager.GetData(buffer, offset, size);
|
||||
}
|
||||
|
||||
public Capabilities GetCapabilities()
|
||||
|
@ -218,7 +222,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)
|
||||
{
|
||||
_bufferManager.SetData(buffer, offset, data, _pipeline.CurrentCommandBuffer, _pipeline.EndRenderPassDelegate);
|
||||
BufferManager.SetData(buffer, offset, data, _pipeline.CurrentCommandBuffer, _pipeline.EndRenderPassDelegate);
|
||||
}
|
||||
|
||||
public void UpdateCounters()
|
||||
|
@ -259,7 +263,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
SyncManager.RegisterFlush();
|
||||
|
||||
// Periodically free unused regions of the staging buffer to avoid doing it all at once.
|
||||
_bufferManager.StagingBuffer.FreeCompleted();
|
||||
BufferManager.StagingBuffer.FreeCompleted();
|
||||
}
|
||||
|
||||
public void SetInterruptAction(Action<Action> interruptAction)
|
||||
|
@ -274,6 +278,7 @@ namespace Ryujinx.Graphics.Metal
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
BackgroundResources.Dispose();
|
||||
_pipeline.Dispose();
|
||||
_window.Dispose();
|
||||
}
|
||||
|
|
66
src/Ryujinx.Graphics.Metal/PersistentFlushBuffer.cs
Normal file
66
src/Ryujinx.Graphics.Metal/PersistentFlushBuffer.cs
Normal file
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Graphics.Metal
|
||||
{
|
||||
[SupportedOSPlatform("macos")]
|
||||
internal class PersistentFlushBuffer : IDisposable
|
||||
{
|
||||
private readonly MetalRenderer _renderer;
|
||||
private readonly Pipeline _pipeline;
|
||||
|
||||
private BufferHolder _flushStorage;
|
||||
|
||||
public PersistentFlushBuffer(MetalRenderer renderer, Pipeline pipeline)
|
||||
{
|
||||
_renderer = renderer;
|
||||
_pipeline = pipeline;
|
||||
}
|
||||
|
||||
private BufferHolder ResizeIfNeeded(int size)
|
||||
{
|
||||
var flushStorage = _flushStorage;
|
||||
|
||||
if (flushStorage == null || size > _flushStorage.Size)
|
||||
{
|
||||
flushStorage?.Dispose();
|
||||
|
||||
flushStorage = _renderer.BufferManager.Create(size);
|
||||
_flushStorage = flushStorage;
|
||||
}
|
||||
|
||||
return flushStorage;
|
||||
}
|
||||
|
||||
public Span<byte> GetBufferData(CommandBufferPool cbp, BufferHolder buffer, int offset, int size)
|
||||
{
|
||||
var flushStorage = ResizeIfNeeded(size);
|
||||
Auto<DisposableBuffer> srcBuffer;
|
||||
|
||||
using (var cbs = cbp.Rent())
|
||||
{
|
||||
srcBuffer = buffer.GetBuffer();
|
||||
var dstBuffer = flushStorage.GetBuffer();
|
||||
|
||||
if (srcBuffer.TryIncrementReferenceCount())
|
||||
{
|
||||
BufferHolder.Copy(_pipeline, cbs, srcBuffer, dstBuffer, offset, 0, size, registerSrcUsage: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Source buffer is no longer alive, don't copy anything to flush storage.
|
||||
srcBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
flushStorage.WaitForFences();
|
||||
srcBuffer?.DecrementReferenceCount();
|
||||
return flushStorage.GetDataStorage(0, size);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_flushStorage.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue