diff --git a/src/Ryujinx.Graphics.Metal/DepthStencilCache.cs b/src/Ryujinx.Graphics.Metal/DepthStencilCache.cs new file mode 100644 index 000000000..8456a9228 --- /dev/null +++ b/src/Ryujinx.Graphics.Metal/DepthStencilCache.cs @@ -0,0 +1,73 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Graphics.GAL; +using SharpMetal.Foundation; +using SharpMetal.Metal; +using System; +using System.Collections.Generic; +using System.Runtime.Versioning; + +namespace Ryujinx.Graphics.Metal +{ + [SupportedOSPlatform("macos")] + public struct DepthStencilHash + { + public struct StencilHash + { + public MTLStencilOperation StencilFailureOperation; + public MTLStencilOperation DepthFailureOperation; + public MTLStencilOperation DepthStencilPassOperation; + public MTLCompareFunction StencilCompareFunction; + public uint ReadMask; + public uint WriteMask; + } + public StencilHash FrontFace; + public StencilHash BackFace; + public MTLCompareFunction DepthCompareFunction; + public bool DepthWriteEnabled; + } + + [SupportedOSPlatform("macos")] + public class DepthStencilCache : StateCache + { + private readonly MTLDevice _device; + + public DepthStencilCache(MTLDevice device) { + _device = device; + } + + protected override DepthStencilHash GetHash(MTLDepthStencilDescriptor descriptor) { + var hash = new DepthStencilHash(); + + // Front face + hash.FrontFace = new DepthStencilHash.StencilHash { + StencilFailureOperation = descriptor.FrontFaceStencil.StencilFailureOperation, + DepthFailureOperation = descriptor.FrontFaceStencil.DepthFailureOperation, + DepthStencilPassOperation = descriptor.FrontFaceStencil.DepthStencilPassOperation, + StencilCompareFunction = descriptor.FrontFaceStencil.StencilCompareFunction, + ReadMask = descriptor.FrontFaceStencil.ReadMask, + WriteMask = descriptor.FrontFaceStencil.WriteMask + }; + + // Back face + hash.BackFace = new DepthStencilHash.StencilHash { + StencilFailureOperation = descriptor.BackFaceStencil.StencilFailureOperation, + DepthFailureOperation = descriptor.BackFaceStencil.DepthFailureOperation, + DepthStencilPassOperation = descriptor.BackFaceStencil.DepthStencilPassOperation, + StencilCompareFunction = descriptor.BackFaceStencil.StencilCompareFunction, + ReadMask = descriptor.BackFaceStencil.ReadMask, + WriteMask = descriptor.BackFaceStencil.WriteMask + }; + + // Depth + hash.DepthCompareFunction = descriptor.DepthCompareFunction; + hash.DepthWriteEnabled = descriptor.DepthWriteEnabled; + + return hash; + } + + protected override MTLDepthStencilState CreateValue(MTLDepthStencilDescriptor descriptor) + { + return _device.NewDepthStencilState(descriptor); + } + } +} diff --git a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs index 2c6893c92..fc8be20c1 100644 --- a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs +++ b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs @@ -16,6 +16,7 @@ namespace Ryujinx.Graphics.Metal private readonly Pipeline _pipeline; private readonly RenderPipelineCache RenderPipelineCache; + private readonly DepthStencilCache DepthStencilCache; private EncoderState _currentState = new(); private EncoderState _backState = new(); @@ -32,6 +33,7 @@ namespace Ryujinx.Graphics.Metal _device = device; _pipeline = pipeline; RenderPipelineCache = new(device); + DepthStencilCache = new(device); } public void SwapStates() @@ -328,7 +330,7 @@ namespace Ryujinx.Graphics.Metal descriptor.FrontFaceStencil = _currentState.FrontFaceStencil; } - _currentState.DepthStencilState = _device.NewDepthStencilState(descriptor); + _currentState.DepthStencilState = DepthStencilCache.GetOrCreate(descriptor); // Mark dirty _currentState.Dirty.DepthStencil = true; @@ -352,7 +354,7 @@ namespace Ryujinx.Graphics.Metal descriptor.FrontFaceStencil = _currentState.FrontFaceStencil; } - _currentState.DepthStencilState = _device.NewDepthStencilState(descriptor); + _currentState.DepthStencilState = DepthStencilCache.GetOrCreate(descriptor); // Mark dirty _currentState.Dirty.DepthStencil = true;