Nenhuma descrição
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

LightBatch.cs 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. using UnityEngine.Experimental.Rendering;
  2. using Unity.Collections;
  3. using Unity.Mathematics;
  4. using Unity.Collections.LowLevel.Unsafe;
  5. namespace UnityEngine.Rendering.Universal
  6. {
  7. internal class LightBuffer
  8. {
  9. static readonly internal int kMax = 2048 * 8;
  10. static readonly internal int kCount = 1;
  11. static readonly internal int kLightMod = 64;
  12. static readonly internal int kBatchMax = 256;
  13. private GraphicsBuffer m_GraphicsBuffer;
  14. private NativeArray<int> m_Markers = new NativeArray<int>(kBatchMax, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  15. private NativeArray<PerLight2D> m_NativeBuffer = new NativeArray<PerLight2D>(kMax, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  16. internal GraphicsBuffer graphicsBuffer
  17. {
  18. get
  19. {
  20. if (null == m_GraphicsBuffer)
  21. m_GraphicsBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, kMax, UnsafeUtility.SizeOf<PerLight2D>());
  22. return m_GraphicsBuffer;
  23. }
  24. }
  25. internal NativeArray<int> lightMarkers
  26. {
  27. get
  28. {
  29. return m_Markers;
  30. }
  31. }
  32. internal NativeArray<PerLight2D> nativeBuffer
  33. {
  34. get
  35. {
  36. return m_NativeBuffer;
  37. }
  38. }
  39. internal void Release()
  40. {
  41. m_GraphicsBuffer.Release();
  42. m_GraphicsBuffer = null;
  43. }
  44. internal void Reset()
  45. {
  46. unsafe { UnsafeUtility.MemClear(m_Markers.GetUnsafePtr(), UnsafeUtility.SizeOf<int>() * LightBuffer.kBatchMax); }
  47. unsafe { UnsafeUtility.MemClear(m_NativeBuffer.GetUnsafePtr(), UnsafeUtility.SizeOf<PerLight2D>() * LightBuffer.kMax); }
  48. }
  49. }
  50. // The idea is to avoid CPU cost when rendering meshes with the same shader (Consider this a light-weight SRP batcher). To identify the Mesh instance ID in the Light Buffer we utilize a Slot Index
  51. // identified from the Blue Channel of the Vertex Colors (Solely used for this purpose). This can batch a maximum of kLightMod meshes in best-case scenario. Simple but no optizations have been added yet
  52. internal class LightBatch
  53. {
  54. static readonly ProfilingSampler profilingDrawBatched = new ProfilingSampler("Light2D Batcher");
  55. static readonly int k_BufferOffset = Shader.PropertyToID("_BatchBufferOffset");
  56. static int sBatchIndexCounter = 0; // For LightMesh asset conditioning to facilitate batching.
  57. private static int batchLightMod => LightBuffer.kLightMod;
  58. private static float batchRunningIndex => (sBatchIndexCounter++) % LightBuffer.kLightMod / (float)LightBuffer.kLightMod;
  59. // Should be in Sync with USE_STRUCTURED_BUFFER_FOR_LIGHT2D_DATA
  60. public static bool isBatchingSupported => false;
  61. private int[] subsets = new int[LightBuffer.kMax];
  62. private Mesh[] lightMeshes = new Mesh[LightBuffer.kMax];
  63. private Matrix4x4[] matrices = new Matrix4x4[LightBuffer.kMax];
  64. private LightBuffer[] lightBuffer = new LightBuffer[LightBuffer.kCount];
  65. private Light2D cachedLight;
  66. private Material cachedMaterial;
  67. private int hashCode = 0;
  68. private int lightCount = 0;
  69. private int maxIndex = 0;
  70. private int batchCount = 0;
  71. private int activeCount = 0;
  72. internal NativeArray<PerLight2D> nativeBuffer
  73. {
  74. get
  75. {
  76. if (null == lightBuffer[activeCount])
  77. lightBuffer[activeCount] = new LightBuffer();
  78. return lightBuffer[activeCount].nativeBuffer;
  79. }
  80. }
  81. internal GraphicsBuffer graphicsBuffer
  82. {
  83. get
  84. {
  85. if (null == lightBuffer[activeCount])
  86. lightBuffer[activeCount] = new LightBuffer();
  87. return lightBuffer[activeCount].graphicsBuffer;
  88. }
  89. }
  90. internal NativeArray<int> lightMarker
  91. {
  92. get
  93. {
  94. if (null == lightBuffer[activeCount])
  95. lightBuffer[activeCount] = new LightBuffer();
  96. return lightBuffer[activeCount].lightMarkers;
  97. }
  98. }
  99. internal PerLight2D GetLight(int index) => nativeBuffer[index];
  100. internal static int batchSlotIndex => (int)(batchRunningIndex * LightBuffer.kLightMod);
  101. #if UNITY_EDITOR
  102. static bool kRegisterCallback = false;
  103. #endif
  104. internal void SetLight(int index, PerLight2D light)
  105. {
  106. var buffer = nativeBuffer;
  107. buffer[index] = light;
  108. }
  109. internal static float GetBatchColor()
  110. {
  111. return (float)batchSlotIndex / (float)batchLightMod;
  112. }
  113. internal static int GetBatchSlotIndex(float channelColor)
  114. {
  115. return (int)(channelColor * LightBuffer.kLightMod);
  116. }
  117. static int Hash(Light2D light, Material material)
  118. {
  119. unchecked
  120. {
  121. int _hashCode = (int)2166136261;
  122. _hashCode = _hashCode * 16777619 ^ material.GetHashCode();
  123. _hashCode = _hashCode * 16777619 ^ (light.lightCookieSprite == null ? 0 : light.lightCookieSprite.GetHashCode());
  124. return _hashCode;
  125. }
  126. }
  127. void Validate()
  128. {
  129. #if UNITY_EDITOR
  130. if (!kRegisterCallback)
  131. UnityEditor.AssemblyReloadEvents.beforeAssemblyReload += OnAssemblyReload;
  132. kRegisterCallback = true;
  133. #endif
  134. }
  135. void OnAssemblyReload()
  136. {
  137. for (int i = 0; i < LightBuffer.kCount; ++i)
  138. lightBuffer[activeCount].Release();
  139. }
  140. void ResetInternals()
  141. {
  142. for (int i = 0; i < LightBuffer.kCount; ++i)
  143. if (null != lightBuffer[i])
  144. lightBuffer[i].Reset();
  145. }
  146. void SetBuffer()
  147. {
  148. Validate();
  149. graphicsBuffer.SetData(nativeBuffer, lightCount, lightCount, math.min(LightBuffer.kBatchMax, LightBuffer.kMax - lightCount));
  150. }
  151. internal int SlotIndex(int x)
  152. {
  153. return lightCount + x;
  154. }
  155. internal void Reset()
  156. {
  157. if (isBatchingSupported)
  158. {
  159. maxIndex = 0;
  160. hashCode = 0;
  161. batchCount = 0;
  162. lightCount = 0;
  163. activeCount = 0;
  164. Shader.SetGlobalBuffer("_Light2DBuffer", graphicsBuffer);
  165. }
  166. }
  167. internal bool CanBatch(Light2D light, Material material, int index, out int lightHash)
  168. {
  169. lightHash = Hash(light, material);
  170. hashCode = (hashCode == 0) ? lightHash : hashCode;
  171. if (batchCount == 0)
  172. {
  173. hashCode = lightHash;
  174. }
  175. else if (hashCode != lightHash || SlotIndex(index) >= LightBuffer.kMax || lightMarker[index] == 1)
  176. {
  177. hashCode = lightHash;
  178. return false;
  179. }
  180. return true;
  181. }
  182. internal bool AddBatch(Light2D light, Material material, Matrix4x4 mat, Mesh mesh, int subset, int lightHash, int index)
  183. {
  184. Debug.Assert(lightHash == hashCode);
  185. cachedLight = light;
  186. cachedMaterial = material;
  187. matrices[batchCount] = mat;
  188. lightMeshes[batchCount] = mesh;
  189. subsets[batchCount] = subset;
  190. batchCount++;
  191. maxIndex = math.max(maxIndex, index);
  192. var lightMark = lightMarker;
  193. lightMark[index] = 1;
  194. return true;
  195. }
  196. internal void Flush(RasterCommandBuffer cmd)
  197. {
  198. if (batchCount > 0)
  199. {
  200. using (new ProfilingScope(cmd, profilingDrawBatched))
  201. {
  202. SetBuffer();
  203. cmd.SetGlobalInt(k_BufferOffset, lightCount);
  204. cmd.DrawMultipleMeshes(matrices, lightMeshes, subsets, batchCount, cachedMaterial, -1, null);
  205. }
  206. lightCount = lightCount + maxIndex + 1;
  207. }
  208. for (int i = 0; i < batchCount; ++i)
  209. lightMeshes[i] = null;
  210. ResetInternals();
  211. batchCount = 0;
  212. maxIndex = 0;
  213. }
  214. }
  215. }