From b0e410a828fd37bf0d9021fc2f6b630e3944a861 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Sat, 11 Sep 2021 20:52:54 +0100 Subject: [PATCH] Lift textures in the AutoDeleteCache for all modifications. (#2615) * Lift textures in the AutoDeleteCache for all modifications. Before, this would only apply to render targets and texture blit. Now it applies to image stores, the fast dma copy path and any other type of modification. Image store always at least has one reference in the texture pool, so the function of the AutoDeleteCache keeping textures _alive_ is not useful, but a very important function for a while has been its use to flush textures in order of modification when they are dereferenced, so that their data is not lost. Before, textures populated using image stores were being dereferenced and reloaded as garbage. Now, when these textures are dereferenced, their data will be put back into memory, and everything stays intact. Fixes lighting breaking when switching levels in THPS1+2, and potentially some more UE4 games. I've tested a bunch more games for regressions and performance impact, but they all seem fine. * Lift copy srcTexture so that it doesn't remain referenceless * Perform lift before reference count change on unbind. It's important to lift on unbind as that is the moment the texture was truly last modified, but definitely not after releasing every single reference. --- Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs | 2 ++ Ryujinx.Graphics.Gpu/Image/Texture.cs | 4 ++++ Ryujinx.Graphics.Gpu/Image/TextureCache.cs | 20 ++++++++++--------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs b/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs index 3c74c1647a..5077cb6a71 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs @@ -127,6 +127,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod return; } + memoryManager.Physical.TextureCache.Lift(srcTexture); + // When the source texture that was found has a depth format, // we must enforce the target texture also has a depth format, // as copies between depth and color formats are not allowed. diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index c9c3c59aca..3a66960d48 100644 --- a/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -1235,6 +1235,8 @@ namespace Ryujinx.Graphics.Gpu.Image IsModified = true; Group.SignalModified(this, !wasModified); } + + _physicalMemory.TextureCache.Lift(this); } /// @@ -1252,6 +1254,8 @@ namespace Ryujinx.Graphics.Gpu.Image Group.SignalModifying(this, bound, !wasModified); } + _physicalMemory.TextureCache.Lift(this); + if (bound) { IncrementReferenceCount(); diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs index 44c974e8f6..ea64f46c14 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs @@ -154,6 +154,17 @@ namespace Ryujinx.Graphics.Gpu.Image return true; } + /// + /// Lifts the texture to the top of the AutoDeleteCache. This is primarily used to enforce that + /// data written to a target will be flushed to memory should the texture be deleted, but also + /// keeps rendered textures alive without a pool reference. + /// + /// Texture to lift + public void Lift(Texture texture) + { + _cache.Lift(texture); + } + /// /// Tries to find an existing texture, or create a new one if not found. /// @@ -442,14 +453,6 @@ namespace Ryujinx.Graphics.Gpu.Image if (texture != null) { - if (!isSamplerTexture) - { - // If not a sampler texture, it is managed by the auto delete - // cache, ensure that it is on the "top" of the list to avoid - // deletion. - _cache.Lift(texture); - } - ChangeSizeIfNeeded(info, texture, isSamplerTexture, sizeHint); texture.SynchronizeMemory(); @@ -849,7 +852,6 @@ namespace Ryujinx.Graphics.Gpu.Image if (match) { - _cache.Lift(texture); return texture; } }