diff --git a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs index 1320a04af..1278b5bc7 100644 --- a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs +++ b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs @@ -17,8 +17,8 @@ namespace Ryujinx.Graphics.Metal private readonly RenderPipelineCache _renderPipelineCache; private readonly DepthStencilCache _depthStencilCache; - private EncoderState _currentState = new(); - private EncoderState _backState = new(); + public EncoderState _currentState = new(); + public List _backStates = new(); public readonly MTLBuffer IndexBuffer => _currentState.IndexBuffer; public readonly MTLIndexType IndexType => _currentState.IndexType; @@ -34,13 +34,20 @@ namespace Ryujinx.Graphics.Metal _depthStencilCache = new(device); } - public void SwapStates() + public void SaveState() { - (_currentState, _backState) = (_backState, _currentState); + _backStates.Add(_currentState); + } - if (_pipeline.CurrentEncoderType == EncoderType.Render) + public void RestoreState() + { + if (_backStates.Count > 0) { - _pipeline.EndCurrentPass(); + _currentState = _backStates[_backStates.Count - 1]; + _backStates.RemoveAt(_backStates.Count - 1); + } else + { + Logger.Error?.Print(LogClass.Gpu, "No state to restore"); } } diff --git a/src/Ryujinx.Graphics.Metal/HelperShader.cs b/src/Ryujinx.Graphics.Metal/HelperShader.cs index 2537d6f36..d5446f615 100644 --- a/src/Ryujinx.Graphics.Metal/HelperShader.cs +++ b/src/Ryujinx.Graphics.Metal/HelperShader.cs @@ -64,12 +64,17 @@ namespace Ryujinx.Graphics.Metal MipFilter = MTLSamplerMipFilter.NotMipmapped }); + // Save current state + _pipeline.SaveState(); + _pipeline.SetProgram(_programColorBlit); _pipeline.SetRenderTargets([destination], null); _pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, source, new Sampler(sampler)); _pipeline.SetPrimitiveTopology(PrimitiveTopology.Triangles); _pipeline.Draw(6, 1, 0, 0); - _pipeline.Finish(); + + // Restore previous state + _pipeline.RestoreState(); } public unsafe void ClearColor( @@ -91,6 +96,9 @@ namespace Ryujinx.Graphics.Metal var handle = buffer.NativePtr; var range = new BufferRange(Unsafe.As(ref handle), 0, ClearColorBufferSize); + // Save current state + _pipeline.SaveState(); + _pipeline.SetUniformBuffers([new BufferAssignment(0, range)]); _pipeline.SetProgram(_programColorClear); @@ -98,7 +106,9 @@ namespace Ryujinx.Graphics.Metal // _pipeline.SetRenderTargetColorMasks([componentMask]); _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip); _pipeline.Draw(4, 1, 0, 0); - _pipeline.Finish(); + + // Restore previous state + _pipeline.RestoreState(); } public unsafe void ClearDepthStencil( @@ -123,15 +133,19 @@ namespace Ryujinx.Graphics.Metal var handle = buffer.NativePtr; var range = new BufferRange(Unsafe.As(ref handle), 0, ClearColorBufferSize); + // Save current state + _pipeline.SaveState(); + _pipeline.SetUniformBuffers([new BufferAssignment(0, range)]); _pipeline.SetProgram(_programDepthStencilClear); - _pipeline.SetRenderTargets([], dst); _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip); _pipeline.SetDepthTest(new DepthTestDescriptor(true, depthMask, CompareOp.Always)); // _pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xFF, stencilMask)); _pipeline.Draw(4, 1, 0, 0); - _pipeline.Finish(); + + // Restore previous state + _pipeline.RestoreState(); } private static StencilTestDescriptor CreateStencilTestDescriptor( diff --git a/src/Ryujinx.Graphics.Metal/Pipeline.cs b/src/Ryujinx.Graphics.Metal/Pipeline.cs index e782c9540..e3e392177 100644 --- a/src/Ryujinx.Graphics.Metal/Pipeline.cs +++ b/src/Ryujinx.Graphics.Metal/Pipeline.cs @@ -46,6 +46,16 @@ namespace Ryujinx.Graphics.Metal _encoderStateManager = new EncoderStateManager(_device, this); } + public void SaveState() + { + _encoderStateManager.SaveState(); + } + + public void RestoreState() + { + _encoderStateManager.RestoreState(); + } + public MTLRenderCommandEncoder GetOrCreateRenderEncoder() { MTLRenderCommandEncoder renderCommandEncoder; @@ -161,7 +171,7 @@ namespace Ryujinx.Graphics.Metal EndCurrentPass(); - _encoderStateManager.SwapStates(); + SaveState(); // 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); @@ -169,15 +179,14 @@ namespace Ryujinx.Graphics.Metal _helperShader.BlitColor(tex, dest); + EndCurrentPass(); + _commandBuffer.PresentDrawable(drawable); _commandBuffer.Commit(); _commandBuffer = _commandQueue.CommandBuffer(); - } - public void Finish() - { - _encoderStateManager.SwapStates(); + RestoreState(); } public void Barrier() @@ -207,8 +216,6 @@ namespace Ryujinx.Graphics.Metal Texture target = _encoderStateManager.RenderTargets[index]; - _encoderStateManager.SwapStates(); - _helperShader.ClearColor(target, colors); } @@ -216,8 +223,6 @@ namespace Ryujinx.Graphics.Metal { Texture target = _encoderStateManager.DepthStencil; - _encoderStateManager.SwapStates(); - _helperShader.ClearDepthStencil(target, [depthValue], depthMask, stencilValue, stencilMask); }