From 918e1c16b76c9c99fdda0d89d3548b6189b57a82 Mon Sep 17 00:00:00 2001 From: Samuliak Date: Sun, 19 May 2024 08:08:12 +0200 Subject: [PATCH] don't end render pass when not neccessary --- src/Ryujinx.Graphics.Metal/EncoderState.cs | 16 ++ .../EncoderStateManager.cs | 210 ++++++------------ src/Ryujinx.Graphics.Metal/Pipeline.cs | 13 +- 3 files changed, 97 insertions(+), 142 deletions(-) diff --git a/src/Ryujinx.Graphics.Metal/EncoderState.cs b/src/Ryujinx.Graphics.Metal/EncoderState.cs index fabbe1c4f..f723bb0ac 100644 --- a/src/Ryujinx.Graphics.Metal/EncoderState.cs +++ b/src/Ryujinx.Graphics.Metal/EncoderState.cs @@ -5,6 +5,19 @@ using System.Runtime.Versioning; namespace Ryujinx.Graphics.Metal { + // TODO: use this (unused right now) + public struct DirtyFlags + { + public bool Pipeline = false; + public bool DepthStencil = false; + public bool CullMode = false; + public bool Winding = false; + public bool Viewport = false; + public bool Scissor = false; + + public DirtyFlags() { } + } + [SupportedOSPlatform("macos")] public struct EncoderState { @@ -52,6 +65,9 @@ namespace Ryujinx.Graphics.Metal public VertexBufferDescriptor[] VertexBuffers = []; public VertexAttribDescriptor[] VertexAttribs = []; + // Dirty flags + public DirtyFlags Dirty = new(); + public EncoderState() { } } } diff --git a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs index e13b3cde6..b26b8803e 100644 --- a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs +++ b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs @@ -54,7 +54,80 @@ namespace Ryujinx.Graphics.Metal var passAttachment = renderPassDescriptor.ColorAttachments.Object((ulong)i); passAttachment.Texture = _currentState.RenderTargets[i]; passAttachment.LoadAction = MTLLoadAction.Load; + } + } + var depthAttachment = renderPassDescriptor.DepthAttachment; + var stencilAttachment = renderPassDescriptor.StencilAttachment; + + if (_currentState.DepthStencil != IntPtr.Zero) + { + switch (_currentState.DepthStencil.PixelFormat) + { + // Depth Only Attachment + case MTLPixelFormat.Depth16Unorm: + case MTLPixelFormat.Depth32Float: + depthAttachment.Texture = _currentState.DepthStencil; + depthAttachment.LoadAction = MTLLoadAction.Load; + break; + + // Stencil Only Attachment + case MTLPixelFormat.Stencil8: + stencilAttachment.Texture = _currentState.DepthStencil; + stencilAttachment.LoadAction = MTLLoadAction.Load; + break; + + // Combined Attachment + case MTLPixelFormat.Depth24UnormStencil8: + case MTLPixelFormat.Depth32FloatStencil8: + depthAttachment.Texture = _currentState.DepthStencil; + depthAttachment.LoadAction = MTLLoadAction.Load; + + var unpackedFormat = FormatTable.PackedStencilToXFormat(_currentState.DepthStencil.PixelFormat); + var stencilView = _currentState.DepthStencil.NewTextureView(unpackedFormat); + stencilAttachment.Texture = stencilView; + stencilAttachment.LoadAction = MTLLoadAction.Load; + break; + default: + Logger.Error?.PrintMsg(LogClass.Gpu, $"Unsupported Depth/Stencil Format: {_currentState.DepthStencil.PixelFormat}!"); + break; + } + } + + // Initialise Encoder + + var renderCommandEncoder = _pipeline.CommandBuffer.RenderCommandEncoder(renderPassDescriptor); + + // TODO: set dirty flags all to true + + return renderCommandEncoder; + } + + public void RebindState(MTLRenderCommandEncoder renderCommandEncoder) + { + SetPipelineState(renderCommandEncoder); + SetDepthStencilState(renderCommandEncoder, _currentState.DepthStencilState); + SetDepthClamp(renderCommandEncoder, _currentState.DepthClipMode); + SetScissors(renderCommandEncoder, _currentState.Scissors); + SetViewports(renderCommandEncoder, _currentState.Viewports); + SetVertexBuffers(renderCommandEncoder, _currentState.VertexBuffers); + SetBuffers(renderCommandEncoder, _currentState.UniformBuffers, true); + SetBuffers(renderCommandEncoder, _currentState.StorageBuffers, true); + SetCullMode(renderCommandEncoder, _currentState.CullMode); + SetFrontFace(renderCommandEncoder, _currentState.Winding); + SetTextureAndSampler(renderCommandEncoder, ShaderStage.Vertex, _currentState.VertexTextures, _currentState.VertexSamplers); + SetTextureAndSampler(renderCommandEncoder, ShaderStage.Fragment, _currentState.FragmentTextures, _currentState.FragmentSamplers); + + _currentState.Dirty = new(); + } + + private void SetPipelineState(MTLRenderCommandEncoder renderCommandEncoder) { + var renderPipelineDescriptor = new MTLRenderPipelineDescriptor(); + + for (int i = 0; i < EncoderState.MaxColorAttachments; i++) + { + if (_currentState.RenderTargets[i] != IntPtr.Zero) + { var pipelineAttachment = renderPipelineDescriptor.ColorAttachments.Object((ulong)i); pipelineAttachment.PixelFormat = _currentState.RenderTargets[i].PixelFormat; pipelineAttachment.SourceAlphaBlendFactor = MTLBlendFactor.SourceAlpha; @@ -75,9 +148,6 @@ namespace Ryujinx.Graphics.Metal } } - var depthAttachment = renderPassDescriptor.DepthAttachment; - var stencilAttachment = renderPassDescriptor.StencilAttachment; - if (_currentState.DepthStencil != IntPtr.Zero) { switch (_currentState.DepthStencil.PixelFormat) @@ -85,29 +155,17 @@ namespace Ryujinx.Graphics.Metal // Depth Only Attachment case MTLPixelFormat.Depth16Unorm: case MTLPixelFormat.Depth32Float: - depthAttachment.Texture = _currentState.DepthStencil; - depthAttachment.LoadAction = MTLLoadAction.Load; renderPipelineDescriptor.DepthAttachmentPixelFormat = _currentState.DepthStencil.PixelFormat; break; // Stencil Only Attachment case MTLPixelFormat.Stencil8: - stencilAttachment.Texture = _currentState.DepthStencil; - stencilAttachment.LoadAction = MTLLoadAction.Load; renderPipelineDescriptor.StencilAttachmentPixelFormat = _currentState.DepthStencil.PixelFormat; break; // Combined Attachment case MTLPixelFormat.Depth24UnormStencil8: case MTLPixelFormat.Depth32FloatStencil8: - depthAttachment.Texture = _currentState.DepthStencil; - depthAttachment.LoadAction = MTLLoadAction.Load; - - var unpackedFormat = FormatTable.PackedStencilToXFormat(_currentState.DepthStencil.PixelFormat); - var stencilView = _currentState.DepthStencil.NewTextureView(unpackedFormat); - stencilAttachment.Texture = stencilView; - stencilAttachment.LoadAction = MTLLoadAction.Load; - renderPipelineDescriptor.DepthAttachmentPixelFormat = _currentState.DepthStencil.PixelFormat; renderPipelineDescriptor.StencilAttachmentPixelFormat = _currentState.DepthStencil.PixelFormat; break; @@ -125,7 +183,7 @@ namespace Ryujinx.Graphics.Metal } else { - return new(IntPtr.Zero); + return; } if (_currentState.FragmentFunction != null) @@ -140,10 +198,6 @@ namespace Ryujinx.Graphics.Metal Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Render Pipeline State: {StringHelper.String(error.LocalizedDescription)}"); } - // Initialise Encoder - - var renderCommandEncoder = _pipeline.CommandBuffer.RenderCommandEncoder(renderPassDescriptor); - renderCommandEncoder.SetRenderPipelineState(pipelineState); renderCommandEncoder.SetBlendColor( @@ -151,20 +205,6 @@ namespace Ryujinx.Graphics.Metal _currentState.BlendColor.Green, _currentState.BlendColor.Blue, _currentState.BlendColor.Alpha); - - SetDepthStencilState(renderCommandEncoder, _currentState.DepthStencilState); - SetDepthClamp(renderCommandEncoder, _currentState.DepthClipMode); - SetScissors(renderCommandEncoder, _currentState.Scissors); - SetViewports(renderCommandEncoder, _currentState.Viewports); - SetVertexBuffers(renderCommandEncoder, _currentState.VertexBuffers); - SetBuffers(renderCommandEncoder, _currentState.UniformBuffers, true); - SetBuffers(renderCommandEncoder, _currentState.StorageBuffers, true); - SetCullMode(renderCommandEncoder, _currentState.CullMode); - SetFrontFace(renderCommandEncoder, _currentState.Winding); - SetTextureAndSampler(renderCommandEncoder, ShaderStage.Vertex, _currentState.VertexTextures, _currentState.VertexSamplers); - SetTextureAndSampler(renderCommandEncoder, ShaderStage.Fragment, _currentState.FragmentTextures, _currentState.FragmentSamplers); - - return renderCommandEncoder; } public void UpdateIndexBuffer(BufferRange buffer, IndexType type) @@ -195,12 +235,6 @@ namespace Ryujinx.Graphics.Metal _currentState.VertexFunction = prg.VertexFunction; _currentState.FragmentFunction = prg.FragmentFunction; - - // Requires recreating pipeline - if (_pipeline.CurrentEncoderType == EncoderType.Render) - { - _pipeline.EndCurrentPass(); - } } public void UpdateRenderTargets(ITexture[] colors, ITexture depthStencil) @@ -232,24 +266,12 @@ namespace Ryujinx.Graphics.Metal public void UpdateVertexAttribs(ReadOnlySpan vertexAttribs) { _currentState.VertexAttribs = vertexAttribs.ToArray(); - - // Requires recreating pipeline - if (_pipeline.CurrentEncoderType == EncoderType.Render) - { - _pipeline.EndCurrentPass(); - } } public void UpdateBlendDescriptors(int index, BlendDescriptor blend) { _currentState.BlendDescriptors[index] = blend; _currentState.BlendColor = blend.BlendConstant; - - // Requires recreating pipeline - if (_pipeline.CurrentEncoderType == EncoderType.Render) - { - _pipeline.EndCurrentPass(); - } } // Inlineable @@ -290,14 +312,6 @@ namespace Ryujinx.Graphics.Metal } _currentState.DepthStencilState = _device.NewDepthStencilState(descriptor); - - // Inline Update - - if (_pipeline.CurrentEncoderType == EncoderType.Render && _pipeline.CurrentEncoder != null) - { - var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value); - SetDepthStencilState(renderCommandEncoder, _currentState.DepthStencilState); - } } // Inlineable @@ -319,27 +333,12 @@ namespace Ryujinx.Graphics.Metal } _currentState.DepthStencilState = _device.NewDepthStencilState(descriptor); - - // Inline Update - - if (_pipeline.CurrentEncoderType == EncoderType.Render && _pipeline.CurrentEncoder != null) - { - var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value); - SetDepthStencilState(renderCommandEncoder, _currentState.DepthStencilState); - } } // Inlineable public void UpdateDepthClamp(bool clamp) { _currentState.DepthClipMode = clamp ? MTLDepthClipMode.Clamp : MTLDepthClipMode.Clip; - - // Inline Update - - if (_pipeline.CurrentEncoderType == EncoderType.Render && _pipeline.CurrentEncoder != null) - { - var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value); - } } // Inlineable @@ -366,14 +365,6 @@ namespace Ryujinx.Graphics.Metal y = (ulong)region.Y }; } - - // Inline Update - - if (_pipeline.CurrentEncoderType == EncoderType.Render && _pipeline.CurrentEncoder != null) - { - var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value); - SetScissors(renderCommandEncoder, _currentState.Scissors); - } } // Inlineable @@ -399,25 +390,11 @@ namespace Ryujinx.Graphics.Metal zfar = Clamp(viewport.DepthFar) }; } - - // Inline Update - - if (_pipeline.CurrentEncoderType == EncoderType.Render && _pipeline.CurrentEncoder != null) - { - var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value); - SetViewports(renderCommandEncoder, _currentState.Viewports); - } } public void UpdateVertexBuffers(ReadOnlySpan vertexBuffers) { _currentState.VertexBuffers = vertexBuffers.ToArray(); - - // Requires recreating pipeline - if (_pipeline.CurrentEncoderType == EncoderType.Render) - { - _pipeline.EndCurrentPass(); - } } // Inlineable @@ -437,14 +414,6 @@ namespace Ryujinx.Graphics.Metal }); } } - - // Inline Update - - if (_pipeline.CurrentEncoderType == EncoderType.Render && _pipeline.CurrentEncoder != null) - { - var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value); - SetBuffers(renderCommandEncoder, _currentState.UniformBuffers, true); - } } // Inlineable @@ -465,42 +434,18 @@ namespace Ryujinx.Graphics.Metal }); } } - - // Inline Update - - if (_pipeline.CurrentEncoderType == EncoderType.Render && _pipeline.CurrentEncoder != null) - { - var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value); - SetBuffers(renderCommandEncoder, _currentState.StorageBuffers, true); - } } // Inlineable public void UpdateCullMode(bool enable, Face face) { _currentState.CullMode = enable ? face.Convert() : MTLCullMode.None; - - // Inline Update - - if (_pipeline.CurrentEncoderType == EncoderType.Render && _pipeline.CurrentEncoder != null) - { - var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value); - SetCullMode(renderCommandEncoder, _currentState.CullMode); - } } // Inlineable public void UpdateFrontFace(FrontFace frontFace) { _currentState.Winding = frontFace.Convert(); - - // Inline Update - - if (_pipeline.CurrentEncoderType == EncoderType.Render && _pipeline.CurrentEncoder != null) - { - var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value); - SetFrontFace(renderCommandEncoder, _currentState.Winding); - } } // Inlineable @@ -517,13 +462,6 @@ namespace Ryujinx.Graphics.Metal _currentState.VertexSamplers[binding] = sampler; break; } - - if (_pipeline.CurrentEncoderType == EncoderType.Render && _pipeline.CurrentEncoder != null) - { - var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value); - SetTextureAndSampler(renderCommandEncoder, ShaderStage.Vertex, _currentState.VertexTextures, _currentState.VertexSamplers); - SetTextureAndSampler(renderCommandEncoder, ShaderStage.Fragment, _currentState.FragmentTextures, _currentState.FragmentSamplers); - } } private static void SetDepthStencilState(MTLRenderCommandEncoder renderCommandEncoder, MTLDepthStencilState? depthStencilState) diff --git a/src/Ryujinx.Graphics.Metal/Pipeline.cs b/src/Ryujinx.Graphics.Metal/Pipeline.cs index f48efaed8..f1dcd19c0 100644 --- a/src/Ryujinx.Graphics.Metal/Pipeline.cs +++ b/src/Ryujinx.Graphics.Metal/Pipeline.cs @@ -48,15 +48,16 @@ namespace Ryujinx.Graphics.Metal public MTLRenderCommandEncoder GetOrCreateRenderEncoder() { - if (_currentEncoder != null) + if (_currentEncoder == null || _currentEncoderType != EncoderType.Render) { - if (_currentEncoderType == EncoderType.Render) - { - return new MTLRenderCommandEncoder(_currentEncoder.Value); - } + BeginRenderPass(); } - return BeginRenderPass(); + var renderCommandEncoder = new MTLRenderCommandEncoder(_currentEncoder.Value); + + _encoderStateManager.RebindState(renderCommandEncoder); + + return renderCommandEncoder; } public MTLBlitCommandEncoder GetOrCreateBlitEncoder()