From ecbf303266d78d7b4287ce4ea97d59107a05fb2f Mon Sep 17 00:00:00 2001
From: riperiperi <rhy3756547@hotmail.com>
Date: Thu, 18 May 2023 07:56:34 +0100
Subject: GPU: Avoid using garbage size for non-cb0 storage buffers (#4999)

* GPU: Avoid using garbage size for non-cb0 storage buffers

In the depths area, Tears of the Kingdom uses a global memory access with address on constant buffer slot 6. This isn't standard and thus doesn't actually have a size 8 bytes after it, so we were reading back a garbage size that ended up very large (at least in version 1.1.0), and would synchronize a lot of data per frame.

This PR makes storage buffers created from addresses outside constant buffer slot 0 get their size as the number of bytes remaining in the GPU mapping starting at the given virtual address. This should bound the buffer to a reasonable size, and ideally stop it crossing into other memory.

* Limit max size

* Add TODO

* Feedback
---
 src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs | 27 ++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

(limited to 'src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs')

diff --git a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
index 0d4a41f0..c7a138c9 100644
--- a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
+++ b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
@@ -637,6 +637,33 @@ namespace Ryujinx.Graphics.Gpu.Memory
             return UnpackPaFromPte(pte) + (va & PageMask);
         }
 
+        /// <summary>
+        /// Translates a GPU virtual address and returns the number of bytes that are mapped after it.
+        /// </summary>
+        /// <param name="va">GPU virtual address to be translated</param>
+        /// <param name="maxSize">Maximum size in bytes to scan</param>
+        /// <returns>Number of bytes, 0 if unmapped</returns>
+        public ulong GetMappedSize(ulong va, ulong maxSize)
+        {
+            if (!ValidateAddress(va))
+            {
+                return 0;
+            }
+
+            ulong startVa = va;
+            ulong endVa = va + maxSize;
+
+            ulong pte = GetPte(va);
+
+            while (pte != PteUnmapped && va < endVa)
+            {
+                va += PageSize - (va & PageMask);
+                pte = GetPte(va);
+            }
+
+            return Math.Min(maxSize, va - startVa);
+        }
+
         /// <summary>
         /// Gets the kind of a given memory page.
         /// This might indicate the type of resource that can be allocated on the page, and also texture tiling.
-- 
cgit v1.2.3-70-g09d2