From f94acdb4efcf48555481f38417f8befa4ca560ad Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Sun, 24 Jan 2021 19:22:19 -0300
Subject: [PATCH] Allow out of bounds storage buffer access by aligning their
 sizes (#1870)

* Allow out of bounds storage buffer access by aligning their sizes

* Use correct size

* Fix typo and comment on the reason for the change
---
 Ryujinx.Graphics.Gpu/Memory/Buffer.cs        | 15 +++++++++++++
 Ryujinx.Graphics.Gpu/Memory/BufferManager.cs | 23 ++++++++++++++++++--
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
index 7127871a79..cdd61b6d95 100644
--- a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
@@ -88,6 +88,21 @@ namespace Ryujinx.Graphics.Gpu.Memory
             _modifiedDelegate = new Action<ulong, ulong>(RegionModified);
         }
 
+        /// <summary>
+        /// Gets a sub-range from the buffer, from a start address till the end of the buffer.
+        /// </summary>
+        /// <remarks>
+        /// This can be used to bind and use sub-ranges of the buffer on the host API.
+        /// </remarks>
+        /// <param name="address">Start address of the sub-range, must be greater than or equal to the buffer address</param>
+        /// <returns>The buffer sub-range</returns>
+        public BufferRange GetRange(ulong address)
+        {
+            ulong offset = address - Address;
+
+            return new BufferRange(Handle, (int)offset, (int)(Size - offset));
+        }
+
         /// <summary>
         /// Gets a sub-range from the buffer.
         /// </summary>
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
index cdcc5a370c..08d52faa4b 100644
--- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
@@ -591,7 +591,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
 
                 if (bounds.Address != 0)
                 {
-                    sRanges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size, bounds.Flags.HasFlag(BufferUsageFlags.Write));
+                    // The storage buffer size is not reliable (it might be lower than the actual size),
+                    // so we bind the entire buffer to allow otherwise out of range accesses to work.
+                    sRanges[bindingInfo.Binding] = GetBufferRangeTillEnd(
+                        bounds.Address,
+                        bounds.Size,
+                        bounds.Flags.HasFlag(BufferUsageFlags.Write));
                 }
             }
 
@@ -764,7 +769,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
 
                     if (bounds.Address != 0)
                     {
-                        ranges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size, bounds.Flags.HasFlag(BufferUsageFlags.Write));
+                        ranges[bindingInfo.Binding] = isStorage
+                            ? GetBufferRangeTillEnd(bounds.Address, bounds.Size, bounds.Flags.HasFlag(BufferUsageFlags.Write))
+                            : GetBufferRange(bounds.Address, bounds.Size, bounds.Flags.HasFlag(BufferUsageFlags.Write));
                     }
                 }
             }
@@ -895,6 +902,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
             buffer.SignalModified(address, size);
         }
 
+        /// <summary>
+        /// Gets a buffer sub-range starting at a given memory address.
+        /// </summary>
+        /// <param name="address">Start address of the memory range</param>
+        /// <param name="size">Size in bytes of the memory range</param>
+        /// <param name="write">Whether the buffer will be written to by this use</param>
+        /// <returns>The buffer sub-range starting at the given memory address</returns>
+        private BufferRange GetBufferRangeTillEnd(ulong address, ulong size, bool write = false)
+        {
+            return GetBuffer(address, size, write).GetRange(address);
+        }
+
         /// <summary>
         /// Gets a buffer sub-range for a given memory range.
         /// </summary>