Mirror of Svelto.ECS because we're a fan of it
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.

SveltoOnDOTSEntitiesSubmissionGroup.cs 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #if UNITY_ECS
  2. using System;
  3. using System.Collections.Generic;
  4. using Svelto.Common;
  5. using Svelto.DataStructures;
  6. using Svelto.ECS.Native;
  7. using Svelto.ECS.Schedulers;
  8. using Unity.Entities;
  9. using Unity.Jobs;
  10. using Allocator = Unity.Collections.Allocator;
  11. namespace Svelto.ECS.SveltoOnDOTS
  12. {
  13. /// <summary>
  14. /// SveltoDOTS ECSEntitiesSubmissionGroup expand the _submissionScheduler responsibility to integrate the
  15. /// submission of Svelto entities with the submission of DOTS ECS entities using EntityCommandBuffer.
  16. /// As there is just one submissionScheduler per enginesRoot, there should be only one SveltoDOTS
  17. /// ECSEntitiesSubmissionGroup
  18. /// per engines group. It's expected use is showed in the class SveltoOnDOTS ECSEnginesGroup which should be used
  19. /// instead of using this class directly.
  20. /// Groups DOTS ECS/Svelto SystemBase engines that creates DOTS ECS entities.
  21. /// Flow:
  22. /// Complete all the jobs used as input dependencies (this is a sync point)
  23. /// Create the new frame Command Buffer to use
  24. /// Svelto entities are submitted
  25. /// Svelto Add and remove callback are called
  26. /// ECB is injected in all the registered engines
  27. /// all the OnUpdate of the registered engines/systems are called
  28. /// the DOTS ECS command buffer is flushed
  29. /// all the DOTS ECS entities created that need Svelto information will be processed
  30. /// </summary>
  31. [DisableAutoCreation]
  32. public sealed partial class SveltoOnDOTSEntitiesSubmissionGroup : SystemBase, IQueryingEntitiesEngine,
  33. ISveltoOnDOTSSubmission
  34. {
  35. public SveltoOnDOTSEntitiesSubmissionGroup(SimpleEntitiesSubmissionScheduler submissionScheduler,
  36. EnginesRoot enginesRoot)
  37. {
  38. _submissionScheduler = submissionScheduler;
  39. _submissionEngines = new FasterList<SveltoOnDOTSHandleCreationEngine>();
  40. _cachedList = new List<DOTSEntityToSetup>();
  41. _sveltoOnDotsHandleLifeTimeEngines = new FasterList<ISveltoOnDOTSHandleLifeTimeEngine>();
  42. var defaultSveltoOnDotsHandleLifeTimeEngine = new SveltoOnDOTSHandleLifeTimeEngine<DOTSEntityComponent>();
  43. enginesRoot.AddEngine(defaultSveltoOnDotsHandleLifeTimeEngine);
  44. _sveltoOnDotsHandleLifeTimeEngines.Add(defaultSveltoOnDotsHandleLifeTimeEngine);
  45. }
  46. public EntitiesDB entitiesDB { get; set; }
  47. public void Ready() { }
  48. //Right, when you record a command outside of a job using the regular ECB, you don't pass it a sort key.
  49. //We instead use a constant for the main thread that is actually set to Int32.MaxValue. Where as the commands
  50. //that are recording from jobs with the ParallelWriter, get a lower value sort key from the job. Because we
  51. //playback the commands in order based on this sort key, the ParallelWriter commands end up happening before
  52. //the main thread commands. This is where your error is coming from because the Instantiate command happens at
  53. //the end because it's sort key is Int32.MaxValue.
  54. //We don't recommend mixing the main thread and ParallelWriter commands in a single ECB for this reason.
  55. public void SubmitEntities(JobHandle jobHandle)
  56. {
  57. if (_submissionScheduler.paused == true)
  58. return;
  59. using (var profiler = new PlatformProfiler("SveltoDOTSEntitiesSubmissionGroup"))
  60. {
  61. using (profiler.Sample("PreSubmissionPhase"))
  62. {
  63. PreSubmissionPhase(ref jobHandle, profiler);
  64. }
  65. //Submit Svelto Entities, calls Add/Remove/MoveTo that can be used by the IDOTS ECSSubmissionEngines
  66. _submissionScheduler.SubmitEntities();
  67. using (profiler.Sample("AfterSubmissionPhase"))
  68. {
  69. AfterSubmissionPhase(profiler);
  70. }
  71. }
  72. }
  73. public void Add(SveltoOnDOTSHandleCreationEngine engine)
  74. {
  75. // Console.LogDebug($"Add Submission Engine {engine} to the DOTS world {_ECBSystem.World.Name}");
  76. //this is temporary enabled because of engines that needs EntityManagers for the wrong reasons.
  77. _submissionEngines.Add(engine);
  78. engine.entityManager = EntityManager;
  79. engine.OnCreate();
  80. }
  81. public void Add(ISveltoOnDOTSHandleLifeTimeEngine engine)
  82. {
  83. // Console.LogDebug($"Add Submission Engine {engine} to the DOTS world {_ECBSystem.World.Name}");
  84. _sveltoOnDotsHandleLifeTimeEngines.Add(engine);
  85. }
  86. void PreSubmissionPhase(ref JobHandle jobHandle, PlatformProfiler profiler)
  87. {
  88. using (profiler.Sample("Complete All Pending Jobs")) jobHandle.Complete(); //sync-point
  89. _entityCommandBuffer = new EntityCommandBuffer((Allocator)Common.Allocator.TempJob);
  90. foreach (var system in _submissionEngines)
  91. system.entityCommandBuffer =
  92. new EntityCommandBufferForSvelto(_entityCommandBuffer, World.EntityManager);
  93. foreach (var system in _sveltoOnDotsHandleLifeTimeEngines)
  94. system.entityCommandBuffer =
  95. new EntityCommandBufferForSvelto(_entityCommandBuffer, World.EntityManager);
  96. }
  97. void AfterSubmissionPhase(PlatformProfiler profiler)
  98. {
  99. JobHandle combinedHandle = default;
  100. for (var i = 0; i < _submissionEngines.count; i++)
  101. {
  102. try
  103. {
  104. combinedHandle = JobHandle.CombineDependencies(combinedHandle, _submissionEngines[i].OnUpdate());
  105. }
  106. catch (Exception e)
  107. {
  108. Console.LogException(e, _submissionEngines[i].name);
  109. throw;
  110. }
  111. }
  112. using (profiler.Sample("Playback Command Buffer"))
  113. {
  114. _entityCommandBuffer.Playback(EntityManager);
  115. _entityCommandBuffer.Dispose();
  116. }
  117. using (profiler.Sample("ConvertPendingEntities"))
  118. ConvertPendingEntities(combinedHandle);
  119. }
  120. //Note: when this is called, the CommandBuffer is flushed so the not temporary DOTS entity ID will be used
  121. void ConvertPendingEntities(JobHandle combinedHandle)
  122. {
  123. var entityCommandBuffer = new EntityCommandBuffer((Allocator)Common.Allocator.TempJob);
  124. var cmd = entityCommandBuffer.AsParallelWriter();
  125. _cachedList.Clear();
  126. //note with DOTS 0.17 unfortunately this allocates a lot :(
  127. EntityManager.GetAllUniqueSharedComponentData(_cachedList);
  128. Dependency = JobHandle.CombineDependencies(Dependency, combinedHandle);
  129. for (int i = 0; i < _cachedList.Count; i++)
  130. {
  131. var dotsEntityToSetup = _cachedList[i];
  132. if (dotsEntityToSetup.@group == ExclusiveGroupStruct.Invalid) continue;
  133. var mapper = entitiesDB.QueryNativeMappedEntities<DOTSEntityComponent>(dotsEntityToSetup.@group);
  134. //Note: for some reason GetAllUniqueSharedComponentData returns DOTSEntityToSetup with valid values
  135. //that are not used anymore by any entity. Something to keep an eye on if fixed on future versions
  136. //of DOTS
  137. Entities.ForEach((Entity entity, int entityInQueryIndex, in DOTSSveltoEGID egid) =>
  138. {
  139. mapper.Entity(egid.egid.entityID).dotsEntity = entity;
  140. cmd.RemoveComponent<DOTSEntityToSetup>(entityInQueryIndex, entity);
  141. }).WithSharedComponentFilter(dotsEntityToSetup).ScheduleParallel();
  142. }
  143. Dependency.Complete();
  144. entityCommandBuffer.Playback(EntityManager);
  145. entityCommandBuffer.Dispose();
  146. }
  147. protected override void OnCreate()
  148. {
  149. }
  150. protected override void OnUpdate()
  151. {
  152. throw new NotSupportedException("if this is called something broke the original design");
  153. }
  154. readonly FasterList<SveltoOnDOTSHandleCreationEngine> _submissionEngines;
  155. readonly FasterList<ISveltoOnDOTSHandleLifeTimeEngine> _sveltoOnDotsHandleLifeTimeEngines;
  156. readonly SimpleEntitiesSubmissionScheduler _submissionScheduler;
  157. readonly List<DOTSEntityToSetup> _cachedList;
  158. EntityCommandBuffer _entityCommandBuffer;
  159. }
  160. }
  161. #endif