From cee712105850ac3385cd0091a923438167433f9f Mon Sep 17 00:00:00 2001
From: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
Date: Sat, 8 Apr 2023 01:22:00 +0200
Subject: Move solution and projects to src
---
src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs | 256 ++++++++++++++++++++++
1 file changed, 256 insertions(+)
create mode 100644 src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs
(limited to 'src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs')
diff --git a/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs b/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs
new file mode 100644
index 00000000..a0b9f57b
--- /dev/null
+++ b/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs
@@ -0,0 +1,256 @@
+using System.Collections;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Gpu.Image
+{
+ ///
+ /// An entry on the short duration texture cache.
+ ///
+ class ShortTextureCacheEntry
+ {
+ public readonly TextureDescriptor Descriptor;
+ public readonly int InvalidatedSequence;
+ public readonly Texture Texture;
+
+ ///
+ /// Create a new entry on the short duration texture cache.
+ ///
+ /// Last descriptor that referenced the texture
+ /// The texture
+ public ShortTextureCacheEntry(TextureDescriptor descriptor, Texture texture)
+ {
+ Descriptor = descriptor;
+ InvalidatedSequence = texture.InvalidatedSequence;
+ Texture = texture;
+ }
+ }
+
+ ///
+ /// A texture cache that automatically removes older textures that are not used for some time.
+ /// The cache works with a rotated list with a fixed size. When new textures are added, the
+ /// old ones at the bottom of the list are deleted.
+ ///
+ class AutoDeleteCache : IEnumerable
+ {
+ private const int MinCountForDeletion = 32;
+ private const int MaxCapacity = 2048;
+ private const ulong MaxTextureSizeCapacity = 512 * 1024 * 1024; // MB;
+
+ private readonly LinkedList _textures;
+ private ulong _totalSize;
+
+ private HashSet _shortCacheBuilder;
+ private HashSet _shortCache;
+
+ private Dictionary _shortCacheLookup;
+
+ ///
+ /// Creates a new instance of the automatic deletion cache.
+ ///
+ public AutoDeleteCache()
+ {
+ _textures = new LinkedList();
+
+ _shortCacheBuilder = new HashSet();
+ _shortCache = new HashSet();
+
+ _shortCacheLookup = new Dictionary();
+ }
+
+ ///
+ /// Adds a new texture to the cache, even if the texture added is already on the cache.
+ ///
+ ///
+ /// Using this method is only recommended if you know that the texture is not yet on the cache,
+ /// otherwise it would store the same texture more than once.
+ ///
+ /// The texture to be added to the cache
+ public void Add(Texture texture)
+ {
+ _totalSize += texture.Size;
+
+ texture.IncrementReferenceCount();
+ texture.CacheNode = _textures.AddLast(texture);
+
+ if (_textures.Count > MaxCapacity ||
+ (_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion))
+ {
+ RemoveLeastUsedTexture();
+ }
+ }
+
+ ///
+ /// Adds a new texture to the cache, or just moves it to the top of the list if the
+ /// texture is already on the cache.
+ ///
+ ///
+ /// Moving the texture to the top of the list prevents it from being deleted,
+ /// as the textures on the bottom of the list are deleted when new ones are added.
+ ///
+ /// The texture to be added, or moved to the top
+ public void Lift(Texture texture)
+ {
+ if (texture.CacheNode != null)
+ {
+ if (texture.CacheNode != _textures.Last)
+ {
+ _textures.Remove(texture.CacheNode);
+
+ texture.CacheNode = _textures.AddLast(texture);
+ }
+
+ if (_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion)
+ {
+ RemoveLeastUsedTexture();
+ }
+ }
+ else
+ {
+ Add(texture);
+ }
+ }
+
+ ///
+ /// Removes the least used texture from the cache.
+ ///
+ private void RemoveLeastUsedTexture()
+ {
+ Texture oldestTexture = _textures.First.Value;
+
+ _totalSize -= oldestTexture.Size;
+
+ if (!oldestTexture.CheckModified(false))
+ {
+ // The texture must be flushed if it falls out of the auto delete cache.
+ // Flushes out of the auto delete cache do not trigger write tracking,
+ // as it is expected that other overlapping textures exist that have more up-to-date contents.
+
+ oldestTexture.Group.SynchronizeDependents(oldestTexture);
+ oldestTexture.FlushModified(false);
+ }
+
+ _textures.RemoveFirst();
+
+ oldestTexture.DecrementReferenceCount();
+ oldestTexture.CacheNode = null;
+ }
+
+ ///
+ /// Removes a texture from the cache.
+ ///
+ /// The texture to be removed from the cache
+ /// True to remove the texture if it was on the cache
+ /// True if the texture was found and removed, false otherwise
+ public bool Remove(Texture texture, bool flush)
+ {
+ if (texture.CacheNode == null)
+ {
+ return false;
+ }
+
+ // Remove our reference to this texture.
+ if (flush)
+ {
+ texture.FlushModified(false);
+ }
+
+ _textures.Remove(texture.CacheNode);
+
+ _totalSize -= texture.Size;
+
+ texture.CacheNode = null;
+
+ return texture.DecrementReferenceCount();
+ }
+
+ ///
+ /// Attempt to find a texture on the short duration cache.
+ ///
+ /// The texture descriptor
+ /// The texture if found, null otherwise
+ public Texture FindShortCache(in TextureDescriptor descriptor)
+ {
+ if (_shortCacheLookup.Count > 0 && _shortCacheLookup.TryGetValue(descriptor, out var entry))
+ {
+ if (entry.InvalidatedSequence == entry.Texture.InvalidatedSequence)
+ {
+ return entry.Texture;
+ }
+ else
+ {
+ _shortCacheLookup.Remove(descriptor);
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Removes a texture from the short duration cache.
+ ///
+ /// Texture to remove from the short cache
+ public void RemoveShortCache(Texture texture)
+ {
+ bool removed = _shortCache.Remove(texture.ShortCacheEntry);
+ removed |= _shortCacheBuilder.Remove(texture.ShortCacheEntry);
+
+ if (removed)
+ {
+ texture.DecrementReferenceCount();
+
+ _shortCacheLookup.Remove(texture.ShortCacheEntry.Descriptor);
+ texture.ShortCacheEntry = null;
+ }
+ }
+
+ ///
+ /// Adds a texture to the short duration cache.
+ /// It starts in the builder set, and it is moved into the deletion set on next process.
+ ///
+ /// Texture to add to the short cache
+ /// Last used texture descriptor
+ public void AddShortCache(Texture texture, ref TextureDescriptor descriptor)
+ {
+ var entry = new ShortTextureCacheEntry(descriptor, texture);
+
+ _shortCacheBuilder.Add(entry);
+ _shortCacheLookup.Add(entry.Descriptor, entry);
+
+ texture.ShortCacheEntry = entry;
+
+ texture.IncrementReferenceCount();
+ }
+
+ ///
+ /// Delete textures from the short duration cache.
+ /// Moves the builder set to be deleted on next process.
+ ///
+ public void ProcessShortCache()
+ {
+ HashSet toRemove = _shortCache;
+
+ foreach (var entry in toRemove)
+ {
+ entry.Texture.DecrementReferenceCount();
+
+ _shortCacheLookup.Remove(entry.Descriptor);
+ entry.Texture.ShortCacheEntry = null;
+ }
+
+ toRemove.Clear();
+ _shortCache = _shortCacheBuilder;
+ _shortCacheBuilder = toRemove;
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return _textures.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return _textures.GetEnumerator();
+ }
+ }
+}
\ No newline at end of file
--
cgit v1.2.3