Dynamically increase buffer size when resizing (#2861)
* Grow buffers by 1.5x of its size when resizing * Further restrict the cases where the dynamic expansion is done
This commit is contained in:
parent
223172ac0b
commit
79becc4b78
1 changed files with 31 additions and 2 deletions
|
@ -17,6 +17,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
private const ulong BufferAlignmentSize = 0x1000;
|
private const ulong BufferAlignmentSize = 0x1000;
|
||||||
private const ulong BufferAlignmentMask = BufferAlignmentSize - 1;
|
private const ulong BufferAlignmentMask = BufferAlignmentSize - 1;
|
||||||
|
|
||||||
|
private const ulong MaxDynamicGrowthSize = 0x100000;
|
||||||
|
|
||||||
private readonly GpuContext _context;
|
private readonly GpuContext _context;
|
||||||
private readonly PhysicalMemory _physicalMemory;
|
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
|
// 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
|
// that fits all the data we need. We also need to copy the contents from the
|
||||||
// old buffer(s) to the new buffer.
|
// old buffer(s) to the new buffer.
|
||||||
|
|
||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
|
|
||||||
if (_bufferOverlaps[0].Address > address || _bufferOverlaps[0].EndAddress < endAddress)
|
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++)
|
for (int index = 0; index < overlapsCount; index++)
|
||||||
{
|
{
|
||||||
Buffer buffer = _bufferOverlaps[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)
|
lock (_buffers)
|
||||||
{
|
{
|
||||||
|
@ -202,7 +231,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
buffer.DisposeData();
|
buffer.DisposeData();
|
||||||
}
|
}
|
||||||
|
|
||||||
newBuffer.SynchronizeMemory(address, endAddress - address);
|
newBuffer.SynchronizeMemory(address, newSize);
|
||||||
|
|
||||||
// Existing buffers were modified, we need to rebind everything.
|
// Existing buffers were modified, we need to rebind everything.
|
||||||
NotifyBuffersModified?.Invoke();
|
NotifyBuffersModified?.Invoke();
|
||||||
|
|
Reference in a new issue