FenceHolder.cs
1 using Silk.NET.Vulkan; 2 using System; 3 using System.Threading; 4 5 namespace Ryujinx.Graphics.Vulkan 6 { 7 class FenceHolder : IDisposable 8 { 9 private readonly Vk _api; 10 private readonly Device _device; 11 private Fence _fence; 12 private int _referenceCount; 13 private int _lock; 14 private readonly bool _concurrentWaitUnsupported; 15 private bool _disposed; 16 17 public unsafe FenceHolder(Vk api, Device device, bool concurrentWaitUnsupported) 18 { 19 _api = api; 20 _device = device; 21 _concurrentWaitUnsupported = concurrentWaitUnsupported; 22 23 var fenceCreateInfo = new FenceCreateInfo 24 { 25 SType = StructureType.FenceCreateInfo, 26 }; 27 28 api.CreateFence(device, in fenceCreateInfo, null, out _fence).ThrowOnError(); 29 30 _referenceCount = 1; 31 } 32 33 public Fence GetUnsafe() 34 { 35 return _fence; 36 } 37 38 public bool TryGet(out Fence fence) 39 { 40 int lastValue; 41 do 42 { 43 lastValue = _referenceCount; 44 45 if (lastValue == 0) 46 { 47 fence = default; 48 return false; 49 } 50 } 51 while (Interlocked.CompareExchange(ref _referenceCount, lastValue + 1, lastValue) != lastValue); 52 53 if (_concurrentWaitUnsupported) 54 { 55 AcquireLock(); 56 } 57 58 fence = _fence; 59 return true; 60 } 61 62 public Fence Get() 63 { 64 Interlocked.Increment(ref _referenceCount); 65 return _fence; 66 } 67 68 public void PutLock() 69 { 70 Put(); 71 72 if (_concurrentWaitUnsupported) 73 { 74 ReleaseLock(); 75 } 76 } 77 78 public void Put() 79 { 80 if (Interlocked.Decrement(ref _referenceCount) == 0) 81 { 82 _api.DestroyFence(_device, _fence, Span<AllocationCallbacks>.Empty); 83 _fence = default; 84 } 85 } 86 87 private void AcquireLock() 88 { 89 while (!TryAcquireLock()) 90 { 91 Thread.SpinWait(32); 92 } 93 } 94 95 private bool TryAcquireLock() 96 { 97 return Interlocked.Exchange(ref _lock, 1) == 0; 98 } 99 100 private void ReleaseLock() 101 { 102 Interlocked.Exchange(ref _lock, 0); 103 } 104 105 public void Wait() 106 { 107 if (_concurrentWaitUnsupported) 108 { 109 AcquireLock(); 110 111 try 112 { 113 FenceHelper.WaitAllIndefinitely(_api, _device, stackalloc Fence[] { _fence }); 114 } 115 finally 116 { 117 ReleaseLock(); 118 } 119 } 120 else 121 { 122 FenceHelper.WaitAllIndefinitely(_api, _device, stackalloc Fence[] { _fence }); 123 } 124 } 125 126 public bool IsSignaled() 127 { 128 if (_concurrentWaitUnsupported) 129 { 130 if (!TryAcquireLock()) 131 { 132 return false; 133 } 134 135 try 136 { 137 return FenceHelper.AllSignaled(_api, _device, stackalloc Fence[] { _fence }); 138 } 139 finally 140 { 141 ReleaseLock(); 142 } 143 } 144 else 145 { 146 return FenceHelper.AllSignaled(_api, _device, stackalloc Fence[] { _fence }); 147 } 148 } 149 150 public void Dispose() 151 { 152 if (!_disposed) 153 { 154 Put(); 155 _disposed = true; 156 } 157 } 158 } 159 }