diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan/BufferHolder.cs')
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/BufferHolder.cs | 227 |
1 files changed, 12 insertions, 215 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs b/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs index 3673ee5a..3dcbc313 100644 --- a/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs +++ b/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs @@ -1,4 +1,3 @@ -using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; using Silk.NET.Vulkan; using System; @@ -31,40 +30,29 @@ namespace Ryujinx.Graphics.Vulkan private readonly VulkanRenderer _gd; private readonly Device _device; - private MemoryAllocation _allocation; - private Auto<DisposableBuffer> _buffer; - private Auto<MemoryAllocation> _allocationAuto; + private readonly MemoryAllocation _allocation; + private readonly Auto<DisposableBuffer> _buffer; + private readonly Auto<MemoryAllocation> _allocationAuto; private readonly bool _allocationImported; - private ulong _bufferHandle; + private readonly ulong _bufferHandle; private CacheByRange<BufferHolder> _cachedConvertedBuffers; public int Size { get; } - private IntPtr _map; + private readonly IntPtr _map; - private MultiFenceHolder _waitable; + private readonly MultiFenceHolder _waitable; private bool _lastAccessIsWrite; - private BufferAllocationType _baseType; - private BufferAllocationType _currentType; - private bool _swapQueued; - - public BufferAllocationType DesiredType { get; private set; } - - private int _setCount; - private int _writeCount; - private int _flushCount; - private int _flushTemp; - private int _lastFlushWrite = -1; + private readonly BufferAllocationType _baseType; + private readonly BufferAllocationType _activeType; private readonly ReaderWriterLockSlim _flushLock; private FenceHolder _flushFence; private int _flushWaiting; - private List<Action> _swapActions; - private byte[] _pendingData; private BufferMirrorRangeList _pendingDataRanges; private Dictionary<ulong, StagingBufferReserved> _mirrors; @@ -83,8 +71,7 @@ namespace Ryujinx.Graphics.Vulkan _map = allocation.HostPointer; _baseType = type; - _currentType = currentType; - DesiredType = currentType; + _activeType = currentType; _flushLock = new ReaderWriterLockSlim(); _useMirrors = gd.IsTBDR; @@ -104,8 +91,7 @@ namespace Ryujinx.Graphics.Vulkan _map = _allocation.HostPointer + offset; _baseType = type; - _currentType = currentType; - DesiredType = currentType; + _activeType = currentType; _flushLock = new ReaderWriterLockSlim(); } @@ -120,164 +106,11 @@ namespace Ryujinx.Graphics.Vulkan Size = size; _baseType = BufferAllocationType.Sparse; - _currentType = BufferAllocationType.Sparse; - DesiredType = BufferAllocationType.Sparse; + _activeType = BufferAllocationType.Sparse; _flushLock = new ReaderWriterLockSlim(); } - public bool TryBackingSwap(ref CommandBufferScoped? cbs) - { - if (_swapQueued && DesiredType != _currentType) - { - // Only swap if the buffer is not used in any queued command buffer. - bool isRented = _buffer.HasRentedCommandBufferDependency(_gd.CommandBufferPool); - - if (!isRented && _gd.CommandBufferPool.OwnedByCurrentThread && !_flushLock.IsReadLockHeld && (_pendingData == null || cbs != null)) - { - var currentAllocation = _allocationAuto; - var currentBuffer = _buffer; - IntPtr currentMap = _map; - - (VkBuffer buffer, MemoryAllocation allocation, BufferAllocationType resultType) = _gd.BufferManager.CreateBacking(_gd, Size, DesiredType, false, false, _currentType); - - if (buffer.Handle != 0) - { - if (cbs != null) - { - ClearMirrors(cbs.Value, 0, Size); - } - - _flushLock.EnterWriteLock(); - - ClearFlushFence(); - - _waitable = new MultiFenceHolder(Size); - - _allocation = allocation; - _allocationAuto = new Auto<MemoryAllocation>(allocation); - _buffer = new Auto<DisposableBuffer>(new DisposableBuffer(_gd.Api, _device, buffer), this, _waitable, _allocationAuto); - _bufferHandle = buffer.Handle; - _map = allocation.HostPointer; - - if (_map != IntPtr.Zero && currentMap != IntPtr.Zero) - { - // Copy data directly. Readbacks don't have to wait if this is done. - - unsafe - { - new Span<byte>((void*)currentMap, Size).CopyTo(new Span<byte>((void*)_map, Size)); - } - } - else - { - cbs ??= _gd.CommandBufferPool.Rent(); - - CommandBufferScoped cbsV = cbs.Value; - - Copy(_gd, cbsV, currentBuffer, _buffer, 0, 0, Size); - - // Need to wait for the data to reach the new buffer before data can be flushed. - - _flushFence = _gd.CommandBufferPool.GetFence(cbsV.CommandBufferIndex); - _flushFence.Get(); - } - - Logger.Debug?.PrintMsg(LogClass.Gpu, $"Converted {Size} buffer {_currentType} to {resultType}"); - - _currentType = resultType; - - if (_swapActions != null) - { - foreach (var action in _swapActions) - { - action(); - } - - _swapActions.Clear(); - } - - currentBuffer.Dispose(); - currentAllocation.Dispose(); - - _gd.PipelineInternal.SwapBuffer(currentBuffer, _buffer); - - _flushLock.ExitWriteLock(); - } - - _swapQueued = false; - - return true; - } - - return false; - } - - _swapQueued = false; - - return true; - } - - private void ConsiderBackingSwap() - { - if (_baseType == BufferAllocationType.Auto) - { - // 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) - { - // 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 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. - - 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. - if (_flushCount > 0) - { - _flushTemp = 1000; - } - } - else if (_writeCount >= (WriteCountThreshold << multiplier)) - { - // Buffers that are written often should ideally be in the device local heap. (Storage buffers) - DesiredType = BufferAllocationType.DeviceLocal; - } - else if (_setCount > (SetCountThreshold << multiplier)) - { - // Buffers that have their data set often should ideally be host mapped. (Constant buffers) - DesiredType = BufferAllocationType.HostMapped; - } - - _lastFlushWrite = -1; - _flushCount = 0; - _writeCount = 0; - _setCount = 0; - } - - if (!_swapQueued && DesiredType != _currentType) - { - _swapQueued = true; - - _gd.PipelineInternal.AddBackingSwap(this); - } - } - } - - public void Pin() - { - if (_baseType == BufferAllocationType.Auto) - { - _baseType = _currentType; - } - } - public unsafe Auto<DisposableBufferView> CreateView(VkFormat format, int offset, int size, Action invalidateView) { var bufferViewCreateInfo = new BufferViewCreateInfo @@ -291,19 +124,9 @@ namespace Ryujinx.Graphics.Vulkan _gd.Api.CreateBufferView(_device, bufferViewCreateInfo, null, out var bufferView).ThrowOnError(); - (_swapActions ??= new List<Action>()).Add(invalidateView); - return new Auto<DisposableBufferView>(new DisposableBufferView(_gd.Api, _device, bufferView), this, _waitable, _buffer); } - public void InheritMetrics(BufferHolder other) - { - _setCount = other._setCount; - _writeCount = other._writeCount; - _flushCount = other._flushCount; - _flushTemp = other._flushTemp; - } - public unsafe void InsertBarrier(CommandBuffer commandBuffer, bool isWrite) { // If the last access is write, we always need a barrier to be sure we will read or modify @@ -423,18 +246,8 @@ namespace Ryujinx.Graphics.Vulkan { if (isWrite) { - _writeCount++; - SignalWrite(0, Size); } - else if (isSSBO) - { - // Always consider SSBO access for swapping to device local memory. - - _writeCount++; - - ConsiderBackingSwap(); - } return _buffer; } @@ -443,8 +256,6 @@ namespace Ryujinx.Graphics.Vulkan { if (isWrite) { - _writeCount++; - SignalWrite(offset, size); } @@ -543,8 +354,6 @@ namespace Ryujinx.Graphics.Vulkan public void SignalWrite(int offset, int size) { - ConsiderBackingSwap(); - if (offset == 0 && size == Size) { _cachedConvertedBuffers.Clear(); @@ -624,13 +433,6 @@ namespace Ryujinx.Graphics.Vulkan WaitForFlushFence(); - if (_lastFlushWrite != _writeCount) - { - // If it's on the same page as the last flush, ignore it. - _lastFlushWrite = _writeCount; - _flushCount++; - } - Span<byte> result; if (_map != IntPtr.Zero) @@ -711,8 +513,7 @@ namespace Ryujinx.Graphics.Vulkan return; } - _setCount++; - bool allowMirror = _useMirrors && allowCbsWait && cbs != null && _currentType <= BufferAllocationType.HostMapped; + bool allowMirror = _useMirrors && allowCbsWait && cbs != null && _activeType <= BufferAllocationType.HostMapped; if (_map != IntPtr.Zero) { @@ -863,8 +664,6 @@ namespace Ryujinx.Graphics.Vulkan var dstBuffer = GetBuffer(cbs.CommandBuffer, dstOffset, data.Length, true).Get(cbs, dstOffset, data.Length, true).Value; - _writeCount--; - InsertBufferBarrier( _gd, cbs.CommandBuffer, @@ -1100,8 +899,6 @@ namespace Ryujinx.Graphics.Vulkan public void Dispose() { - _swapQueued = false; - _gd.PipelineInternal?.FlushCommandsIfWeightExceeding(_buffer, (ulong)Size); _buffer.Dispose(); |
