Metal: Buffers Take 2 (#21)

* Basic BufferManager

* Start Scoped Command Buffers

* Fences stuff

* Remember to cleanup sync manager

* Auto, Command Buffer Dependants

* Cleanup

* Cleanup + Fix Texture->Buffer Copies

* Slow buffer upload

* Cleanup + Rework TextureBuffer

* Don’t get unsafe

* Cleanup

* Goddamn it

* Staging Buffer + Interrupt Action + Flush
This commit is contained in:
Isaac Marovitz 2024-06-19 23:13:55 +01:00
parent d0946213fa
commit 58b3e2e82b
24 changed files with 2380 additions and 205 deletions

View file

@ -5,12 +5,11 @@ using SharpMetal.Foundation;
using SharpMetal.Metal;
using SharpMetal.QuartzCore;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
enum EncoderType
public enum EncoderType
{
Blit,
Compute,
@ -19,14 +18,19 @@ namespace Ryujinx.Graphics.Metal
}
[SupportedOSPlatform("macos")]
class Pipeline : IPipeline, IDisposable
public class Pipeline : IPipeline, IDisposable
{
private readonly MTLDevice _device;
private readonly MTLCommandQueue _commandQueue;
private readonly HelperShader _helperShader;
private readonly MetalRenderer _renderer;
private MTLCommandBuffer _commandBuffer;
public MTLCommandBuffer CommandBuffer => _commandBuffer;
private CommandBufferScoped Cbs;
private CommandBufferScoped? PreloadCbs;
public MTLCommandBuffer CommandBuffer;
public readonly Action EndRenderPassDelegate;
public CommandBufferScoped CurrentCommandBuffer => Cbs;
private MTLCommandEncoder? _currentEncoder;
public MTLCommandEncoder? CurrentEncoder => _currentEncoder;
@ -36,14 +40,20 @@ namespace Ryujinx.Graphics.Metal
private EncoderStateManager _encoderStateManager;
public Pipeline(MTLDevice device, MTLCommandQueue commandQueue)
public Pipeline(MTLDevice device, MetalRenderer renderer, MTLCommandQueue commandQueue)
{
_device = device;
_renderer = renderer;
_commandQueue = commandQueue;
_helperShader = new HelperShader(_device, this);
_commandBuffer = _commandQueue.CommandBuffer();
_encoderStateManager = new EncoderStateManager(_device, this);
EndRenderPassDelegate = EndCurrentPass;
CommandBuffer = (Cbs = _renderer.CommandBufferPool.Rent()).CommandBuffer;
}
public void InitEncoderStateManager(BufferManager bufferManager)
{
_encoderStateManager = new EncoderStateManager(_device, bufferManager, this);
}
public void SaveState()
@ -156,7 +166,7 @@ namespace Ryujinx.Graphics.Metal
EndCurrentPass();
var descriptor = new MTLBlitPassDescriptor();
var blitCommandEncoder = _commandBuffer.BlitCommandEncoder(descriptor);
var blitCommandEncoder = Cbs.CommandBuffer.BlitCommandEncoder(descriptor);
_currentEncoder = blitCommandEncoder;
_currentEncoderType = EncoderType.Blit;
@ -178,21 +188,35 @@ namespace Ryujinx.Graphics.Metal
{
// TODO: Clean this up
var textureInfo = new TextureCreateInfo((int)drawable.Texture.Width, (int)drawable.Texture.Height, (int)drawable.Texture.Depth, (int)drawable.Texture.MipmapLevelCount, (int)drawable.Texture.SampleCount, 0, 0, 0, Format.B8G8R8A8Unorm, 0, Target.Texture2D, SwizzleComponent.Red, SwizzleComponent.Green, SwizzleComponent.Blue, SwizzleComponent.Alpha);
var dst = new Texture(_device, this, textureInfo, drawable.Texture, 0, 0);
var dst = new Texture(_device, _renderer, this, textureInfo, drawable.Texture, 0, 0);
_helperShader.BlitColor(src, dst, srcRegion, dstRegion, isLinear);
_renderer.HelperShader.BlitColor(src, dst, srcRegion, dstRegion, isLinear);
EndCurrentPass();
_commandBuffer.PresentDrawable(drawable);
_commandBuffer.Commit();
Cbs.CommandBuffer.PresentDrawable(drawable);
_commandBuffer = _commandQueue.CommandBuffer();
CommandBuffer = (Cbs = _renderer.CommandBufferPool.ReturnAndRent(Cbs)).CommandBuffer;
// TODO: Auto flush counting
_renderer.SyncManager.GetAndResetWaitTicks();
// Cleanup
dst.Dispose();
}
public void FlushCommandsImpl()
{
SaveState();
EndCurrentPass();
CommandBuffer = (Cbs = _renderer.CommandBufferPool.ReturnAndRent(Cbs)).CommandBuffer;
_renderer.RegisterFlush();
RestoreState();
}
public void BlitColor(
ITexture src,
ITexture dst,
@ -200,7 +224,7 @@ namespace Ryujinx.Graphics.Metal
Extents2D dstRegion,
bool linearFilter)
{
_helperShader.BlitColor(src, dst, srcRegion, dstRegion, linearFilter);
_renderer.HelperShader.BlitColor(src, dst, srcRegion, dstRegion, linearFilter);
}
public void Barrier()
@ -235,9 +259,10 @@ namespace Ryujinx.Graphics.Metal
{
var blitCommandEncoder = GetOrCreateBlitEncoder();
var mtlBuffer = _renderer.BufferManager.GetBuffer(destination, offset, size, true).Get(Cbs, offset, size, true).Value;
// Might need a closer look, range's count, lower, and upper bound
// must be a multiple of 4
MTLBuffer mtlBuffer = new(Unsafe.As<BufferHandle, IntPtr>(ref destination));
blitCommandEncoder.FillBuffer(mtlBuffer,
new NSRange
{
@ -259,7 +284,7 @@ namespace Ryujinx.Graphics.Metal
return;
}
_helperShader.ClearColor(index, colors, componentMask, dst.Width, dst.Height);
_renderer.HelperShader.ClearColor(index, colors, componentMask, dst.Width, dst.Height);
}
public void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue, int stencilMask)
@ -273,7 +298,7 @@ namespace Ryujinx.Graphics.Metal
return;
}
_helperShader.ClearDepthStencil(depthValue, depthMask, stencilValue, stencilMask, depthStencil.Width, depthStencil.Height);
_renderer.HelperShader.ClearDepthStencil(depthValue, depthMask, stencilValue, stencilMask, depthStencil.Width, depthStencil.Height);
}
public void CommandBufferBarrier()
@ -281,19 +306,12 @@ namespace Ryujinx.Graphics.Metal
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
}
public void CopyBuffer(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size)
public void CopyBuffer(BufferHandle src, BufferHandle dst, int srcOffset, int dstOffset, int size)
{
var blitCommandEncoder = GetOrCreateBlitEncoder();
var srcBuffer = _renderer.BufferManager.GetBuffer(src, srcOffset, size, false);
var dstBuffer = _renderer.BufferManager.GetBuffer(dst, dstOffset, size, true);
MTLBuffer sourceBuffer = new(Unsafe.As<BufferHandle, IntPtr>(ref source));
MTLBuffer destinationBuffer = new(Unsafe.As<BufferHandle, IntPtr>(ref destination));
blitCommandEncoder.CopyFromBuffer(
sourceBuffer,
(ulong)srcOffset,
destinationBuffer,
(ulong)dstOffset,
(ulong)size);
BufferHolder.Copy(this, Cbs, srcBuffer, dstBuffer, srcOffset, dstOffset, size);
}
public void DispatchCompute(int groupsX, int groupsY, int groupsZ, int groupSizeX, int groupSizeY, int groupSizeZ)
@ -327,11 +345,13 @@ namespace Ryujinx.Graphics.Metal
// TODO: Support topology re-indexing to provide support for TriangleFans
var primitiveType = _encoderStateManager.Topology.Convert();
var indexBuffer = _renderer.BufferManager.GetBuffer(_encoderStateManager.IndexBuffer.Handle, false);
renderCommandEncoder.DrawIndexedPrimitives(
primitiveType,
(ulong)indexCount,
_encoderStateManager.IndexType,
_encoderStateManager.IndexBuffer,
indexBuffer.Get(Cbs, 0, indexCount * sizeof(int)).Value,
_encoderStateManager.IndexBufferOffset,
(ulong)instanceCount,
firstVertex,
@ -368,7 +388,7 @@ namespace Ryujinx.Graphics.Metal
public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion)
{
_helperShader.DrawTexture(texture, sampler, srcRegion, dstRegion);
_renderer.HelperShader.DrawTexture(texture, sampler, srcRegion, dstRegion);
}
public void SetAlphaTest(bool enable, float reference, CompareOp op)