aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs78
-rw-r--r--Ryujinx.Graphics.Gpu/Image/Texture.cs7
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureCache.cs13
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureGroup.cs26
4 files changed, 40 insertions, 84 deletions
diff --git a/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs b/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs
index 379eb715..a0b9f57b 100644
--- a/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs
@@ -33,10 +33,12 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
class AutoDeleteCache : IEnumerable<Texture>
{
+ private const int MinCountForDeletion = 32;
private const int MaxCapacity = 2048;
+ private const ulong MaxTextureSizeCapacity = 512 * 1024 * 1024; // MB;
private readonly LinkedList<Texture> _textures;
- private readonly ConcurrentQueue<Texture> _deferredRemovals;
+ private ulong _totalSize;
private HashSet<ShortTextureCacheEntry> _shortCacheBuilder;
private HashSet<ShortTextureCacheEntry> _shortCache;
@@ -49,7 +51,6 @@ namespace Ryujinx.Graphics.Gpu.Image
public AutoDeleteCache()
{
_textures = new LinkedList<Texture>();
- _deferredRemovals = new ConcurrentQueue<Texture>();
_shortCacheBuilder = new HashSet<ShortTextureCacheEntry>();
_shortCache = new HashSet<ShortTextureCacheEntry>();
@@ -67,37 +68,15 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="texture">The texture to be added to the cache</param>
public void Add(Texture texture)
{
- texture.IncrementReferenceCount();
+ _totalSize += texture.Size;
+ texture.IncrementReferenceCount();
texture.CacheNode = _textures.AddLast(texture);
- if (_textures.Count > MaxCapacity)
- {
- Texture oldestTexture = _textures.First.Value;
-
- 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;
- }
-
- if (_deferredRemovals.Count > 0)
+ if (_textures.Count > MaxCapacity ||
+ (_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion))
{
- while (_deferredRemovals.TryDequeue(out Texture textureToRemove))
- {
- Remove(textureToRemove, false);
- }
+ RemoveLeastUsedTexture();
}
}
@@ -120,6 +99,11 @@ namespace Ryujinx.Graphics.Gpu.Image
texture.CacheNode = _textures.AddLast(texture);
}
+
+ if (_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion)
+ {
+ RemoveLeastUsedTexture();
+ }
}
else
{
@@ -128,6 +112,31 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
+ /// Removes the least used texture from the cache.
+ /// </summary>
+ 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;
+ }
+
+ /// <summary>
/// Removes a texture from the cache.
/// </summary>
/// <param name="texture">The texture to be removed from the cache</param>
@@ -148,21 +157,14 @@ namespace Ryujinx.Graphics.Gpu.Image
_textures.Remove(texture.CacheNode);
+ _totalSize -= texture.Size;
+
texture.CacheNode = null;
return texture.DecrementReferenceCount();
}
/// <summary>
- /// Queues removal of a texture from the cache in a thread safe way.
- /// </summary>
- /// <param name="texture">The texture to be removed from the cache</param>
- public void RemoveDeferred(Texture texture)
- {
- _deferredRemovals.Enqueue(texture);
- }
-
- /// <summary>
/// Attempt to find a texture on the short duration cache.
/// </summary>
/// <param name="descriptor">The texture descriptor</param>
diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs
index 352a828d..6c0de536 100644
--- a/Ryujinx.Graphics.Gpu/Image/Texture.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs
@@ -1637,13 +1637,6 @@ namespace Ryujinx.Graphics.Gpu.Image
}
RemoveFromPools(true);
-
- // We only want to remove if there's no mapped region of the texture that was modified by the GPU,
- // otherwise we could lose data.
- if (!Group.AnyModified(this))
- {
- _physicalMemory.TextureCache.QueueAutoDeleteCacheRemoval(this);
- }
}
/// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index 1d5b1851..27bec786 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -1080,19 +1080,6 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
- /// Queues the removal of a texture from the auto delete cache.
- /// </summary>
- /// <remarks>
- /// This function is thread safe and can be called from any thread.
- /// The texture will be deleted on the next time the cache is used.
- /// </remarks>
- /// <param name="texture">The texture to be removed</param>
- public void QueueAutoDeleteCacheRemoval(Texture texture)
- {
- _cache.RemoveDeferred(texture);
- }
-
- /// <summary>
/// Adds a texture to the short duration cache. This typically keeps it alive for two ticks.
/// </summary>
/// <param name="texture">Texture to add to the short cache</param>
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
index 896e11a5..942fa2f8 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
@@ -435,32 +435,6 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
- /// Checks if a texture was modified by the GPU.
- /// </summary>
- /// <param name="texture">The texture to be checked</param>
- /// <returns>True if any region of the texture was modified by the GPU, false otherwise</returns>
- public bool AnyModified(Texture texture)
- {
- bool anyModified = false;
-
- EvaluateRelevantHandles(texture, (baseHandle, regionCount, split) =>
- {
- for (int i = 0; i < regionCount; i++)
- {
- TextureGroupHandle group = _handles[baseHandle + i];
-
- if (group.Modified)
- {
- anyModified = true;
- break;
- }
- }
- });
-
- return anyModified;
- }
-
- /// <summary>
/// Flush modified ranges for a given texture.
/// </summary>
/// <param name="texture">The texture being used</param>