diff options
-rw-r--r-- | Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs | 26 | ||||
-rw-r--r-- | Ryujinx.Graphics.Gpu/Image/Texture.cs | 7 | ||||
-rw-r--r-- | Ryujinx.Graphics.Gpu/Image/TextureCache.cs | 13 | ||||
-rw-r--r-- | Ryujinx.Graphics.Gpu/Image/TextureGroup.cs | 26 |
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> |