diff --git a/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs b/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs index a0b9f57bd9..2465efb0f9 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs @@ -1,5 +1,4 @@ using System.Collections; -using System.Collections.Concurrent; using System.Collections.Generic; namespace Ryujinx.Graphics.Gpu.Image @@ -9,6 +8,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// class ShortTextureCacheEntry { + public bool IsAutoDelete; public readonly TextureDescriptor Descriptor; public readonly int InvalidatedSequence; public readonly Texture Texture; @@ -24,6 +24,17 @@ namespace Ryujinx.Graphics.Gpu.Image InvalidatedSequence = texture.InvalidatedSequence; Texture = texture; } + + /// + /// Create a new entry on the short duration texture cache from the auto delete cache. + /// + /// The texture + public ShortTextureCacheEntry(Texture texture) + { + IsAutoDelete = true; + InvalidatedSequence = texture.InvalidatedSequence; + Texture = texture; + } } /// @@ -199,7 +210,11 @@ namespace Ryujinx.Graphics.Gpu.Image { texture.DecrementReferenceCount(); - _shortCacheLookup.Remove(texture.ShortCacheEntry.Descriptor); + if (!texture.ShortCacheEntry.IsAutoDelete) + { + _shortCacheLookup.Remove(texture.ShortCacheEntry.Descriptor); + } + texture.ShortCacheEntry = null; } } @@ -222,6 +237,25 @@ namespace Ryujinx.Graphics.Gpu.Image texture.IncrementReferenceCount(); } + /// + /// Adds a texture to the short duration cache without a descriptor. This typically keeps it alive for two ticks. + /// On expiry, it will be removed from the AutoDeleteCache. + /// + /// Texture to add to the short cache + public void AddShortCache(Texture texture) + { + if (texture.ShortCacheEntry != null) + { + var entry = new ShortTextureCacheEntry(texture); + + _shortCacheBuilder.Add(entry); + + texture.ShortCacheEntry = entry; + + texture.IncrementReferenceCount(); + } + } + /// /// Delete textures from the short duration cache. /// Moves the builder set to be deleted on next process. @@ -234,7 +268,15 @@ namespace Ryujinx.Graphics.Gpu.Image { entry.Texture.DecrementReferenceCount(); - _shortCacheLookup.Remove(entry.Descriptor); + if (entry.IsAutoDelete) + { + Remove(entry.Texture, false); + } + else + { + _shortCacheLookup.Remove(entry.Descriptor); + } + entry.Texture.ShortCacheEntry = null; } diff --git a/src/Ryujinx.Graphics.Gpu/Image/Texture.cs b/src/Ryujinx.Graphics.Gpu/Image/Texture.cs index 3b25798894..6c9de8d6a8 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -144,6 +144,11 @@ namespace Ryujinx.Graphics.Gpu.Image /// public ShortTextureCacheEntry ShortCacheEntry { get; set; } + /// + /// Whether this texture has ever been referenced by a pool. + /// + public bool HadPoolOwner { get; private set; } + /// Physical memory ranges where the texture data is located. /// public MultiRange Range { get; private set; } @@ -1506,10 +1511,13 @@ namespace Ryujinx.Graphics.Gpu.Image /// GPU VA of the pool reference public void IncrementReferenceCount(TexturePool pool, int id, ulong gpuVa) { + HadPoolOwner = true; + lock (_poolOwners) { _poolOwners.Add(new TexturePoolOwner { Pool = pool, ID = id, GpuAddress = gpuVa }); } + _referenceCount++; if (ShortCacheEntry != null) @@ -1594,7 +1602,7 @@ namespace Ryujinx.Graphics.Gpu.Image _poolOwners.Clear(); } - if (ShortCacheEntry != null && _context.IsGpuThread()) + if (ShortCacheEntry != null && !ShortCacheEntry.IsAutoDelete && _context.IsGpuThread()) { // If this is called from another thread (unmapped), the short cache will // have to remove this texture on a future tick. diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs index 97d78a3496..fc2c07e559 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs @@ -848,7 +848,17 @@ namespace Ryujinx.Graphics.Gpu.Image if (overlapInCache) { - _cache.Remove(overlap, flush); + if (flush || overlap.HadPoolOwner || overlap.IsView) + { + _cache.Remove(overlap, flush); + } + else + { + // This texture has only ever been referenced in the AutoDeleteCache. + // Keep this texture alive with the short duration cache, as it may be used often but not sampled. + + _cache.AddShortCache(overlap); + } } removeOverlap = modified; @@ -1198,6 +1208,16 @@ namespace Ryujinx.Graphics.Gpu.Image _cache.AddShortCache(texture, ref descriptor); } + /// + /// Adds a texture to the short duration cache without a descriptor. This typically keeps it alive for two ticks. + /// On expiry, it will be removed from the AutoDeleteCache. + /// + /// Texture to add to the short cache + public void AddShortCache(Texture texture) + { + _cache.AddShortCache(texture); + } + /// /// Removes a texture from the short duration cache. ///