aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs26
-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, 72 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs b/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs
index 277f39b9..4a1615f0 100644
--- a/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs
@@ -1,4 +1,5 @@
using System.Collections;
+using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Gpu.Image
@@ -13,6 +14,7 @@ namespace Ryujinx.Graphics.Gpu.Image
private const int MaxCapacity = 2048;
private readonly LinkedList<Texture> _textures;
+ private readonly ConcurrentQueue<Texture> _deferredRemovals;
/// <summary>
/// Creates a new instance of the automatic deletion cache.
@@ -20,6 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Image
public AutoDeleteCache()
{
_textures = new LinkedList<Texture>();
+ _deferredRemovals = new ConcurrentQueue<Texture>();
}
/// <summary>
@@ -56,6 +59,14 @@ namespace Ryujinx.Graphics.Gpu.Image
oldestTexture.CacheNode = null;
}
+
+ if (_deferredRemovals.Count > 0)
+ {
+ while (_deferredRemovals.TryDequeue(out Texture textureToRemove))
+ {
+ Remove(textureToRemove, false);
+ }
+ }
}
/// <summary>
@@ -84,6 +95,12 @@ namespace Ryujinx.Graphics.Gpu.Image
}
}
+ /// <summary>
+ /// Removes a texture from the cache.
+ /// </summary>
+ /// <param name="texture">The texture to be removed from the cache</param>
+ /// <param name="flush">True to remove the texture if it was on the cache</param>
+ /// <returns>True if the texture was found and removed, false otherwise</returns>
public bool Remove(Texture texture, bool flush)
{
if (texture.CacheNode == null)
@@ -104,6 +121,15 @@ namespace Ryujinx.Graphics.Gpu.Image
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);
+ }
+
public IEnumerator<Texture> GetEnumerator()
{
return _textures.GetEnumerator();
diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs
index 0995314d..f0c31be6 100644
--- a/Ryujinx.Graphics.Gpu/Image/Texture.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs
@@ -1676,6 +1676,13 @@ 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 16bfc693..c020f4c8 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -1166,6 +1166,19 @@ 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>
/// Disposes all textures and samplers in the cache.
/// It's an error to use the texture cache after disposal.
/// </summary>
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
index ca54dc2f..cd17564a 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
@@ -435,6 +435,32 @@ 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>