From 1b28ecd63eb49917e3711eb7e06739ebe87e8f41 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Mon, 8 May 2023 11:45:12 +0100 Subject: Vulkan: Simplify MultiFenceHolder and managing them (#4845) * Vulkan: Simplify waitable add/remove Removal of unnecessary hashset and dictionary * Thread safety for GetBufferData in PersistentFlushBuffer * Fix WaitForFencesImpl thread safety * Proper methods for risky reference increments * Wrong type of CB. * Address feedback --- src/Ryujinx.Graphics.Vulkan/MultiFenceHolder.cs | 111 ++++++++++++++++-------- 1 file changed, 76 insertions(+), 35 deletions(-) (limited to 'src/Ryujinx.Graphics.Vulkan/MultiFenceHolder.cs') diff --git a/src/Ryujinx.Graphics.Vulkan/MultiFenceHolder.cs b/src/Ryujinx.Graphics.Vulkan/MultiFenceHolder.cs index 9a9a3626..13a4f4c1 100644 --- a/src/Ryujinx.Graphics.Vulkan/MultiFenceHolder.cs +++ b/src/Ryujinx.Graphics.Vulkan/MultiFenceHolder.cs @@ -1,6 +1,5 @@ using Silk.NET.Vulkan; -using System.Collections.Generic; -using System.Linq; +using System; namespace Ryujinx.Graphics.Vulkan { @@ -11,7 +10,7 @@ namespace Ryujinx.Graphics.Vulkan { private static int BufferUsageTrackingGranularity = 4096; - private readonly Dictionary _fences; + private readonly FenceHolder[] _fences; private BufferUsageBitmap _bufferUsageBitmap; /// @@ -19,7 +18,7 @@ namespace Ryujinx.Graphics.Vulkan /// public MultiFenceHolder() { - _fences = new Dictionary(); + _fences = new FenceHolder[CommandBufferPool.MaxCommandBuffers]; } /// @@ -28,7 +27,7 @@ namespace Ryujinx.Graphics.Vulkan /// Size of the buffer public MultiFenceHolder(int size) { - _fences = new Dictionary(); + _fences = new FenceHolder[CommandBufferPool.MaxCommandBuffers]; _bufferUsageBitmap = new BufferUsageBitmap(size, BufferUsageTrackingGranularity); } @@ -80,25 +79,37 @@ namespace Ryujinx.Graphics.Vulkan /// /// Command buffer index of the command buffer that owns the fence /// Fence to be added - public void AddFence(int cbIndex, FenceHolder fence) + /// True if the command buffer's previous fence value was null + public bool AddFence(int cbIndex, FenceHolder fence) { - lock (_fences) + ref FenceHolder fenceRef = ref _fences[cbIndex]; + + if (fenceRef == null) { - _fences.TryAdd(fence, cbIndex); + fenceRef = fence; + return true; } + + return false; } /// /// Removes a fence from the holder. /// /// Command buffer index of the command buffer that owns the fence - /// Fence to be removed - public void RemoveFence(int cbIndex, FenceHolder fence) + public void RemoveFence(int cbIndex) { - lock (_fences) - { - _fences.Remove(fence); - } + _fences[cbIndex] = null; + } + + /// + /// Determines if a fence referenced on the given command buffer. + /// + /// Index of the command buffer to check if it's used + /// True if referenced, false otherwise + public bool HasFence(int cbIndex) + { + return _fences[cbIndex] != null; } /// @@ -147,21 +158,29 @@ namespace Ryujinx.Graphics.Vulkan /// True if all fences were signaled before the timeout expired, false otherwise private bool WaitForFencesImpl(Vk api, Device device, int offset, int size, bool hasTimeout, ulong timeout) { - FenceHolder[] fenceHolders; - Fence[] fences; + Span fenceHolders = new FenceHolder[CommandBufferPool.MaxCommandBuffers]; - lock (_fences) - { - fenceHolders = size != 0 ? GetOverlappingFences(offset, size) : _fences.Keys.ToArray(); - fences = new Fence[fenceHolders.Length]; + int count = size != 0 ? GetOverlappingFences(fenceHolders, offset, size) : GetFences(fenceHolders); + Span fences = stackalloc Fence[count]; - for (int i = 0; i < fenceHolders.Length; i++) + int fenceCount = 0; + + for (int i = 0; i < count; i++) + { + if (fenceHolders[i].TryGet(out Fence fence)) { - fences[i] = fenceHolders[i].Get(); + fences[fenceCount] = fence; + + if (fenceCount < i) + { + fenceHolders[fenceCount] = fenceHolders[i]; + } + + fenceCount++; } } - if (fences.Length == 0) + if (fenceCount == 0) { return true; } @@ -170,14 +189,14 @@ namespace Ryujinx.Graphics.Vulkan if (hasTimeout) { - signaled = FenceHelper.AllSignaled(api, device, fences, timeout); + signaled = FenceHelper.AllSignaled(api, device, fences.Slice(0, fenceCount), timeout); } else { - FenceHelper.WaitAllIndefinitely(api, device, fences); + FenceHelper.WaitAllIndefinitely(api, device, fences.Slice(0, fenceCount)); } - for (int i = 0; i < fenceHolders.Length; i++) + for (int i = 0; i < fenceCount; i++) { fenceHolders[i].Put(); } @@ -185,28 +204,50 @@ namespace Ryujinx.Graphics.Vulkan return signaled; } + /// + /// Gets fences to wait for. + /// + /// Span to store fences in + /// Number of fences placed in storage + private int GetFences(Span storage) + { + int count = 0; + + for (int i = 0; i < _fences.Length; i++) + { + var fence = _fences[i]; + + if (fence != null) + { + storage[count++] = fence; + } + } + + return count; + } + /// /// Gets fences to wait for use of a given buffer region. /// + /// Span to store overlapping fences in /// Offset of the range /// Size of the range in bytes - /// Fences for the specified region - private FenceHolder[] GetOverlappingFences(int offset, int size) + /// Number of fences for the specified region placed in storage + private int GetOverlappingFences(Span storage, int offset, int size) { - List overlapping = new List(); + int count = 0; - foreach (var kv in _fences) + for (int i = 0; i < _fences.Length; i++) { - var fence = kv.Key; - var ownerCbIndex = kv.Value; + var fence = _fences[i]; - if (_bufferUsageBitmap.OverlapsWith(ownerCbIndex, offset, size)) + if (fence != null && _bufferUsageBitmap.OverlapsWith(i, offset, size)) { - overlapping.Add(fence); + storage[count++] = fence; } } - return overlapping.ToArray(); + return count; } } } -- cgit v1.2.3