暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GPUResidentDrawer.cs 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. #define GPU_RESIDENT_DRAWER_ALLOW_FORCE_ON
  2. using System;
  3. using System.Collections.Generic;
  4. using Unity.Collections;
  5. using UnityEngine.Assertions;
  6. using UnityEngine.LowLevel;
  7. using UnityEngine.PlayerLoop;
  8. using UnityEngine.Profiling;
  9. using UnityEngine.SceneManagement;
  10. using static UnityEngine.ObjectDispatcher;
  11. using Unity.Jobs;
  12. using static UnityEngine.Rendering.RenderersParameters;
  13. using Unity.Jobs.LowLevel.Unsafe;
  14. using UnityEngine.Rendering.RenderGraphModule;
  15. #if UNITY_EDITOR
  16. using UnityEditor;
  17. using UnityEditor.Rendering;
  18. #endif
  19. namespace UnityEngine.Rendering
  20. {
  21. /// <summary>
  22. /// Static utility class for updating data post cull in begin camera rendering
  23. /// </summary>
  24. public partial class GPUResidentDrawer
  25. {
  26. internal static GPUResidentDrawer instance { get => s_Instance; }
  27. private static GPUResidentDrawer s_Instance = null;
  28. ////////////////////////////////////////
  29. // Public API for rendering pipelines //
  30. ////////////////////////////////////////
  31. #region Public API
  32. /// <summary>
  33. /// Utility function to test if instance occlusion culling is enabled
  34. /// </summary>
  35. /// <returns>True if instance occlusion culling is enabled</returns>
  36. public static bool IsInstanceOcclusionCullingEnabled()
  37. {
  38. if (s_Instance == null)
  39. return false;
  40. if (s_Instance.settings.mode != GPUResidentDrawerMode.InstancedDrawing)
  41. return false;
  42. if (s_Instance.settings.enableOcclusionCulling)
  43. return true;
  44. return false;
  45. }
  46. /// <summary>
  47. /// Utility function for updating data post cull in begin camera rendering
  48. /// </summary>
  49. /// <param name="context">
  50. /// Context containing the data to be set
  51. /// </param>
  52. public static void PostCullBeginCameraRendering(RenderRequestBatcherContext context)
  53. {
  54. s_Instance?.batcher.PostCullBeginCameraRendering(context);
  55. }
  56. /// <summary>
  57. /// Utility function for updating probe data after global ambient probe is set up
  58. /// </summary>
  59. public static void OnSetupAmbientProbe()
  60. {
  61. s_Instance?.batcher.OnSetupAmbientProbe();
  62. }
  63. /// <summary>
  64. /// Utility function to run an occlusion test in compute to update indirect draws.
  65. /// This function will dispatch compute shaders to run the given occlusion test and
  66. /// update all indirect draws in the culling output for the given view.
  67. /// The next time a renderer list that uses this culling output is drawn, these
  68. /// indirect draw commands will contain only the instances that passed the given
  69. /// occlusion test.
  70. /// </summary>
  71. /// <param name="renderGraph">Render graph that will have a compute pass added.</param>
  72. /// <param name="settings">The view to update and occlusion test to use.</param>
  73. /// <param name="subviewOcclusionTests">Specifies the occluder subviews to use with each culling split index.</param>
  74. public static void InstanceOcclusionTest(RenderGraph renderGraph, in OcclusionCullingSettings settings, ReadOnlySpan<SubviewOcclusionTest> subviewOcclusionTests)
  75. {
  76. s_Instance?.batcher.InstanceOcclusionTest(renderGraph, settings, subviewOcclusionTests);
  77. }
  78. /// <summary>
  79. /// Utility function used to update occluders using a depth buffer.
  80. /// This function will dispatch compute shaders to read the given depth buffer
  81. /// and build a mip pyramid of closest depths for use during occlusion culling.
  82. /// The next time an occlusion test is issed for this view, instances will be
  83. /// tested against the updated occluders.
  84. /// </summary>
  85. /// <param name="renderGraph">Render graph that will have a compute pass added.</param>
  86. /// <param name="occluderParameters">Parameter to specify the view and depth buffer to read.</param>
  87. /// <param name="occluderSubviewUpdates">Specifies which occluder subviews to update from slices of the input depth buffer.</param>
  88. public static void UpdateInstanceOccluders(RenderGraph renderGraph, in OccluderParameters occluderParameters, ReadOnlySpan<OccluderSubviewUpdate> occluderSubviewUpdates)
  89. {
  90. s_Instance?.batcher.UpdateInstanceOccluders(renderGraph, occluderParameters, occluderSubviewUpdates);
  91. }
  92. /// <summary>
  93. /// Enable or disable GPUResidentDrawer based on the project settings.
  94. /// We call this every frame because GPUResidentDrawer can be enabled/disabled by the settings outside the render pipeline asset.
  95. /// </summary>
  96. public static void ReinitializeIfNeeded()
  97. {
  98. #if UNITY_EDITOR
  99. if (!IsForcedOnViaCommandLine() && (IsProjectSupported() != IsEnabled()))
  100. {
  101. Reinitialize();
  102. }
  103. #endif
  104. }
  105. #endregion
  106. #region Public Debug API
  107. /// <summary>
  108. /// Utility function to render an occlusion test heatmap debug overlay.
  109. /// </summary>
  110. /// <param name="renderGraph">Render graph that will have a compute pass added.</param>
  111. /// <param name="debugSettings">The rendering debugger debug settings to read parameters from.</param>
  112. /// <param name="viewInstanceID">The instance ID of the camera using a GPU occlusion test.</param>
  113. /// <param name="colorBuffer">The color buffer to render the overlay on.</param>
  114. public static void RenderDebugOcclusionTestOverlay(RenderGraph renderGraph, DebugDisplayGPUResidentDrawer debugSettings, int viewInstanceID, TextureHandle colorBuffer)
  115. {
  116. s_Instance?.batcher.occlusionCullingCommon.RenderDebugOcclusionTestOverlay(renderGraph, debugSettings, viewInstanceID, colorBuffer);
  117. }
  118. /// <summary>
  119. /// Utility function visualise the occluder pyramid in a debug overlay.
  120. /// </summary>
  121. /// <param name="renderGraph">Render graph that will have a compute pass added.</param>
  122. /// <param name="debugSettings">The rendering debugger debug settings to read parameters from.</param>
  123. /// <param name="screenPos">The screen position to render the overlay at.</param>
  124. /// <param name="maxHeight">The maximum screen height of the overlay.</param>
  125. /// <param name="colorBuffer">The color buffer to render the overlay on.</param>
  126. public static void RenderDebugOccluderOverlay(RenderGraph renderGraph, DebugDisplayGPUResidentDrawer debugSettings, Vector2 screenPos, float maxHeight, TextureHandle colorBuffer)
  127. {
  128. s_Instance?.batcher.occlusionCullingCommon.RenderDebugOccluderOverlay(renderGraph, debugSettings, screenPos, maxHeight, colorBuffer);
  129. }
  130. #endregion
  131. internal static DebugRendererBatcherStats GetDebugStats()
  132. {
  133. return s_Instance?.m_BatchersContext.debugStats;
  134. }
  135. private void InsertIntoPlayerLoop()
  136. {
  137. var rootLoop = LowLevel.PlayerLoop.GetCurrentPlayerLoop();
  138. bool isAdded = false;
  139. for (var i = 0; i < rootLoop.subSystemList.Length; i++)
  140. {
  141. var subSystem = rootLoop.subSystemList[i];
  142. // We have to update inside the PostLateUpdate systems, because we have to be able to get previous matrices from renderers.
  143. // Previous matrices are updated by renderer managers on UpdateAllRenderers which is part of PostLateUpdate.
  144. if (!isAdded && subSystem.type == typeof(PostLateUpdate))
  145. {
  146. var subSubSystems = new List<PlayerLoopSystem>();
  147. foreach (var subSubSystem in subSystem.subSystemList)
  148. {
  149. if (subSubSystem.type == typeof(PostLateUpdate.FinishFrameRendering))
  150. {
  151. PlayerLoopSystem s = default;
  152. s.updateDelegate += PostPostLateUpdateStatic;
  153. s.type = GetType();
  154. subSubSystems.Add(s);
  155. isAdded = true;
  156. }
  157. subSubSystems.Add(subSubSystem);
  158. }
  159. subSystem.subSystemList = subSubSystems.ToArray();
  160. rootLoop.subSystemList[i] = subSystem;
  161. }
  162. }
  163. LowLevel.PlayerLoop.SetPlayerLoop(rootLoop);
  164. }
  165. private void RemoveFromPlayerLoop()
  166. {
  167. var rootLoop = LowLevel.PlayerLoop.GetCurrentPlayerLoop();
  168. for (int i = 0; i < rootLoop.subSystemList.Length; i++)
  169. {
  170. var subsystem = rootLoop.subSystemList[i];
  171. if (subsystem.type != typeof(PostLateUpdate))
  172. continue;
  173. var newList = new List<PlayerLoopSystem>();
  174. foreach (var subSubSystem in subsystem.subSystemList)
  175. {
  176. if (subSubSystem.type != GetType())
  177. newList.Add(subSubSystem);
  178. }
  179. subsystem.subSystemList = newList.ToArray();
  180. rootLoop.subSystemList[i] = subsystem;
  181. }
  182. LowLevel.PlayerLoop.SetPlayerLoop(rootLoop);
  183. }
  184. #if UNITY_EDITOR
  185. private static void OnAssemblyReload()
  186. {
  187. if (s_Instance is not null)
  188. s_Instance.Dispose();
  189. }
  190. #endif
  191. internal static bool IsEnabled()
  192. {
  193. return s_Instance is not null;
  194. }
  195. internal static GPUResidentDrawerSettings GetGlobalSettingsFromRPAsset()
  196. {
  197. var renderPipelineAsset = GraphicsSettings.currentRenderPipeline;
  198. if (renderPipelineAsset is not IGPUResidentRenderPipeline mbAsset)
  199. return new GPUResidentDrawerSettings();
  200. var settings = mbAsset.gpuResidentDrawerSettings;
  201. if (IsForcedOnViaCommandLine())
  202. settings.mode = GPUResidentDrawerMode.InstancedDrawing;
  203. if (IsOcclusionForcedOnViaCommandLine())
  204. settings.enableOcclusionCulling = true;
  205. return settings;
  206. }
  207. /// <summary>
  208. /// Is GRD forced on via the command line via -force-gpuresidentdrawer. Editor only.
  209. /// </summary>
  210. /// <returns>true if forced on</returns>
  211. private static bool IsForcedOnViaCommandLine()
  212. {
  213. #if UNITY_EDITOR
  214. return s_IsForcedOnViaCommandLine;
  215. #else
  216. return false;
  217. #endif
  218. }
  219. /// <summary>
  220. /// Is occlusion culling forced on via the command line via -force-gpuocclusion. Editor only.
  221. /// </summary>
  222. /// <returns>true if forced on</returns>
  223. private static bool IsOcclusionForcedOnViaCommandLine()
  224. {
  225. #if UNITY_EDITOR
  226. return s_IsOcclusionForcedOnViaCommandLine;
  227. #else
  228. return false;
  229. #endif
  230. }
  231. internal static void Reinitialize()
  232. {
  233. var settings = GetGlobalSettingsFromRPAsset();
  234. // When compiling in the editor, we include a try catch block around our initialization logic to avoid leaving the editor window in a broken state if something goes wrong.
  235. // We can probably remove this in the future once the edit mode functionality stabilizes, but for now it's safest to have a fallback.
  236. #if UNITY_EDITOR
  237. try
  238. #endif
  239. {
  240. Recreate(settings);
  241. }
  242. #if UNITY_EDITOR
  243. catch (Exception exception)
  244. {
  245. Debug.LogError($"The GPU Resident Drawer encountered an error during initialization. The standard SRP path will be used instead. [Error: {exception.Message}]");
  246. Debug.LogError($"GPU Resident drawer stack trace: {exception.StackTrace}");
  247. CleanUp();
  248. }
  249. #endif
  250. }
  251. private static void CleanUp()
  252. {
  253. if (s_Instance == null)
  254. return;
  255. s_Instance.Dispose();
  256. s_Instance = null;
  257. }
  258. private static void Recreate(GPUResidentDrawerSettings settings)
  259. {
  260. CleanUp();
  261. if (IsGPUResidentDrawerSupportedBySRP(settings, out var message, out var severity))
  262. {
  263. s_Instance = new GPUResidentDrawer(settings, 4096, 0);
  264. }
  265. else
  266. {
  267. LogMessage(message, severity);
  268. }
  269. }
  270. internal GPUResidentBatcher batcher { get => m_Batcher; }
  271. internal GPUResidentDrawerSettings settings { get => m_Settings; }
  272. private GPUResidentDrawerSettings m_Settings;
  273. private GPUDrivenProcessor m_GPUDrivenProcessor = null;
  274. private RenderersBatchersContext m_BatchersContext = null;
  275. private GPUResidentBatcher m_Batcher = null;
  276. private ObjectDispatcher m_Dispatcher;
  277. private MeshRendererDrawer m_MeshRendererDrawer;
  278. #if UNITY_EDITOR
  279. private static readonly bool s_IsForcedOnViaCommandLine;
  280. private static readonly bool s_IsOcclusionForcedOnViaCommandLine;
  281. private NativeList<int> m_FrameCameraIDs;
  282. private bool m_FrameUpdateNeeded = false;
  283. private bool m_SelectionChanged;
  284. static GPUResidentDrawer()
  285. {
  286. Lightmapping.bakeCompleted += Reinitialize;
  287. #if GPU_RESIDENT_DRAWER_ALLOW_FORCE_ON
  288. foreach (var arg in Environment.GetCommandLineArgs())
  289. {
  290. if (arg.Equals("-force-gpuresidentdrawer", StringComparison.InvariantCultureIgnoreCase))
  291. {
  292. Debug.Log("GPU Resident Drawer forced on via commandline");
  293. s_IsForcedOnViaCommandLine = true;
  294. }
  295. if (arg.Equals("-force-gpuocclusion", StringComparison.InvariantCultureIgnoreCase))
  296. {
  297. Debug.Log("GPU occlusion culling forced on via commandline");
  298. s_IsOcclusionForcedOnViaCommandLine = true;
  299. }
  300. }
  301. #endif
  302. }
  303. #endif
  304. private GPUResidentDrawer(GPUResidentDrawerSettings settings, int maxInstanceCount, int maxTreeInstanceCount)
  305. {
  306. var resources = GraphicsSettings.GetRenderPipelineSettings<GPUResidentDrawerResources>();
  307. var renderPipelineAsset = GraphicsSettings.currentRenderPipeline;
  308. var mbAsset = renderPipelineAsset as IGPUResidentRenderPipeline;
  309. Debug.Assert(mbAsset != null, "No compatible Render Pipeline found");
  310. Assert.IsFalse(settings.mode == GPUResidentDrawerMode.Disabled);
  311. m_Settings = settings;
  312. var rbcDesc = RenderersBatchersContextDesc.NewDefault();
  313. rbcDesc.instanceNumInfo = new InstanceNumInfo(meshRendererNum: maxInstanceCount, speedTreeNum: maxTreeInstanceCount);
  314. rbcDesc.supportDitheringCrossFade = settings.supportDitheringCrossFade;
  315. rbcDesc.smallMeshScreenPercentage = settings.smallMeshScreenPercentage;
  316. rbcDesc.enableBoundingSpheresInstanceData = settings.enableOcclusionCulling;
  317. rbcDesc.enableCullerDebugStats = true; // for now, always allow the possibility of reading counter stats from the cullers.
  318. var instanceCullingBatcherDesc = InstanceCullingBatcherDesc.NewDefault();
  319. #if UNITY_EDITOR
  320. instanceCullingBatcherDesc.brgPicking = settings.pickingShader;
  321. instanceCullingBatcherDesc.brgLoading = settings.loadingShader;
  322. instanceCullingBatcherDesc.brgError = settings.errorShader;
  323. #endif
  324. m_GPUDrivenProcessor = new GPUDrivenProcessor();
  325. m_BatchersContext = new RenderersBatchersContext(rbcDesc, m_GPUDrivenProcessor, resources);
  326. m_Batcher = new GPUResidentBatcher(
  327. m_BatchersContext,
  328. instanceCullingBatcherDesc,
  329. m_GPUDrivenProcessor);
  330. m_Dispatcher = new ObjectDispatcher();
  331. m_Dispatcher.EnableTypeTracking<LODGroup>(TypeTrackingFlags.SceneObjects);
  332. m_Dispatcher.EnableTypeTracking<Mesh>();
  333. m_Dispatcher.EnableTypeTracking<Material>();
  334. m_Dispatcher.EnableTransformTracking<LODGroup>(TransformTrackingType.GlobalTRS);
  335. m_MeshRendererDrawer = new MeshRendererDrawer(this, m_Dispatcher);
  336. #if UNITY_EDITOR
  337. AssemblyReloadEvents.beforeAssemblyReload += OnAssemblyReload;
  338. m_FrameCameraIDs = new NativeList<int>(1, Allocator.Persistent);
  339. #endif
  340. SceneManager.sceneLoaded += OnSceneLoaded;
  341. RenderPipelineManager.beginContextRendering += OnBeginContextRendering;
  342. RenderPipelineManager.endContextRendering += OnEndContextRendering;
  343. RenderPipelineManager.beginCameraRendering += OnBeginCameraRendering;
  344. RenderPipelineManager.endCameraRendering += OnEndCameraRendering;
  345. #if UNITY_EDITOR
  346. Selection.selectionChanged += OnSelectionChanged;
  347. #endif
  348. // GPU Resident Drawer only supports legacy lightmap binding.
  349. // Accordingly, we set the keyword globally across all shaders.
  350. const string useLegacyLightmapsKeyword = "USE_LEGACY_LIGHTMAPS";
  351. Shader.EnableKeyword(useLegacyLightmapsKeyword);
  352. InsertIntoPlayerLoop();
  353. }
  354. private void Dispose()
  355. {
  356. Assert.IsNotNull(s_Instance);
  357. #if UNITY_EDITOR
  358. AssemblyReloadEvents.beforeAssemblyReload -= OnAssemblyReload;
  359. if (m_FrameCameraIDs.IsCreated)
  360. m_FrameCameraIDs.Dispose();
  361. #endif
  362. SceneManager.sceneLoaded -= OnSceneLoaded;
  363. RenderPipelineManager.beginContextRendering -= OnBeginContextRendering;
  364. RenderPipelineManager.endContextRendering -= OnEndContextRendering;
  365. RenderPipelineManager.beginCameraRendering -= OnBeginCameraRendering;
  366. RenderPipelineManager.endCameraRendering -= OnEndCameraRendering;
  367. #if UNITY_EDITOR
  368. Selection.selectionChanged -= OnSelectionChanged;
  369. #endif
  370. RemoveFromPlayerLoop();
  371. const string useLegacyLightmapsKeyword = "USE_LEGACY_LIGHTMAPS";
  372. Shader.DisableKeyword(useLegacyLightmapsKeyword);
  373. m_MeshRendererDrawer.Dispose();
  374. m_MeshRendererDrawer = null;
  375. m_Dispatcher.Dispose();
  376. m_Dispatcher = null;
  377. s_Instance = null;
  378. m_Batcher?.Dispose();
  379. m_BatchersContext.Dispose();
  380. m_GPUDrivenProcessor.Dispose();
  381. }
  382. private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
  383. {
  384. // Loaded scene might contain light probes that would affect existing objects. Hence we have to update all probes data.
  385. if(mode == LoadSceneMode.Additive)
  386. m_BatchersContext.UpdateAmbientProbeAndGpuBuffer(forceUpdate: true);
  387. }
  388. private static void PostPostLateUpdateStatic()
  389. {
  390. s_Instance?.PostPostLateUpdate();
  391. }
  392. private void OnBeginContextRendering(ScriptableRenderContext context, List<Camera> cameras)
  393. {
  394. if (s_Instance is null)
  395. return;
  396. #if UNITY_EDITOR
  397. EditorFrameUpdate(cameras);
  398. #endif
  399. m_Batcher.OnBeginContextRendering();
  400. }
  401. #if UNITY_EDITOR
  402. // If running in the editor the player loop might not run
  403. // In order to still have a single frame update we keep track of the camera ids
  404. // A frame update happens in case the first camera is rendered again
  405. private void EditorFrameUpdate(List<Camera> cameras)
  406. {
  407. bool newFrame = false;
  408. foreach (Camera camera in cameras)
  409. {
  410. int instanceID = camera.GetInstanceID();
  411. if (m_FrameCameraIDs.Length == 0 || m_FrameCameraIDs.Contains(instanceID))
  412. {
  413. newFrame = true;
  414. m_FrameCameraIDs.Clear();
  415. }
  416. m_FrameCameraIDs.Add(instanceID);
  417. }
  418. if (newFrame)
  419. {
  420. if (m_FrameUpdateNeeded)
  421. m_Batcher.UpdateFrame();
  422. else
  423. m_FrameUpdateNeeded = true;
  424. }
  425. ProcessSelection();
  426. }
  427. private void OnSelectionChanged()
  428. {
  429. m_SelectionChanged = true;
  430. }
  431. private void ProcessSelection()
  432. {
  433. if(!m_SelectionChanged)
  434. return;
  435. m_SelectionChanged = false;
  436. Object[] renderers = Selection.GetFiltered(typeof(MeshRenderer), SelectionMode.Deep);
  437. var rendererIDs = new NativeArray<int>(renderers.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
  438. for (int i = 0; i < renderers.Length; ++i)
  439. rendererIDs[i] = renderers[i] ? renderers[i].GetInstanceID() : 0;
  440. m_Batcher.UpdateSelectedRenderers(rendererIDs);
  441. rendererIDs.Dispose();
  442. }
  443. #endif
  444. private void OnEndContextRendering(ScriptableRenderContext context, List<Camera> cameras)
  445. {
  446. if (s_Instance is null)
  447. return;
  448. m_Batcher.OnEndContextRendering();
  449. }
  450. private void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
  451. {
  452. m_Batcher.OnBeginCameraRendering(camera);
  453. }
  454. private void OnEndCameraRendering(ScriptableRenderContext context, Camera camera)
  455. {
  456. m_Batcher.OnEndCameraRendering(camera);
  457. }
  458. private void PostPostLateUpdate()
  459. {
  460. m_BatchersContext.UpdateAmbientProbeAndGpuBuffer(forceUpdate: false);
  461. Profiler.BeginSample("GPUResidentDrawer.DispatchChanges");
  462. var lodGroupTransformData = m_Dispatcher.GetTransformChangesAndClear<LODGroup>(TransformTrackingType.GlobalTRS, Allocator.TempJob);
  463. var lodGroupData = m_Dispatcher.GetTypeChangesAndClear<LODGroup>(Allocator.TempJob, noScriptingArray: true);
  464. var meshDataSorted = m_Dispatcher.GetTypeChangesAndClear<Mesh>(Allocator.TempJob, sortByInstanceID: true, noScriptingArray: true);
  465. var materialData = m_Dispatcher.GetTypeChangesAndClear<Material>(Allocator.TempJob, noScriptingArray: true);
  466. Profiler.EndSample();
  467. Profiler.BeginSample("GPUResidentDrawer.ProcessMaterials");
  468. ProcessMaterials(materialData.destroyedID);
  469. Profiler.EndSample();
  470. Profiler.BeginSample("GPUResidentDrawer.ProcessMeshes");
  471. ProcessMeshes(meshDataSorted.destroyedID);
  472. Profiler.EndSample();
  473. Profiler.BeginSample("GPUResidentDrawer.ProcessLODGroups");
  474. ProcessLODGroups(lodGroupData.changedID, lodGroupData.destroyedID, lodGroupTransformData.transformedID);
  475. Profiler.EndSample();
  476. lodGroupTransformData.Dispose();
  477. lodGroupData.Dispose();
  478. meshDataSorted.Dispose();
  479. materialData.Dispose();
  480. Profiler.BeginSample("GPUResidentDrawer.ProcessDraws");
  481. m_MeshRendererDrawer.ProcessDraws();
  482. // Add more drawers here ...
  483. Profiler.EndSample();
  484. m_BatchersContext.UpdateInstanceMotions();
  485. m_Batcher.UpdateFrame();
  486. #if UNITY_EDITOR
  487. m_FrameUpdateNeeded = false;
  488. #endif
  489. }
  490. private void ProcessMaterials(NativeArray<int> destroyedID)
  491. {
  492. if(destroyedID.Length == 0)
  493. return;
  494. m_Batcher.DestroyMaterials(destroyedID);
  495. }
  496. private void ProcessMeshes(NativeArray<int> destroyedID)
  497. {
  498. if (destroyedID.Length == 0)
  499. return;
  500. var destroyedMeshInstances = new NativeList<InstanceHandle>(Allocator.TempJob);
  501. ScheduleQueryMeshInstancesJob(destroyedID, destroyedMeshInstances).Complete();
  502. m_Batcher.DestroyInstances(destroyedMeshInstances.AsArray());
  503. destroyedMeshInstances.Dispose();
  504. //@ Some rendererGroupID will not be invalidated when their mesh changed. We will need to update Mesh bounds, probes etc. manually for them.
  505. m_Batcher.DestroyMeshes(destroyedID);
  506. }
  507. private void ProcessLODGroups(NativeArray<int> changedID, NativeArray<int> destroyed, NativeArray<int> transformedID)
  508. {
  509. m_BatchersContext.DestroyLODGroups(destroyed);
  510. m_BatchersContext.UpdateLODGroups(changedID);
  511. m_BatchersContext.TransformLODGroups(transformedID);
  512. }
  513. internal void ProcessRenderers(NativeArray<int> rendererGroupsID)
  514. {
  515. Profiler.BeginSample("GPUResidentDrawer.ProcessMeshRenderers");
  516. var changedInstances = new NativeArray<InstanceHandle>(rendererGroupsID.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
  517. ScheduleQueryRendererGroupInstancesJob(rendererGroupsID, changedInstances).Complete();
  518. m_Batcher.DestroyInstances(changedInstances);
  519. changedInstances.Dispose();
  520. m_Batcher.UpdateRenderers(rendererGroupsID);
  521. Profiler.EndSample();
  522. }
  523. internal void TransformInstances(NativeArray<InstanceHandle> instances, NativeArray<Matrix4x4> localToWorldMatrices)
  524. {
  525. Profiler.BeginSample("GPUResidentDrawer.TransformInstances");
  526. m_BatchersContext.UpdateInstanceTransforms(instances, localToWorldMatrices);
  527. Profiler.EndSample();
  528. }
  529. internal void FreeInstances(NativeArray<InstanceHandle> instances)
  530. {
  531. Profiler.BeginSample("GPUResidentDrawer.FreeInstances");
  532. m_Batcher.DestroyInstances(instances);
  533. m_BatchersContext.FreeInstances(instances);
  534. Profiler.EndSample();
  535. }
  536. internal void FreeRendererGroupInstances(NativeArray<int> rendererGroupIDs)
  537. {
  538. Profiler.BeginSample("GPUResidentDrawer.FreeRendererGroupInstances");
  539. m_Batcher.FreeRendererGroupInstances(rendererGroupIDs);
  540. Profiler.EndSample();
  541. }
  542. //@ Implement later...
  543. internal InstanceHandle AppendNewInstance(int rendererGroupID, in Matrix4x4 instanceTransform)
  544. {
  545. throw new NotImplementedException();
  546. }
  547. //@ Additionally we need to implement the way to tie external transforms (not Transform components) with instances.
  548. //@ So that an individual instance could be transformed externally and then updated in the drawer.
  549. internal JobHandle ScheduleQueryRendererGroupInstancesJob(NativeArray<int> rendererGroupIDs, NativeArray<InstanceHandle> instances)
  550. {
  551. return m_BatchersContext.ScheduleQueryRendererGroupInstancesJob(rendererGroupIDs, instances);
  552. }
  553. internal JobHandle ScheduleQueryRendererGroupInstancesJob(NativeArray<int> rendererGroupIDs, NativeList<InstanceHandle> instances)
  554. {
  555. return m_BatchersContext.ScheduleQueryRendererGroupInstancesJob(rendererGroupIDs, instances);
  556. }
  557. internal JobHandle ScheduleQueryRendererGroupInstancesJob(NativeArray<int> rendererGroupIDs, NativeArray<int> instancesOffset, NativeArray<int> instancesCount, NativeList<InstanceHandle> instances)
  558. {
  559. return m_BatchersContext.ScheduleQueryRendererGroupInstancesJob(rendererGroupIDs, instancesOffset, instancesCount, instances);
  560. }
  561. internal JobHandle ScheduleQueryMeshInstancesJob(NativeArray<int> sortedMeshIDs, NativeList<InstanceHandle> instances)
  562. {
  563. return m_BatchersContext.ScheduleQueryMeshInstancesJob(sortedMeshIDs, instances);
  564. }
  565. }
  566. }