|
|
@@ -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();
|