diff --git a/src/Ryujinx.Graphics.Metal/DisposableSampler.cs b/src/Ryujinx.Graphics.Metal/DisposableSampler.cs new file mode 100644 index 000000000..ba041be89 --- /dev/null +++ b/src/Ryujinx.Graphics.Metal/DisposableSampler.cs @@ -0,0 +1,22 @@ +using SharpMetal.Metal; +using System; +using System.Runtime.Versioning; + +namespace Ryujinx.Graphics.Metal +{ + [SupportedOSPlatform("macos")] + readonly struct DisposableSampler : IDisposable + { + public MTLSamplerState Value { get; } + + public DisposableSampler(MTLSamplerState sampler) + { + Value = sampler; + } + + public void Dispose() + { + Value.Dispose(); + } + } +} diff --git a/src/Ryujinx.Graphics.Metal/EncoderState.cs b/src/Ryujinx.Graphics.Metal/EncoderState.cs index d5dd5123b..8aa816efb 100644 --- a/src/Ryujinx.Graphics.Metal/EncoderState.cs +++ b/src/Ryujinx.Graphics.Metal/EncoderState.cs @@ -55,10 +55,10 @@ namespace Ryujinx.Graphics.Metal { public ShaderStage Stage; public TextureBase Storage; - public Sampler Sampler; + public Auto Sampler; public Format ImageFormat; - public TextureRef(ShaderStage stage, TextureBase storage, Sampler sampler) + public TextureRef(ShaderStage stage, TextureBase storage, Auto sampler) { Stage = stage; Storage = storage; diff --git a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs index 50d9c9789..ae3f3abbf 100644 --- a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs +++ b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs @@ -865,11 +865,11 @@ namespace Ryujinx.Graphics.Metal SignalDirty(DirtyFlags.StencilRef); } - public readonly void UpdateTextureAndSampler(ShaderStage stage, int binding, TextureBase texture, Sampler sampler) + public readonly void UpdateTextureAndSampler(ShaderStage stage, int binding, TextureBase texture, SamplerHolder samplerHolder) { if (texture != null) { - _currentState.TextureRefs[binding] = new(stage, texture, sampler); + _currentState.TextureRefs[binding] = new(stage, texture, samplerHolder.GetSampler()); } else { @@ -1312,7 +1312,7 @@ namespace Ryujinx.Graphics.Metal if (texture.Sampler != null) { - vertResourceIds[vertResourceIdIndex] = texture.Sampler.GetSampler().GpuResourceID._impl; + vertResourceIds[vertResourceIdIndex] = texture.Sampler.Get(_pipeline.Cbs).Value.GpuResourceID._impl; vertResourceIdIndex++; } @@ -1326,7 +1326,7 @@ namespace Ryujinx.Graphics.Metal if (texture.Sampler != null) { - fragResourceIds[fragResourceIdIndex] = texture.Sampler.GetSampler().GpuResourceID._impl; + fragResourceIds[fragResourceIdIndex] = texture.Sampler.Get(_pipeline.Cbs).Value.GpuResourceID._impl; fragResourceIdIndex++; } @@ -1343,7 +1343,7 @@ namespace Ryujinx.Graphics.Metal if (segment.Type != ResourceType.BufferTexture) { var textures = textureArray.GetTextureRefs(); - var samplers = new Sampler[textures.Length]; + var samplers = new Auto[textures.Length]; for (int i = 0; i < textures.Length; i++) { @@ -1379,7 +1379,7 @@ namespace Ryujinx.Graphics.Metal if (sampler != null) { - gpuAddress = sampler.GetSampler().GpuResourceID._impl; + gpuAddress = sampler.Get(_pipeline.Cbs).Value.GpuResourceID._impl; } if ((segment.Stages & ResourceStages.Vertex) != 0) @@ -1612,7 +1612,7 @@ namespace Ryujinx.Graphics.Metal if (texture.Sampler != null) { - resourceIds[resourceIdIndex] = texture.Sampler.GetSampler().GpuResourceID._impl; + resourceIds[resourceIdIndex] = texture.Sampler.Get(_pipeline.Cbs).Value.GpuResourceID._impl; resourceIdIndex++; } } @@ -1625,7 +1625,7 @@ namespace Ryujinx.Graphics.Metal if (segment.Type != ResourceType.BufferTexture) { var textures = textureArray.GetTextureRefs(); - var samplers = new Sampler[textures.Length]; + var samplers = new Auto[textures.Length]; for (int i = 0; i < textures.Length; i++) { @@ -1646,7 +1646,7 @@ namespace Ryujinx.Graphics.Metal { if (sampler != null) { - resourceIds[resourceIdIndex] = sampler.GetSampler().GpuResourceID._impl; + resourceIds[resourceIdIndex] = sampler.Get(_pipeline.Cbs).Value.GpuResourceID._impl; resourceIdIndex++; } } diff --git a/src/Ryujinx.Graphics.Metal/HelperShader.cs b/src/Ryujinx.Graphics.Metal/HelperShader.cs index c86974e47..039e3c595 100644 --- a/src/Ryujinx.Graphics.Metal/HelperShader.cs +++ b/src/Ryujinx.Graphics.Metal/HelperShader.cs @@ -47,8 +47,8 @@ namespace Ryujinx.Graphics.Metal _renderer = renderer; _pipeline = pipeline; - _samplerNearest = new Sampler(_device, SamplerCreateInfo.Create(MinFilter.Nearest, MagFilter.Nearest)); - _samplerLinear = new Sampler(_device, SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear)); + _samplerNearest = new SamplerHolder(renderer, _device, SamplerCreateInfo.Create(MinFilter.Nearest, MagFilter.Nearest)); + _samplerLinear = new SamplerHolder(renderer, _device, SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear)); var blitResourceLayout = new ResourceLayoutBuilder() .Add(ResourceStages.Vertex, ResourceType.UniformBuffer, 0) diff --git a/src/Ryujinx.Graphics.Metal/MetalRenderer.cs b/src/Ryujinx.Graphics.Metal/MetalRenderer.cs index 6bdc043bf..6a55e3e20 100644 --- a/src/Ryujinx.Graphics.Metal/MetalRenderer.cs +++ b/src/Ryujinx.Graphics.Metal/MetalRenderer.cs @@ -4,6 +4,7 @@ using Ryujinx.Graphics.Shader.Translation; using SharpMetal.Metal; using SharpMetal.QuartzCore; using System; +using System.Collections.Generic; using System.Runtime.Versioning; namespace Ryujinx.Graphics.Metal @@ -33,9 +34,12 @@ namespace Ryujinx.Graphics.Metal internal Action InterruptAction { get; private set; } internal SyncManager SyncManager { get; private set; } + internal HashSet Samplers { get; } + public MetalRenderer(Func metalLayer) { _device = MTLDevice.CreateSystemDefaultDevice(); + Samplers = new HashSet(); if (_device.ArgumentBuffersSupport != MTLArgumentBuffersTier.Tier2) { @@ -101,7 +105,7 @@ namespace Ryujinx.Graphics.Metal public ISampler CreateSampler(SamplerCreateInfo info) { - return new Sampler(_device, info); + return new SamplerHolder(this, _device, info); } public ITexture CreateTexture(TextureCreateInfo info) @@ -281,6 +285,12 @@ namespace Ryujinx.Graphics.Metal public void Dispose() { BackgroundResources.Dispose(); + + foreach (var sampler in Samplers) + { + sampler.Dispose(); + } + _pipeline.Dispose(); _window.Dispose(); } diff --git a/src/Ryujinx.Graphics.Metal/Pipeline.cs b/src/Ryujinx.Graphics.Metal/Pipeline.cs index f6a5e0908..00da26419 100644 --- a/src/Ryujinx.Graphics.Metal/Pipeline.cs +++ b/src/Ryujinx.Graphics.Metal/Pipeline.cs @@ -768,9 +768,9 @@ namespace Ryujinx.Graphics.Metal { if (texture is TextureBase tex) { - if (sampler == null || sampler is Sampler) + if (sampler == null || sampler is SamplerHolder) { - _encoderStateManager.UpdateTextureAndSampler(stage, binding, tex, (Sampler)sampler); + _encoderStateManager.UpdateTextureAndSampler(stage, binding, tex, (SamplerHolder)sampler); } } } diff --git a/src/Ryujinx.Graphics.Metal/Sampler.cs b/src/Ryujinx.Graphics.Metal/SamplerHolder.cs similarity index 77% rename from src/Ryujinx.Graphics.Metal/Sampler.cs rename to src/Ryujinx.Graphics.Metal/SamplerHolder.cs index 1189288f6..3241efa6d 100644 --- a/src/Ryujinx.Graphics.Metal/Sampler.cs +++ b/src/Ryujinx.Graphics.Metal/SamplerHolder.cs @@ -6,12 +6,17 @@ using System.Runtime.Versioning; namespace Ryujinx.Graphics.Metal { [SupportedOSPlatform("macos")] - class Sampler : ISampler + class SamplerHolder : ISampler { - private readonly MTLSamplerState _mtlSamplerState; + private readonly MetalRenderer _renderer; + private readonly Auto _sampler; - public Sampler(MTLDevice device, SamplerCreateInfo info) + public SamplerHolder(MetalRenderer renderer, MTLDevice device, SamplerCreateInfo info) { + _renderer = renderer; + + renderer.Samplers.Add(this); + (MTLSamplerMinMagFilter minFilter, MTLSamplerMipFilter mipFilter) = info.MinFilter.Convert(); MTLSamplerBorderColor borderColor = GetConstrainedBorderColor(info.BorderColor, out _); @@ -33,14 +38,9 @@ namespace Ryujinx.Graphics.Metal SupportArgumentBuffers = true }; - var samplerState = device.NewSamplerState(descriptor); + var sampler = device.NewSamplerState(descriptor); - _mtlSamplerState = samplerState; - } - - public Sampler(MTLSamplerState samplerState) - { - _mtlSamplerState = samplerState; + _sampler = new Auto(new DisposableSampler(sampler)); } private static MTLSamplerBorderColor GetConstrainedBorderColor(ColorF arbitraryBorderColor, out bool cantConstrain) @@ -74,14 +74,17 @@ namespace Ryujinx.Graphics.Metal return MTLSamplerBorderColor.OpaqueBlack; } - public MTLSamplerState GetSampler() + public Auto GetSampler() { - return _mtlSamplerState; + return _sampler; } public void Dispose() { - _mtlSamplerState.Dispose(); + if (_renderer.Samplers.Remove(this)) + { + _sampler.Dispose(); + } } } } diff --git a/src/Ryujinx.Graphics.Metal/TextureArray.cs b/src/Ryujinx.Graphics.Metal/TextureArray.cs index cfca843f7..ea2c74420 100644 --- a/src/Ryujinx.Graphics.Metal/TextureArray.cs +++ b/src/Ryujinx.Graphics.Metal/TextureArray.cs @@ -33,9 +33,9 @@ namespace Ryujinx.Graphics.Metal { ISampler sampler = samplers[i]; - if (sampler is Sampler samp) + if (sampler is SamplerHolder samp) { - _textureRefs[index + i].Sampler = samp; + _textureRefs[index + i].Sampler = samp.GetSampler(); } else {