aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Vulkan/Auto.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Vulkan/Auto.cs')
-rw-r--r--Ryujinx.Graphics.Vulkan/Auto.cs154
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;
+ }
+ }
+ }
+}