From f665e1b40969d1673c7a12c44235aefb2a2ea627 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Fri, 2 Apr 2021 11:33:39 -0300
Subject: [PATCH] Hold reference for render targets in use (#2156)

---
 Ryujinx.Graphics.Gpu/Image/Texture.cs        | 15 ++++--
 Ryujinx.Graphics.Gpu/Image/TextureManager.cs | 52 ++++++++++----------
 2 files changed, 38 insertions(+), 29 deletions(-)

diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs
index 26e102a935..6d2510f14b 100644
--- a/Ryujinx.Graphics.Gpu/Image/Texture.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs
@@ -73,7 +73,7 @@ namespace Ryujinx.Graphics.Gpu.Image
         public bool ChangedSize { get; private set; }
 
         /// <summary>
-        /// Set when a texture's GPU VA has ever been partially or fully unmapped. 
+        /// Set when a texture's GPU VA has ever been partially or fully unmapped.
         /// This indicates that the range must be fully checked when matching the texture.
         /// </summary>
         public bool ChangedMapping { get; private set; }
@@ -628,7 +628,7 @@ namespace Ryujinx.Graphics.Gpu.Image
         }
 
         /// <summary>
-        /// Fully synchronizes guest and host memory. 
+        /// Fully synchronizes guest and host memory.
         /// This will replace the entire texture with the data present in guest memory.
         /// </summary>
         public void SynchronizeFull()
@@ -1127,7 +1127,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                 {
                     TextureCreateInfo createInfo = TextureManager.GetCreateInfo(view.Info, _context.Capabilities, ScaleFactor);
 
-                    ITexture newView = parent.HostTexture.CreateView(createInfo, view.FirstLayer + firstLayer, view.FirstLevel + firstLevel); 
+                    ITexture newView = parent.HostTexture.CreateView(createInfo, view.FirstLayer + firstLayer, view.FirstLevel + firstLevel);
 
                     view.ReplaceView(parent, view.Info, newView, view.FirstLayer + firstLayer, view.FirstLevel + firstLevel);
                 }
@@ -1188,6 +1188,15 @@ namespace Ryujinx.Graphics.Gpu.Image
                 IsModified = true;
                 Group.SignalModifying(this, bound, !wasModified);
             }
+
+            if (bound)
+            {
+                IncrementReferenceCount();
+            }
+            else
+            {
+                DecrementReferenceCount();
+            }
         }
 
         /// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
index 2b756e4c2c..17bb553f3e 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
@@ -197,6 +197,27 @@ namespace Ryujinx.Graphics.Gpu.Image
             return changesScale || (hasValue && color.ScaleMode != TextureScaleMode.Blacklisted && color.ScaleFactor != GraphicsConfig.ResScale);
         }
 
+        /// <summary>
+        /// Sets the render target depth-stencil buffer.
+        /// </summary>
+        /// <param name="depthStencil">The depth-stencil buffer texture</param>
+        /// <returns>True if render target scale must be updated.</returns>
+        public bool SetRenderTargetDepthStencil(Texture depthStencil)
+        {
+            bool hasValue = depthStencil != null;
+            bool changesScale = (hasValue != (_rtDepthStencil != null)) || (hasValue && RenderTargetScale != depthStencil.ScaleFactor);
+
+            if (_rtDepthStencil != depthStencil)
+            {
+                _rtDepthStencil?.SignalModifying(false);
+                depthStencil?.SignalModifying(true);
+
+                _rtDepthStencil = depthStencil;
+            }
+
+            return changesScale || (hasValue && depthStencil.ScaleMode != TextureScaleMode.Blacklisted && depthStencil.ScaleFactor != GraphicsConfig.ResScale);
+        }
+
         /// <summary>
         /// Gets the first available bound colour target, or the depth stencil target if not present.
         /// </summary>
@@ -290,27 +311,6 @@ namespace Ryujinx.Graphics.Gpu.Image
             RenderTargetScale = targetScale;
         }
 
-        /// <summary>
-        /// Sets the render target depth-stencil buffer.
-        /// </summary>
-        /// <param name="depthStencil">The depth-stencil buffer texture</param>
-        /// <returns>True if render target scale must be updated.</returns>
-        public bool SetRenderTargetDepthStencil(Texture depthStencil)
-        {
-            bool hasValue = depthStencil != null;
-            bool changesScale = (hasValue != (_rtDepthStencil != null)) || (hasValue && RenderTargetScale != depthStencil.ScaleFactor);
-
-            if (_rtDepthStencil != depthStencil)
-            {
-                _rtDepthStencil?.SignalModifying(false);
-                depthStencil?.SignalModifying(true);
-
-                _rtDepthStencil = depthStencil;
-            }
-
-            return changesScale || (hasValue && depthStencil.ScaleMode != TextureScaleMode.Blacklisted && depthStencil.ScaleFactor != GraphicsConfig.ResScale);
-        }
-
         /// <summary>
         /// Commits bindings on the compute pipeline.
         /// </summary>
@@ -716,7 +716,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                     // If they don't, it may still be mapped to the same physical region, so we
                     // do a more expensive check to tell if they are mapped into the same physical regions.
                     // If the GPU VA for the texture has ever been unmapped, then the range must be checked regardless.
-                    if ((overlap.Info.GpuAddress != info.GpuAddress || overlap.ChangedMapping) && 
+                    if ((overlap.Info.GpuAddress != info.GpuAddress || overlap.ChangedMapping) &&
                         !_context.MemoryManager.CompareRange(overlap.Range, info.GpuAddress))
                     {
                         continue;
@@ -775,7 +775,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                 Array.Resize(ref _overlapInfo, _textureOverlaps.Length);
             }
 
-            // =============== Find Texture View of Existing Texture =============== 
+            // =============== Find Texture View of Existing Texture ===============
 
             int fullyCompatible = 0;
 
@@ -841,7 +841,7 @@ namespace Ryujinx.Graphics.Gpu.Image
             if (texture != null)
             {
                 // This texture could be a view of multiple parent textures with different storages, even if it is a view.
-                // When a texture is created, make sure all possible dependencies to other textures are created as copies. 
+                // When a texture is created, make sure all possible dependencies to other textures are created as copies.
                 // (even if it could be fulfilled without a copy)
 
                 for (int index = 0; index < overlapsCount; index++)
@@ -859,7 +859,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                 texture.SynchronizeMemory();
             }
 
-            // =============== Create a New Texture =============== 
+            // =============== Create a New Texture ===============
 
             // No match, create a new texture.
             if (texture == null)
@@ -993,7 +993,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                         overlap.ReplaceView(texture, overlapInfo, newView, oInfo.FirstLayer, oInfo.FirstLevel);
                     }
                 }
-                
+
                 texture.SynchronizeMemory();
             }