Auto.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. using System;
  2. using System.Diagnostics;
  3. using System.Threading;
  4. namespace Ryujinx.Graphics.Vulkan
  5. {
  6. interface IAuto
  7. {
  8. bool HasCommandBufferDependency(CommandBufferScoped cbs);
  9. void IncrementReferenceCount();
  10. void DecrementReferenceCount(int cbIndex);
  11. void DecrementReferenceCount();
  12. }
  13. interface IAutoPrivate : IAuto
  14. {
  15. void AddCommandBufferDependencies(CommandBufferScoped cbs);
  16. }
  17. class Auto<T> : IAutoPrivate, IDisposable where T : IDisposable
  18. {
  19. private int _referenceCount;
  20. private T _value;
  21. private readonly BitMap _cbOwnership;
  22. private readonly MultiFenceHolder _waitable;
  23. private readonly IAutoPrivate[] _referencedObjs;
  24. private bool _disposed;
  25. private bool _destroyed;
  26. public Auto(T value)
  27. {
  28. _referenceCount = 1;
  29. _value = value;
  30. _cbOwnership = new BitMap(CommandBufferPool.MaxCommandBuffers);
  31. }
  32. public Auto(T value, MultiFenceHolder waitable, params IAutoPrivate[] referencedObjs) : this(value)
  33. {
  34. _waitable = waitable;
  35. _referencedObjs = referencedObjs;
  36. for (int i = 0; i < referencedObjs.Length; i++)
  37. {
  38. referencedObjs[i].IncrementReferenceCount();
  39. }
  40. }
  41. public T Get(CommandBufferScoped cbs, int offset, int size)
  42. {
  43. _waitable?.AddBufferUse(cbs.CommandBufferIndex, offset, size);
  44. return Get(cbs);
  45. }
  46. public T GetUnsafe()
  47. {
  48. return _value;
  49. }
  50. public T Get(CommandBufferScoped cbs)
  51. {
  52. if (!_destroyed)
  53. {
  54. AddCommandBufferDependencies(cbs);
  55. }
  56. return _value;
  57. }
  58. public bool HasCommandBufferDependency(CommandBufferScoped cbs)
  59. {
  60. return _cbOwnership.IsSet(cbs.CommandBufferIndex);
  61. }
  62. public bool HasRentedCommandBufferDependency(CommandBufferPool cbp)
  63. {
  64. return _cbOwnership.AnySet();
  65. }
  66. public void AddCommandBufferDependencies(CommandBufferScoped cbs)
  67. {
  68. // We don't want to add a reference to this object to the command buffer
  69. // more than once, so if we detect that the command buffer already has ownership
  70. // of this object, then we can just return without doing anything else.
  71. if (_cbOwnership.Set(cbs.CommandBufferIndex))
  72. {
  73. if (_waitable != null)
  74. {
  75. cbs.AddWaitable(_waitable);
  76. }
  77. cbs.AddDependant(this);
  78. // We need to add a dependency on the command buffer to all objects this object
  79. // references aswell.
  80. if (_referencedObjs != null)
  81. {
  82. for (int i = 0; i < _referencedObjs.Length; i++)
  83. {
  84. _referencedObjs[i].AddCommandBufferDependencies(cbs);
  85. }
  86. }
  87. }
  88. }
  89. public void IncrementReferenceCount()
  90. {
  91. if (Interlocked.Increment(ref _referenceCount) == 1)
  92. {
  93. Interlocked.Decrement(ref _referenceCount);
  94. throw new InvalidOperationException("Attempted to increment the reference count of an object that was already destroyed.");
  95. }
  96. }
  97. public void DecrementReferenceCount(int cbIndex)
  98. {
  99. _cbOwnership.Clear(cbIndex);
  100. DecrementReferenceCount();
  101. }
  102. public void DecrementReferenceCount()
  103. {
  104. if (Interlocked.Decrement(ref _referenceCount) == 0)
  105. {
  106. _value.Dispose();
  107. _value = default;
  108. _destroyed = true;
  109. // Value is no longer in use by the GPU, dispose all other
  110. // resources that it references.
  111. if (_referencedObjs != null)
  112. {
  113. for (int i = 0; i < _referencedObjs.Length; i++)
  114. {
  115. _referencedObjs[i].DecrementReferenceCount();
  116. }
  117. }
  118. }
  119. Debug.Assert(_referenceCount >= 0);
  120. }
  121. public void Dispose()
  122. {
  123. if (!_disposed)
  124. {
  125. DecrementReferenceCount();
  126. _disposed = true;
  127. }
  128. }
  129. }
  130. }