From b6e093b0fce3dc4fe607a84f57e6406b5ab8e387 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Wed, 29 Sep 2021 01:11:05 +0100 Subject: [PATCH] Force copy when auto-deleting a texture with dependencies (#2687) When a texture is deleted by falling to the bottom of the AutoDeleteCache, its data is flushed to preserve any GPU writes that occurred. This ensures that the data appears in any textures recreated in the future, but didn't account for a texture that already existed with a copy dependency. This change forces copy dependencies to complete if a texture falls out from from the AutoDeleteCache. (not removed via overlap, as that would be wasted effort) Fixes broken lighting caused by pausing in SMO's Metro Kingdom. May fix some other issues. --- Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs | 8 ++++---- Ryujinx.Graphics.Gpu/Image/TextureGroup.cs | 17 +++++++++++++++++ .../Image/TextureGroupHandle.cs | 16 ++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs b/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs index 726b97ea17..8bc6d5448c 100644 --- a/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs +++ b/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs @@ -41,14 +41,14 @@ namespace Ryujinx.Graphics.Gpu.Image { Texture oldestTexture = _textures.First.Value; - oldestTexture.SynchronizeMemory(); - - if (oldestTexture.IsModified && !oldestTexture.CheckModified(true)) + if (oldestTexture.IsModified && !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.Flush(false); + + oldestTexture.Group.SynchronizeDependents(oldestTexture); + oldestTexture.Flush(false); } _textures.RemoveFirst(); diff --git a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs index 1fe0bbf7a7..2bd97432c7 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs @@ -234,6 +234,23 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Synchronize dependent textures, if any of them have deferred a copy from the given texture. + /// + /// The texture to synchronize dependents of + public void SynchronizeDependents(Texture texture) + { + EvaluateRelevantHandles(texture, (baseHandle, regionCount, split) => + { + for (int i = 0; i < regionCount; i++) + { + TextureGroupHandle group = _handles[baseHandle + i]; + + group.SynchronizeDependents(); + } + }); + } + /// /// Signal that a texture in the group has been modified by the GPU. /// diff --git a/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs b/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs index 27ee1e4993..0b69b6c730 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs @@ -140,6 +140,22 @@ namespace Ryujinx.Graphics.Gpu.Image _bindCount = Math.Max(0, _bindCount + (bound ? 1 : -1)); } + /// + /// Synchronize dependent textures, if any of them have deferred a copy from this texture. + /// + public void SynchronizeDependents() + { + foreach (TextureDependency dependency in Dependencies) + { + TextureGroupHandle otherHandle = dependency.Other.Handle; + + if (otherHandle.DeferredCopy == this) + { + otherHandle._group.Storage.SynchronizeMemory(); + } + } + } + /// /// Signal that a copy dependent texture has been modified, and must have its data copied to this one. ///