From 8d36681bf1eb732307086203f3bbd2509f55c234 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Sat, 6 Mar 2021 14:43:55 +0000 Subject: Improve handling for unmapped GPU resources (#2083) * Improve handling for unmapped GPU resources - Fixed a memory tracking bug that would set protection on empty PTEs - When a texture's memory is (partially) unmapped, all pool references are forcibly removed and the texture must be rediscovered to draw with it. This will also force the texture discovery to always compare the texture's range for a match. - RegionHandles now know if they are unmapped, and automatically unset their dirty flag when unmapped. - Partial texture sync now loads only the region of texture that has been modified. Unmapped memory tracking handles cause dirty flags for a texture group handle to be ignored. This greatly improves the emulator's stability for newer UE4 games. * Address feedback, fix MultiRange slice Fixed an issue where the size of the multi-range slice would be miscalculated. * Update Ryujinx.Memory/Range/MultiRange.cs (feedback) Co-authored-by: Mary Co-authored-by: Mary --- Ryujinx.Graphics.Gpu/Image/TexturePool.cs | 52 +++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) (limited to 'Ryujinx.Graphics.Gpu/Image/TexturePool.cs') diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs index 58e881ca..eece2a79 100644 --- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs +++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs @@ -2,6 +2,7 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Texture; using System; +using System.Collections.Concurrent; using System.Collections.Generic; namespace Ryujinx.Graphics.Gpu.Image @@ -12,6 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Image class TexturePool : Pool { private int _sequenceNumber; + private readonly ConcurrentQueue _dereferenceQueue = new ConcurrentQueue(); /// /// Intrusive linked list node used on the texture pool cache. @@ -53,6 +55,8 @@ namespace Ryujinx.Graphics.Gpu.Image TextureInfo info = GetInfo(descriptor, out int layerSize); + ProcessDereferenceQueue(); + texture = Context.Methods.TextureManager.FindOrCreateTexture(TextureSearchFlags.ForSampler, info, layerSize); // If this happens, then the texture address is invalid, we can't add it to the cache. @@ -61,7 +65,7 @@ namespace Ryujinx.Graphics.Gpu.Image return null; } - texture.IncrementReferenceCount(); + texture.IncrementReferenceCount(this, id); Items[id] = texture; @@ -92,6 +96,39 @@ namespace Ryujinx.Graphics.Gpu.Image return texture; } + /// + /// Forcibly remove a texture from this pool's items. + /// If deferred, the dereference will be queued to occur on the render thread. + /// + /// The texture being removed + /// The ID of the texture in this pool + /// If true, queue the dereference to happen on the render thread, otherwise dereference immediately + public void ForceRemove(Texture texture, int id, bool deferred) + { + Items[id] = null; + + if (deferred) + { + _dereferenceQueue.Enqueue(texture); + } + else + { + texture.DecrementReferenceCount(); + } + } + + /// + /// Process the dereference queue, decrementing the reference count for each texture in it. + /// This is used to ensure that texture disposal happens on the render thread. + /// + private void ProcessDereferenceQueue() + { + while (_dereferenceQueue.TryDequeue(out Texture toRemove)) + { + toRemove.DecrementReferenceCount(); + } + } + /// /// Implementation of the texture pool range invalidation. /// @@ -99,6 +136,8 @@ namespace Ryujinx.Graphics.Gpu.Image /// Size of the range being invalidated protected override void InvalidateRangeImpl(ulong address, ulong size) { + ProcessDereferenceQueue(); + ulong endAddress = address + size; for (; address < endAddress; address += DescriptorSize) @@ -118,7 +157,7 @@ namespace Ryujinx.Graphics.Gpu.Image continue; } - texture.DecrementReferenceCount(); + texture.DecrementReferenceCount(this, id); Items[id] = null; } @@ -342,7 +381,14 @@ namespace Ryujinx.Graphics.Gpu.Image /// The texture to be deleted protected override void Delete(Texture item) { - item?.DecrementReferenceCount(); + item?.DecrementReferenceCount(this); + } + + public override void Dispose() + { + ProcessDereferenceQueue(); + + base.Dispose(); } } } \ No newline at end of file -- cgit v1.2.3