diff options
Diffstat (limited to 'Ryujinx.Graphics.Vulkan/Auto.cs')
-rw-r--r-- | Ryujinx.Graphics.Vulkan/Auto.cs | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Vulkan/Auto.cs b/Ryujinx.Graphics.Vulkan/Auto.cs new file mode 100644 index 00000000..77261de9 --- /dev/null +++ b/Ryujinx.Graphics.Vulkan/Auto.cs @@ -0,0 +1,154 @@ +using System; +using System.Diagnostics; +using System.Threading; + +namespace Ryujinx.Graphics.Vulkan +{ + interface IAuto + { + bool HasCommandBufferDependency(CommandBufferScoped cbs); + + void IncrementReferenceCount(); + void DecrementReferenceCount(int cbIndex); + void DecrementReferenceCount(); + } + + interface IAutoPrivate : IAuto + { + void AddCommandBufferDependencies(CommandBufferScoped cbs); + } + + class Auto<T> : IAutoPrivate, IDisposable where T : IDisposable + { + private int _referenceCount; + private T _value; + + private readonly BitMap _cbOwnership; + private readonly MultiFenceHolder _waitable; + private readonly IAutoPrivate[] _referencedObjs; + + private bool _disposed; + private bool _destroyed; + + public Auto(T value) + { + _referenceCount = 1; + _value = value; + _cbOwnership = new BitMap(CommandBufferPool.MaxCommandBuffers); + } + + public Auto(T value, MultiFenceHolder waitable, params IAutoPrivate[] referencedObjs) : this(value) + { + _waitable = waitable; + _referencedObjs = referencedObjs; + + for (int i = 0; i < referencedObjs.Length; i++) + { + referencedObjs[i].IncrementReferenceCount(); + } + } + + public T Get(CommandBufferScoped cbs, int offset, int size) + { + _waitable?.AddBufferUse(cbs.CommandBufferIndex, offset, size); + return Get(cbs); + } + + public T GetUnsafe() + { + return _value; + } + + public T Get(CommandBufferScoped cbs) + { + if (!_destroyed) + { + AddCommandBufferDependencies(cbs); + } + + return _value; + } + + public bool HasCommandBufferDependency(CommandBufferScoped cbs) + { + return _cbOwnership.IsSet(cbs.CommandBufferIndex); + } + + public bool HasRentedCommandBufferDependency(CommandBufferPool cbp) + { + return _cbOwnership.AnySet(); + } + + public void AddCommandBufferDependencies(CommandBufferScoped cbs) + { + // We don't want to add a reference to this object to the command buffer + // more than once, so if we detect that the command buffer already has ownership + // of this object, then we can just return without doing anything else. + if (_cbOwnership.Set(cbs.CommandBufferIndex)) + { + if (_waitable != null) + { + cbs.AddWaitable(_waitable); + } + + cbs.AddDependant(this); + + // We need to add a dependency on the command buffer to all objects this object + // references aswell. + if (_referencedObjs != null) + { + for (int i = 0; i < _referencedObjs.Length; i++) + { + _referencedObjs[i].AddCommandBufferDependencies(cbs); + } + } + } + } + + public void IncrementReferenceCount() + { + if (Interlocked.Increment(ref _referenceCount) == 1) + { + Interlocked.Decrement(ref _referenceCount); + throw new InvalidOperationException("Attempted to increment the reference count of an object that was already destroyed."); + } + } + + public void DecrementReferenceCount(int cbIndex) + { + _cbOwnership.Clear(cbIndex); + DecrementReferenceCount(); + } + + public void DecrementReferenceCount() + { + if (Interlocked.Decrement(ref _referenceCount) == 0) + { + _value.Dispose(); + _value = default; + _destroyed = true; + + // Value is no longer in use by the GPU, dispose all other + // resources that it references. + if (_referencedObjs != null) + { + for (int i = 0; i < _referencedObjs.Length; i++) + { + _referencedObjs[i].DecrementReferenceCount(); + } + } + } + + Debug.Assert(_referenceCount >= 0); + } + + public void Dispose() + { + if (!_disposed) + { + DecrementReferenceCount(); + _disposed = true; + } + } + } +} |