diff --git a/Ryujinx.Graphics.Gpu/Image/Pool.cs b/Ryujinx.Graphics.Gpu/Image/Pool.cs index c2c1a9a19..c5aef77f6 100644 --- a/Ryujinx.Graphics.Gpu/Image/Pool.cs +++ b/Ryujinx.Graphics.Gpu/Image/Pool.cs @@ -8,14 +8,16 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Represents a pool of GPU resources, such as samplers or textures. /// - /// Type of the GPU resource - abstract class Pool : IDisposable + /// Type of the GPU resource + /// Type of the descriptor + abstract class Pool : IDisposable where T2 : unmanaged { protected const int DescriptorSize = 0x20; protected GpuContext Context; - protected T[] Items; + protected T1[] Items; + protected T2[] DescriptorCache; /// /// The maximum ID value of resources on the pool (inclusive). @@ -47,7 +49,8 @@ namespace Ryujinx.Graphics.Gpu.Image ulong size = (ulong)(uint)count * DescriptorSize; - Items = new T[count]; + Items = new T1[count]; + DescriptorCache = new T2[count]; Address = address; Size = size; @@ -56,12 +59,23 @@ namespace Ryujinx.Graphics.Gpu.Image _modifiedDelegate = RegionModified; } + + /// + /// Gets the descriptor for a given ID. + /// + /// ID of the descriptor. This is effectively a zero-based index + /// The descriptor + public T2 GetDescriptor(int id) + { + return Context.PhysicalMemory.Read(Address + (ulong)id * DescriptorSize); + } + /// /// Gets the GPU resource with the given ID. /// /// ID of the resource. This is effectively a zero-based index /// The GPU resource with the given ID - public abstract T Get(int id); + public abstract T1 Get(int id); /// /// Synchronizes host memory with guest memory. @@ -97,7 +111,7 @@ namespace Ryujinx.Graphics.Gpu.Image protected abstract void InvalidateRangeImpl(ulong address, ulong size); - protected abstract void Delete(T item); + protected abstract void Delete(T1 item); /// /// Performs the disposal of all resources stored on the pool. diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs b/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs index 2c28b743f..64a146fb3 100644 --- a/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs +++ b/Ryujinx.Graphics.Gpu/Image/SamplerDescriptor.cs @@ -1,4 +1,6 @@ using Ryujinx.Graphics.GAL; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; namespace Ryujinx.Graphics.Gpu.Image { @@ -244,5 +246,15 @@ namespace Ryujinx.Graphics.Gpu.Image { return ((Word2 >> 12) & 0xfff) * Frac8ToF32; } + + /// + /// Check if two descriptors are equal. + /// + /// The descriptor to compare against + /// True if they are equal, false otherwise + public bool Equals(ref SamplerDescriptor other) + { + return Unsafe.As>(ref this).Equals(Unsafe.As>(ref other)); + } } } diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs index ca13a7d6f..1395aea22 100644 --- a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs +++ b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs @@ -3,7 +3,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Sampler pool. /// - class SamplerPool : Pool + class SamplerPool : Pool { private int _sequenceNumber; @@ -38,11 +38,13 @@ namespace Ryujinx.Graphics.Gpu.Image if (sampler == null) { - SamplerDescriptor descriptor = Context.PhysicalMemory.Read(Address + (ulong)id * DescriptorSize); + SamplerDescriptor descriptor = GetDescriptor(id); sampler = new Sampler(Context, descriptor); Items[id] = sampler; + + DescriptorCache[id] = descriptor; } return sampler; @@ -65,6 +67,14 @@ namespace Ryujinx.Graphics.Gpu.Image if (sampler != null) { + SamplerDescriptor descriptor = GetDescriptor(id); + + // If the descriptors are the same, the sampler is still valid. + if (descriptor.Equals(ref DescriptorCache[id])) + { + continue; + } + sampler.Dispose(); Items[id] = null; diff --git a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs index 76d97bf8c..e85df136b 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs @@ -1,4 +1,6 @@ using Ryujinx.Graphics.Gpu.Shader.Cache.Definition; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; namespace Ryujinx.Graphics.Gpu.Image { @@ -248,5 +250,15 @@ namespace Ryujinx.Graphics.Gpu.Image return result; } + + /// + /// Check if two descriptors are equal. + /// + /// The descriptor to compare against + /// True if they are equal, false otherwise + public bool Equals(ref TextureDescriptor other) + { + return Unsafe.As>(ref this).Equals(Unsafe.As>(ref other)); + } } } diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs index dfcd8a528..58e881ca7 100644 --- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs +++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs @@ -1,6 +1,5 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; -using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Texture; using System; using System.Collections.Generic; @@ -10,7 +9,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Texture pool. /// - class TexturePool : Pool + class TexturePool : Pool { private int _sequenceNumber; @@ -65,6 +64,8 @@ namespace Ryujinx.Graphics.Gpu.Image texture.IncrementReferenceCount(); Items[id] = texture; + + DescriptorCache[id] = descriptor; } else { @@ -91,16 +92,6 @@ namespace Ryujinx.Graphics.Gpu.Image return texture; } - /// - /// Gets the texture descriptor from a given texture ID. - /// - /// ID of the texture. This is effectively a zero-based index - /// The texture descriptor - public TextureDescriptor GetDescriptor(int id) - { - return Context.PhysicalMemory.Read(Address + (ulong)id * DescriptorSize); - } - /// /// Implementation of the texture pool range invalidation. /// @@ -122,8 +113,7 @@ namespace Ryujinx.Graphics.Gpu.Image // If the descriptors are the same, the texture is the same, // we don't need to remove as it was not modified. Just continue. - if (texture.Info.GpuAddress == descriptor.UnpackAddress() && - texture.IsExactMatch(GetInfo(descriptor, out _), TextureSearchFlags.Strict) != TextureMatchQuality.NoMatch) + if (descriptor.Equals(ref DescriptorCache[id])) { continue; }