forked from MeloNX/MeloNX
Add spin lock to prevent waiting for fences on multiple threads at once on Adreno
This commit is contained in:
parent
3e6ec4aea8
commit
f1814ca542
@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
lock (queueLock)
|
||||
{
|
||||
_pool = new CommandBufferPool(_gd.Api, _device, queue, queueLock, _gd.QueueFamilyIndex, isLight: true);
|
||||
_pool = new CommandBufferPool(_gd.Api, _device, queue, queueLock, _gd.QueueFamilyIndex, _gd.Vendor == Vendor.Qualcomm, isLight: true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private readonly Device _device;
|
||||
private readonly Queue _queue;
|
||||
private readonly object _queueLock;
|
||||
private readonly bool _fenceNeedsLock;
|
||||
private readonly CommandPool _pool;
|
||||
private readonly Thread _owner;
|
||||
|
||||
@ -61,12 +62,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private int _queuedCount;
|
||||
private int _inUseCount;
|
||||
|
||||
public unsafe CommandBufferPool(Vk api, Device device, Queue queue, object queueLock, uint queueFamilyIndex, bool isLight = false)
|
||||
public unsafe CommandBufferPool(Vk api, Device device, Queue queue, object queueLock, uint queueFamilyIndex, bool fenceNeedsLock, bool isLight = false)
|
||||
{
|
||||
_api = api;
|
||||
_device = device;
|
||||
_queue = queue;
|
||||
_queueLock = queueLock;
|
||||
_fenceNeedsLock = fenceNeedsLock;
|
||||
_owner = Thread.CurrentThread;
|
||||
|
||||
var commandPoolCreateInfo = new CommandPoolCreateInfo
|
||||
@ -357,7 +359,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (refreshFence)
|
||||
{
|
||||
entry.Fence = new FenceHolder(_api, _device);
|
||||
entry.Fence = new FenceHolder(_api, _device, _fenceNeedsLock);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -10,12 +10,15 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private readonly Device _device;
|
||||
private Fence _fence;
|
||||
private int _referenceCount;
|
||||
private int _lock;
|
||||
private readonly bool _needsLock;
|
||||
private bool _disposed;
|
||||
|
||||
public unsafe FenceHolder(Vk api, Device device)
|
||||
public unsafe FenceHolder(Vk api, Device device, bool needsLock)
|
||||
{
|
||||
_api = api;
|
||||
_device = device;
|
||||
_needsLock = needsLock;
|
||||
|
||||
var fenceCreateInfo = new FenceCreateInfo
|
||||
{
|
||||
@ -47,6 +50,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
while (Interlocked.CompareExchange(ref _referenceCount, lastValue + 1, lastValue) != lastValue);
|
||||
|
||||
if (_needsLock)
|
||||
{
|
||||
AcquireLock();
|
||||
}
|
||||
|
||||
fence = _fence;
|
||||
return true;
|
||||
}
|
||||
@ -57,6 +65,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return _fence;
|
||||
}
|
||||
|
||||
public void PutLock()
|
||||
{
|
||||
Put();
|
||||
|
||||
if (_needsLock)
|
||||
{
|
||||
ReleaseLock();
|
||||
}
|
||||
}
|
||||
|
||||
public void Put()
|
||||
{
|
||||
if (Interlocked.Decrement(ref _referenceCount) == 0)
|
||||
@ -66,24 +84,54 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
private void AcquireLock()
|
||||
{
|
||||
while (!TryAcquireLock())
|
||||
{
|
||||
Thread.SpinWait(32);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryAcquireLock()
|
||||
{
|
||||
return Interlocked.Exchange(ref _lock, 1) == 0;
|
||||
}
|
||||
|
||||
private void ReleaseLock()
|
||||
{
|
||||
Interlocked.Exchange(ref _lock, 0);
|
||||
}
|
||||
|
||||
public void Wait()
|
||||
{
|
||||
Span<Fence> fences = stackalloc Fence[]
|
||||
if (_needsLock)
|
||||
{
|
||||
_fence,
|
||||
};
|
||||
AcquireLock();
|
||||
}
|
||||
|
||||
FenceHelper.WaitAllIndefinitely(_api, _device, fences);
|
||||
FenceHelper.WaitAllIndefinitely(_api, _device, stackalloc Fence[] { _fence });
|
||||
|
||||
if (_needsLock)
|
||||
{
|
||||
ReleaseLock();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSignaled()
|
||||
{
|
||||
Span<Fence> fences = stackalloc Fence[]
|
||||
if (_needsLock && !TryAcquireLock())
|
||||
{
|
||||
_fence,
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
return FenceHelper.AllSignaled(_api, _device, fences);
|
||||
bool result = FenceHelper.AllSignaled(_api, _device, stackalloc Fence[] { _fence });
|
||||
|
||||
if (_needsLock)
|
||||
{
|
||||
ReleaseLock();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -205,7 +205,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
for (int i = 0; i < fenceCount; i++)
|
||||
{
|
||||
fenceHolders[i].Put();
|
||||
fenceHolders[i].PutLock();
|
||||
}
|
||||
|
||||
return signaled;
|
||||
|
@ -291,6 +291,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
ref var properties = ref properties2.Properties;
|
||||
|
||||
Vendor = VendorUtils.FromId(properties.VendorID);
|
||||
|
||||
ulong minResourceAlignment = Math.Max(
|
||||
Math.Max(
|
||||
properties.Limits.MinStorageBufferOffsetAlignment,
|
||||
@ -347,7 +349,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtExternalMemoryHost hostMemoryApi);
|
||||
HostMemoryAllocator = new HostMemoryAllocator(MemoryAllocator, Api, hostMemoryApi, _device);
|
||||
|
||||
CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex);
|
||||
CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex, Vendor == Vendor.Qualcomm);
|
||||
|
||||
DescriptorSetManager = new DescriptorSetManager(_device, PipelineBase.DescriptorSetLayouts);
|
||||
|
||||
@ -697,8 +699,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
string vendorName = VendorUtils.GetNameFromId(properties.VendorID);
|
||||
|
||||
Vendor = VendorUtils.FromId(properties.VendorID);
|
||||
|
||||
IsAmdWindows = Vendor == Vendor.Amd && OperatingSystem.IsWindows();
|
||||
IsIntelWindows = Vendor == Vendor.Intel && OperatingSystem.IsWindows();
|
||||
IsTBDR =
|
||||
|
Loading…
x
Reference in New Issue
Block a user