Vulkan: Device map buffers written more than flushed (#4911)

This commit is contained in:
riperiperi 2023-05-13 14:15:05 +01:00 committed by GitHub
parent aae4595bdb
commit 17ba217940
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -56,6 +56,7 @@ namespace Ryujinx.Graphics.Vulkan
private int _writeCount; private int _writeCount;
private int _flushCount; private int _flushCount;
private int _flushTemp; private int _flushTemp;
private int _lastFlushWrite = -1;
private ReaderWriterLock _flushLock; private ReaderWriterLock _flushLock;
private FenceHolder _flushFence; private FenceHolder _flushFence;
@ -200,14 +201,21 @@ namespace Ryujinx.Graphics.Vulkan
{ {
if (_baseType == BufferAllocationType.Auto) if (_baseType == BufferAllocationType.Auto)
{ {
if (_writeCount >= WriteCountThreshold || _setCount >= SetCountThreshold || _flushCount >= FlushCountThreshold) // When flushed, wait for a bit more info to make a decision.
bool wasFlushed = _flushTemp > 0;
int multiplier = wasFlushed ? 2 : 0;
if (_writeCount >= (WriteCountThreshold << multiplier) || _setCount >= (SetCountThreshold << multiplier) || _flushCount >= (FlushCountThreshold << multiplier))
{ {
if (_flushCount > 0 || _flushTemp-- > 0) if (_flushCount > 0 || _flushTemp-- > 0)
{ {
// Buffers that flush should ideally be mapped in host address space for easy copies. // Buffers that flush should ideally be mapped in host address space for easy copies.
// If the buffer is large it will do better on GPU memory, as there will be more writes than data flushes (typically individual pages). // If the buffer is large it will do better on GPU memory, as there will be more writes than data flushes (typically individual pages).
// If it is small, then it's likely most of the buffer will be flushed so we want it on host memory, as access is cached. // If it is small, then it's likely most of the buffer will be flushed so we want it on host memory, as access is cached.
DesiredType = Size > DeviceLocalSizeThreshold ? BufferAllocationType.DeviceLocalMapped : BufferAllocationType.HostMapped;
bool hostMappingSensitive = _gd.Vendor == Vendor.Nvidia;
bool deviceLocalMapped = Size > DeviceLocalSizeThreshold || (wasFlushed && _writeCount > _flushCount * 10 && hostMappingSensitive) || _currentType == BufferAllocationType.DeviceLocalMapped;
DesiredType = deviceLocalMapped ? BufferAllocationType.DeviceLocalMapped : BufferAllocationType.HostMapped;
// It's harder for a buffer that is flushed to revert to another type of mapping. // It's harder for a buffer that is flushed to revert to another type of mapping.
if (_flushCount > 0) if (_flushCount > 0)
@ -215,17 +223,18 @@ namespace Ryujinx.Graphics.Vulkan
_flushTemp = 1000; _flushTemp = 1000;
} }
} }
else if (_writeCount >= WriteCountThreshold) else if (_writeCount >= (WriteCountThreshold << multiplier))
{ {
// Buffers that are written often should ideally be in the device local heap. (Storage buffers) // Buffers that are written often should ideally be in the device local heap. (Storage buffers)
DesiredType = BufferAllocationType.DeviceLocal; DesiredType = BufferAllocationType.DeviceLocal;
} }
else if (_setCount > SetCountThreshold) else if (_setCount > (SetCountThreshold << multiplier))
{ {
// Buffers that have their data set often should ideally be host mapped. (Constant buffers) // Buffers that have their data set often should ideally be host mapped. (Constant buffers)
DesiredType = BufferAllocationType.HostMapped; DesiredType = BufferAllocationType.HostMapped;
} }
_lastFlushWrite = -1;
_flushCount = 0; _flushCount = 0;
_writeCount = 0; _writeCount = 0;
_setCount = 0; _setCount = 0;
@ -418,7 +427,12 @@ namespace Ryujinx.Graphics.Vulkan
WaitForFlushFence(); WaitForFlushFence();
if (_lastFlushWrite != _writeCount)
{
// If it's on the same page as the last flush, ignore it.
_lastFlushWrite = _writeCount;
_flushCount++; _flushCount++;
}
Span<byte> result; Span<byte> result;