DeferredShaderData.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using Unity.Collections;
  4. using UnityEngine.Rendering.Universal.Internal;
  5. namespace UnityEngine.Rendering.Universal
  6. {
  7. class DeferredShaderData : IDisposable
  8. {
  9. static DeferredShaderData m_Instance = null;
  10. struct ComputeBufferInfo
  11. {
  12. public uint frameUsed;
  13. public ComputeBufferType type; // There is no interface to retrieve the type of a ComputeBuffer, so we must save it on our side
  14. }
  15. // Precomputed tiles (for each tiler).
  16. NativeArray<PreTile>[] m_PreTiles = null;
  17. // Structured buffers and constant buffers are all allocated from this array.
  18. ComputeBuffer[] m_Buffers = null;
  19. // We need to store extra info per ComputeBuffer.
  20. ComputeBufferInfo[] m_BufferInfos;
  21. // How many buffers have been created so far. This is <= than m_Buffers.Length.
  22. int m_BufferCount = 0;
  23. // Remember index of last buffer used. This optimizes the search for available buffer.
  24. int m_CachedBufferIndex = 0;
  25. // This counter is allowed to cycle back to 0.
  26. uint m_FrameIndex = 0;
  27. DeferredShaderData()
  28. {
  29. m_PreTiles = new NativeArray<PreTile>[DeferredConfig.kTilerDepth];
  30. m_Buffers = new ComputeBuffer[64];
  31. m_BufferInfos = new ComputeBufferInfo[64];
  32. }
  33. internal static DeferredShaderData instance
  34. {
  35. get
  36. {
  37. if (m_Instance == null)
  38. m_Instance = new DeferredShaderData();
  39. return m_Instance;
  40. }
  41. }
  42. public void Dispose()
  43. {
  44. DisposeNativeArrays(ref m_PreTiles);
  45. for (int i = 0; i < m_Buffers.Length; ++i)
  46. {
  47. if (m_Buffers[i] != null)
  48. {
  49. m_Buffers[i].Dispose();
  50. m_Buffers[i] = null;
  51. }
  52. }
  53. m_BufferCount = 0;
  54. }
  55. internal void ResetBuffers()
  56. {
  57. ++m_FrameIndex; // Allowed to cycle back to 0.
  58. }
  59. internal NativeArray<PreTile> GetPreTiles(int level, int count)
  60. {
  61. return GetOrUpdateNativeArray<PreTile>(ref m_PreTiles, level, count);
  62. }
  63. internal ComputeBuffer ReserveBuffer<T>(int count, bool asCBuffer) where T : struct
  64. {
  65. int stride = Marshal.SizeOf<T>();
  66. int paddedCount = asCBuffer ? Align(stride * count, 16) / stride : count;
  67. return GetOrUpdateBuffer(paddedCount, stride, asCBuffer);
  68. }
  69. NativeArray<T> GetOrUpdateNativeArray<T>(ref NativeArray<T>[] nativeArrays, int level, int count) where T : struct
  70. {
  71. if (!nativeArrays[level].IsCreated)
  72. {
  73. nativeArrays[level] = new NativeArray<T>(count, Allocator.Persistent);
  74. }
  75. else if (count > nativeArrays[level].Length)
  76. {
  77. nativeArrays[level].Dispose();
  78. nativeArrays[level] = new NativeArray<T>(count, Allocator.Persistent);
  79. }
  80. return nativeArrays[level];
  81. }
  82. void DisposeNativeArrays<T>(ref NativeArray<T>[] nativeArrays) where T : struct
  83. {
  84. for (int i = 0; i < nativeArrays.Length; ++i)
  85. {
  86. if (nativeArrays[i].IsCreated)
  87. nativeArrays[i].Dispose();
  88. }
  89. }
  90. ComputeBuffer GetOrUpdateBuffer(int count, int stride, bool isConstantBuffer)
  91. {
  92. ComputeBufferType type = isConstantBuffer ? ComputeBufferType.Constant : ComputeBufferType.Structured;
  93. #if UNITY_SWITCH // maxQueuedFrames returns -1 on Switch!
  94. int maxQueuedFrames = 3;
  95. #else
  96. int maxQueuedFrames = QualitySettings.maxQueuedFrames;
  97. Assertions.Assert.IsTrue(maxQueuedFrames >= 1, "invalid QualitySettings.maxQueuedFrames");
  98. #endif
  99. for (int i = 0; i < m_BufferCount; ++i)
  100. {
  101. int bufferIndex = (m_CachedBufferIndex + i + 1) % m_BufferCount;
  102. if (IsLessCircular(m_BufferInfos[bufferIndex].frameUsed + (uint)maxQueuedFrames, m_FrameIndex)
  103. && m_BufferInfos[bufferIndex].type == type && m_Buffers[bufferIndex].count == count && m_Buffers[bufferIndex].stride == stride)
  104. {
  105. m_BufferInfos[bufferIndex].frameUsed = m_FrameIndex;
  106. m_CachedBufferIndex = bufferIndex;
  107. return m_Buffers[bufferIndex];
  108. }
  109. }
  110. if (m_BufferCount == m_Buffers.Length) // If all buffers used: allocate more space.
  111. {
  112. ComputeBuffer[] newBuffers = new ComputeBuffer[m_BufferCount * 2];
  113. for (int i = 0; i < m_BufferCount; ++i)
  114. newBuffers[i] = m_Buffers[i];
  115. m_Buffers = newBuffers;
  116. ComputeBufferInfo[] newBufferInfos = new ComputeBufferInfo[m_BufferCount * 2];
  117. for (int i = 0; i < m_BufferCount; ++i)
  118. newBufferInfos[i] = m_BufferInfos[i];
  119. m_BufferInfos = newBufferInfos;
  120. }
  121. // Create new buffer.
  122. m_Buffers[m_BufferCount] = new ComputeBuffer(count, stride, type, ComputeBufferMode.Immutable);
  123. m_BufferInfos[m_BufferCount].frameUsed = m_FrameIndex;
  124. m_BufferInfos[m_BufferCount].type = type;
  125. m_CachedBufferIndex = m_BufferCount;
  126. return m_Buffers[m_BufferCount++];
  127. }
  128. void DisposeBuffers(ComputeBuffer[,] buffers)
  129. {
  130. for (int i = 0; i < buffers.GetLength(0); ++i)
  131. {
  132. for (int j = 0; j < buffers.GetLength(1); ++j)
  133. {
  134. if (buffers[i, j] != null)
  135. {
  136. buffers[i, j].Dispose();
  137. buffers[i, j] = null;
  138. }
  139. }
  140. }
  141. }
  142. static bool IsLessCircular(uint a, uint b)
  143. {
  144. return a != b ? (b - a) < 0x80000000 : false;
  145. }
  146. static int Align(int s, int alignment)
  147. {
  148. return ((s + alignment - 1) / alignment) * alignment;
  149. }
  150. }
  151. }