One encoder at a time

This commit is contained in:
Isaac Marovitz 2023-07-28 16:23:13 -04:00 committed by Isaac Marovitz
parent e269d1605d
commit f4aea9b7ec
3 changed files with 135 additions and 31 deletions

View file

@ -15,14 +15,11 @@ namespace Ryujinx.Graphics.Metal
private readonly MTLCommandQueue _mtlCommandQueue; private readonly MTLCommandQueue _mtlCommandQueue;
private MTLCommandBuffer _commandBuffer; private MTLCommandBuffer _commandBuffer;
private MTLRenderCommandEncoder _renderCommandEncoder; private MTLCommandEncoder _currentEncoder;
private MTLRenderPipelineState _renderPipelineState;
private MTLBlitCommandEncoder _blitCommandEncoder;
public MTLRenderCommandEncoder RenderCommandEncoder => _renderCommandEncoder; public MTLCommandEncoder CurrentEncoder;
public MTLBlitCommandEncoder BlitCommandEncoder => _blitCommandEncoder;
private PrimitiveTopology _topology; private RenderEncoderState _renderEncoderState;
private MTLBuffer _indexBuffer; private MTLBuffer _indexBuffer;
private MTLIndexType _indexType; private MTLIndexType _indexType;
@ -35,35 +32,57 @@ namespace Ryujinx.Graphics.Metal
var renderPipelineDescriptor = new MTLRenderPipelineDescriptor(); var renderPipelineDescriptor = new MTLRenderPipelineDescriptor();
var error = new NSError(IntPtr.Zero); var error = new NSError(IntPtr.Zero);
_renderPipelineState = _device.NewRenderPipelineState(renderPipelineDescriptor, ref error); _renderEncoderState = new(_device.NewRenderPipelineState(renderPipelineDescriptor, ref error));
if (error != IntPtr.Zero) if (error != IntPtr.Zero)
{ {
// throw new Exception($"Failed to create render pipeline state! {StringHelp}"); // throw new Exception($"Failed to create render pipeline state! {StringHelp}");
throw new Exception($"Failed to create render pipeline state!"); throw new Exception($"Failed to create render pipeline state!");
} }
CreateCommandBuffer(); _commandBuffer = _mtlCommandQueue.CommandBuffer();
}
public void EndCurrentPass()
{
if (_currentEncoder != null)
{
_currentEncoder.EndEncoding();
_currentEncoder = null;
}
}
public MTLRenderCommandEncoder BeginRenderPass()
{
EndCurrentPass();
var descriptor = new MTLRenderPassDescriptor { };
var renderCommandEncoder = _commandBuffer.RenderCommandEncoder(descriptor);
_renderEncoderState.SetEncoderState(renderCommandEncoder);
_currentEncoder = renderCommandEncoder;
return renderCommandEncoder;
}
public MTLBlitCommandEncoder BeginBlitPass()
{
EndCurrentPass();
var descriptor = new MTLBlitPassDescriptor { };
var blitCommandEncoder = _commandBuffer.BlitCommandEncoder(descriptor);
_currentEncoder = blitCommandEncoder;
return blitCommandEncoder;
} }
public void Present() public void Present()
{ {
_renderCommandEncoder.EndEncoding(); EndCurrentPass();
_blitCommandEncoder.EndEncoding();
// TODO: Give command buffer a valid MTLDrawable // TODO: Give command buffer a valid MTLDrawable
// _commandBuffer.PresentDrawable(); // _commandBuffer.PresentDrawable();
_commandBuffer.Commit(); _commandBuffer.Commit();
CreateCommandBuffer();
}
public void CreateCommandBuffer()
{
_commandBuffer = _mtlCommandQueue.CommandBuffer(); _commandBuffer = _mtlCommandQueue.CommandBuffer();
_renderCommandEncoder = _commandBuffer.RenderCommandEncoder(new MTLRenderPassDescriptor());
_renderCommandEncoder.SetRenderPipelineState(_renderPipelineState);
_blitCommandEncoder = _commandBuffer.BlitCommandEncoder(new MTLBlitPassDescriptor());
} }
public void Barrier() public void Barrier()
@ -104,18 +123,40 @@ namespace Ryujinx.Graphics.Metal
public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance) public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
{ {
// TODO: Support topology re-indexing to provide support for TriangleFans MTLRenderCommandEncoder renderCommandEncoder;
var _primitiveType = _topology.Convert();
_renderCommandEncoder.DrawPrimitives(_primitiveType, (ulong)firstVertex, (ulong)vertexCount, (ulong)instanceCount, (ulong)firstInstance); if (_currentEncoder is MTLRenderCommandEncoder encoder)
{
renderCommandEncoder = encoder;
}
else
{
renderCommandEncoder = BeginRenderPass();
}
// TODO: Support topology re-indexing to provide support for TriangleFans
var primitiveType = _renderEncoderState.Topology.Convert();
renderCommandEncoder.DrawPrimitives(primitiveType, (ulong)firstVertex, (ulong)vertexCount, (ulong)instanceCount, (ulong)firstInstance);
} }
public void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int firstVertex, int firstInstance) public void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int firstVertex, int firstInstance)
{ {
// TODO: Support topology re-indexing to provide support for TriangleFans MTLRenderCommandEncoder renderCommandEncoder;
var _primitiveType = _topology.Convert();
_renderCommandEncoder.DrawIndexedPrimitives(_primitiveType, (ulong)indexCount, _indexType, _indexBuffer, _indexBufferOffset, (ulong)instanceCount, firstVertex, (ulong)firstInstance); if (_currentEncoder is MTLRenderCommandEncoder encoder)
{
renderCommandEncoder = encoder;
}
else
{
renderCommandEncoder = BeginRenderPass();
}
// TODO: Support topology re-indexing to provide support for TriangleFans
var primitiveType = _renderEncoderState.Topology.Convert();
renderCommandEncoder.DrawIndexedPrimitives(primitiveType, (ulong)indexCount, _indexType, _indexBuffer, _indexBufferOffset, (ulong)instanceCount, firstVertex, (ulong)firstInstance);
} }
public void DrawIndexedIndirect(BufferRange indirectBuffer) public void DrawIndexedIndirect(BufferRange indirectBuffer)
@ -180,12 +221,26 @@ namespace Ryujinx.Graphics.Metal
public void SetFaceCulling(bool enable, Face face) public void SetFaceCulling(bool enable, Face face)
{ {
_renderCommandEncoder.SetCullMode(enable ? face.Convert() : MTLCullMode.None); var cullMode = enable ? face.Convert() : MTLCullMode.None;
if (_currentEncoder is MTLRenderCommandEncoder renderCommandEncoder)
{
renderCommandEncoder.SetCullMode(cullMode);
}
_renderEncoderState.CullMode = cullMode;
} }
public void SetFrontFace(FrontFace frontFace) public void SetFrontFace(FrontFace frontFace)
{ {
_renderCommandEncoder.SetFrontFacingWinding(frontFace.Convert()); var winding = frontFace.Convert();
if (_currentEncoder is MTLRenderCommandEncoder renderCommandEncoder)
{
renderCommandEncoder.SetFrontFacingWinding(winding);
}
_renderEncoderState.Winding = winding;
} }
public void SetIndexBuffer(BufferRange buffer, IndexType type) public void SetIndexBuffer(BufferRange buffer, IndexType type)
@ -244,7 +299,7 @@ namespace Ryujinx.Graphics.Metal
public void SetPrimitiveTopology(PrimitiveTopology topology) public void SetPrimitiveTopology(PrimitiveTopology topology)
{ {
_topology = topology; _renderEncoderState.Topology = topology;
} }
public void SetProgram(IProgram program) public void SetProgram(IProgram program)

