aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2022-03-14 23:33:53 -0300
committerGitHub <noreply@github.com>2022-03-15 03:33:53 +0100
commit79becc4b78bd8a8402cc86a96c812cb8ac9d027a (patch)
tree19b07f3c0aea1afbb116112a69c415e5120b20c2 /Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
parent223172ac0babc7dc272a5489ac2e91062a12a0c2 (diff)
Dynamically increase buffer size when resizing (#2861)1.1.73
* Grow buffers by 1.5x of its size when resizing * Further restrict the cases where the dynamic expansion is done
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Memory/BufferCache.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferCache.cs33
1 files changed, 31 insertions, 2 deletions
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs b/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
index 63d22150..14b177aa 100644
--- a/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
@@ -17,6 +17,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
private const ulong BufferAlignmentSize = 0x1000;
private const ulong BufferAlignmentMask = BufferAlignmentSize - 1;
+ private const ulong MaxDynamicGrowthSize = 0x100000;
+
private readonly GpuContext _context;
private readonly PhysicalMemory _physicalMemory;
@@ -166,10 +168,35 @@ namespace Ryujinx.Graphics.Gpu.Memory
// Otherwise, we must delete the overlapping buffers and create a bigger buffer
// that fits all the data we need. We also need to copy the contents from the
// old buffer(s) to the new buffer.
+
ulong endAddress = address + size;
if (_bufferOverlaps[0].Address > address || _bufferOverlaps[0].EndAddress < endAddress)
{
+ // Check if the following conditions are met:
+ // - We have a single overlap.
+ // - The overlap starts at or before the requested range. That is, the overlap happens at the end.
+ // - The size delta between the new, merged buffer and the old one is of at most 2 pages.
+ // In this case, we attempt to extend the buffer further than the requested range,
+ // this can potentially avoid future resizes if the application keeps using overlapping
+ // sequential memory.
+ // Allowing for 2 pages (rather than just one) is necessary to catch cases where the
+ // range crosses a page, and after alignment, ends having a size of 2 pages.
+ if (overlapsCount == 1 &&
+ address >= _bufferOverlaps[0].Address &&
+ endAddress - _bufferOverlaps[0].EndAddress <= BufferAlignmentSize * 2)
+ {
+ // Try to grow the buffer by 1.5x of its current size.
+ // This improves performance in the cases where the buffer is resized often by small amounts.
+ ulong existingSize = _bufferOverlaps[0].Size;
+ ulong growthSize = (existingSize + Math.Min(existingSize >> 1, MaxDynamicGrowthSize)) & ~BufferAlignmentMask;
+
+ size = Math.Max(size, growthSize);
+ endAddress = address + size;
+
+ overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref _bufferOverlaps);
+ }
+
for (int index = 0; index < overlapsCount; index++)
{
Buffer buffer = _bufferOverlaps[index];
@@ -183,7 +210,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
}
- Buffer newBuffer = new Buffer(_context, _physicalMemory, address, endAddress - address, _bufferOverlaps.Take(overlapsCount));
+ ulong newSize = endAddress - address;
+
+ Buffer newBuffer = new Buffer(_context, _physicalMemory, address, newSize, _bufferOverlaps.Take(overlapsCount));
lock (_buffers)
{
@@ -202,7 +231,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
buffer.DisposeData();
}
- newBuffer.SynchronizeMemory(address, endAddress - address);
+ newBuffer.SynchronizeMemory(address, newSize);
// Existing buffers were modified, we need to rebind everything.
NotifyBuffersModified?.Invoke();