Auto.cs 3.9 KB

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