View file

@ -0,0 +1,27 @@
using Ryujinx.Graphics.GAL;
using SharpMetal.Metal;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
struct RenderEncoderState
{
public MTLRenderPipelineState RenderPipelineState;
public PrimitiveTopology Topology = PrimitiveTopology.Triangles;
public MTLCullMode CullMode = MTLCullMode.None;
public MTLWinding Winding = MTLWinding.Clockwise;
public RenderEncoderState(MTLRenderPipelineState renderPipelineState)
{
RenderPipelineState = renderPipelineState;
}
public void SetEncoderState(MTLRenderCommandEncoder renderCommandEncoder)
{
renderCommandEncoder.SetRenderPipelineState(RenderPipelineState);
renderCommandEncoder.SetCullMode(CullMode);
renderCommandEncoder.SetFrontFacingWinding(Winding);
}
}
}

View file

@ -46,9 +46,20 @@ namespace Ryujinx.Graphics.Metal
public void CopyTo(ITexture destination, int firstLayer, int firstLevel) public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
{ {
MTLBlitCommandEncoder blitCommandEncoder;
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
{
blitCommandEncoder = encoder;
}
else
{
blitCommandEncoder = _pipeline.BeginBlitPass();
}
if (destination is Texture destinationTexture) if (destination is Texture destinationTexture)
{ {
_pipeline.BlitCommandEncoder.CopyFromTexture( blitCommandEncoder.CopyFromTexture(
MTLTexture, MTLTexture,
(ulong)firstLayer, (ulong)firstLayer,
(ulong)firstLevel, (ulong)firstLevel,
@ -62,9 +73,20 @@ namespace Ryujinx.Graphics.Metal
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel) public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
{ {
MTLBlitCommandEncoder blitCommandEncoder;
if (_pipeline.CurrentEncoder is MTLBlitCommandEncoder encoder)
{
blitCommandEncoder = encoder;
}
else
{
blitCommandEncoder = _pipeline.BeginBlitPass();
}
if (destination is Texture destinationTexture) if (destination is Texture destinationTexture)
{ {
_pipeline.BlitCommandEncoder.CopyFromTexture( blitCommandEncoder.CopyFromTexture(
MTLTexture, MTLTexture,
(ulong)srcLayer, (ulong)srcLayer,
(ulong)srcLevel, (ulong)srcLevel,