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.

241 lines
8.9KB

  1. #if UNITY_ECS
  2. using System.Collections;
  3. using Svelto.Common;
  4. using Svelto.DataStructures;
  5. using Svelto.ECS.Native;
  6. using Svelto.ECS.Schedulers;
  7. using Unity.Entities;
  8. using Unity.Jobs;
  9. namespace Svelto.ECS.Extensions.Unity
  10. {
  11. /// <summary>
  12. /// Group of UECS/Svelto SystemBase engines that creates UECS entities.
  13. /// Svelto entities are submitted
  14. /// Svelto Add and remove callback are called
  15. /// OnUpdate of the systems are called
  16. /// finally the UECS command buffer is flushed
  17. /// Note: I cannot use Unity ComponentSystemGroups nor I can rely on the SystemBase Dependency field to
  18. /// solve external dependencies. External dependencies are tracked, but only linked to the UECS components operations
  19. /// With Dependency I cannot guarantee that an external container is used before previous jobs working on it are completed
  20. /// </summary>
  21. [DisableAutoCreation]
  22. public sealed class SveltoUECSEntitiesSubmissionGroup : SystemBase, IQueryingEntitiesEngine , IReactOnAddAndRemove<UECSEntityComponent>
  23. , IReactOnSwap<UECSEntityComponent>, ISveltoUECSSubmission
  24. {
  25. public SveltoUECSEntitiesSubmissionGroup(SimpleEntitiesSubmissionScheduler submissionScheduler)
  26. {
  27. _submissionScheduler = submissionScheduler;
  28. _engines = new FasterList<SubmissionEngine>();
  29. _afterSubmissionEngines = new FasterList<IUpdateAfterSubmission>();
  30. _beforeSubmissionEngines = new FasterList<IUpdateBeforeSubmission>();
  31. }
  32. protected override void OnCreate()
  33. {
  34. _ECBSystem = World.CreateSystem<SubmissionEntitiesCommandBufferSystem>();
  35. _entityQuery = GetEntityQuery(typeof(UpdateUECSEntityAfterSubmission));
  36. }
  37. public EntitiesDB entitiesDB { get; set; }
  38. public void Ready() { }
  39. public void Add(ref UECSEntityComponent entityComponent, EGID egid) { }
  40. public void Remove(ref UECSEntityComponent entityComponent, EGID egid)
  41. {
  42. _ECB.DestroyEntity(entityComponent.uecsEntity);
  43. }
  44. public void MovedTo(ref UECSEntityComponent entityComponent, ExclusiveGroupStruct previousGroup, EGID egid)
  45. {
  46. _ECB.SetSharedComponent(entityComponent.uecsEntity, new UECSSveltoGroupID(egid.groupID));
  47. }
  48. public void Add(SubmissionEngine engine)
  49. {
  50. Svelto.Console.LogDebug($"Add Engine {engine} to the UECS world {_ECBSystem.World.Name}");
  51. _ECBSystem.World.AddSystem(engine);
  52. if (engine is IUpdateAfterSubmission afterSubmission)
  53. _afterSubmissionEngines.Add(afterSubmission);
  54. if (engine is IUpdateBeforeSubmission beforeSubmission)
  55. _beforeSubmissionEngines.Add(beforeSubmission);
  56. _engines.Add(engine);
  57. }
  58. public void SubmitEntities(JobHandle jobHandle)
  59. {
  60. if (_submissionScheduler.paused)
  61. return;
  62. using (var profiler = new PlatformProfiler("SveltoUECSEntitiesSubmissionGroup - PreSubmissionPhase"))
  63. {
  64. PreSubmissionPhase(ref jobHandle, profiler);
  65. //Submit Svelto Entities, calls Add/Remove/MoveTo that can be used by the IUECSSubmissionEngines
  66. using (profiler.Sample("Submit svelto entities"))
  67. {
  68. _submissionScheduler.SubmitEntities();
  69. }
  70. AfterSubmissionPhase(profiler);
  71. }
  72. }
  73. public IEnumerator SubmitEntitiesAsync(JobHandle jobHandle, uint maxEntities)
  74. {
  75. if (_submissionScheduler.paused)
  76. yield break;
  77. using (var profiler = new PlatformProfiler("SveltoUECSEntitiesSubmissionGroup - PreSubmissionPhase"))
  78. {
  79. PreSubmissionPhase(ref jobHandle, profiler);
  80. var submitEntitiesAsync = _submissionScheduler.SubmitEntitiesAsync(maxEntities);
  81. //Submit Svelto Entities, calls Add/Remove/MoveTo that can be used by the IUECSSubmissionEngines
  82. while (true)
  83. {
  84. using (profiler.Sample("Submit svelto entities async"))
  85. {
  86. submitEntitiesAsync.MoveNext();
  87. }
  88. if (submitEntitiesAsync.Current == true)
  89. {
  90. using (profiler.Yield())
  91. yield return null;
  92. }
  93. else
  94. break;
  95. }
  96. AfterSubmissionPhase(profiler);
  97. }
  98. }
  99. void PreSubmissionPhase(ref JobHandle jobHandle, PlatformProfiler profiler)
  100. {
  101. JobHandle BeforeECBFlushEngines()
  102. {
  103. JobHandle jobHandle = default;
  104. //execute submission engines and complete jobs because of this I don't need to do _ECBSystem.AddJobHandleForProducer(Dependency);
  105. for (var index = 0; index < _beforeSubmissionEngines.count; index++)
  106. {
  107. ref var engine = ref _beforeSubmissionEngines[index];
  108. using (profiler.Sample(engine.name))
  109. {
  110. jobHandle = JobHandle.CombineDependencies(jobHandle, engine.BeforeSubmissionUpdate(jobHandle));
  111. }
  112. }
  113. return jobHandle;
  114. }
  115. using (profiler.Sample("Complete All Pending Jobs"))
  116. {
  117. jobHandle.Complete();
  118. }
  119. //prepare the entity command buffer to be used by the registered engines
  120. var entityCommandBuffer = _ECBSystem.CreateCommandBuffer();
  121. foreach (var system in _engines)
  122. {
  123. system.ECB = entityCommandBuffer;
  124. }
  125. _ECB = entityCommandBuffer;
  126. RemovePreviousMarkingComponents(entityCommandBuffer);
  127. using (profiler.Sample("Before Submission Engines"))
  128. {
  129. BeforeECBFlushEngines().Complete();
  130. }
  131. }
  132. void AfterSubmissionPhase(PlatformProfiler profiler)
  133. {
  134. JobHandle AfterECBFlushEngines()
  135. {
  136. JobHandle jobHandle = default;
  137. //execute submission engines and complete jobs because of this I don't need to do _ECBSystem.AddJobHandleForProducer(Dependency);
  138. for (var index = 0; index < _afterSubmissionEngines.count; index++)
  139. {
  140. ref var engine = ref _afterSubmissionEngines[index];
  141. using (profiler.Sample(engine.name))
  142. {
  143. jobHandle = JobHandle.CombineDependencies(jobHandle, engine.AfterSubmissionUpdate(jobHandle));
  144. }
  145. }
  146. return jobHandle;
  147. }
  148. using (profiler.Sample("Flush Command Buffer"))
  149. {
  150. _ECBSystem.Update();
  151. }
  152. ConvertPendingEntities().Complete();
  153. using (profiler.Sample("After Submission Engines"))
  154. {
  155. AfterECBFlushEngines().Complete();
  156. }
  157. }
  158. void RemovePreviousMarkingComponents(EntityCommandBuffer ECB)
  159. {
  160. ECB.RemoveComponentForEntityQuery<UpdateUECSEntityAfterSubmission>(_entityQuery);
  161. }
  162. JobHandle ConvertPendingEntities()
  163. {
  164. if (_entityQuery.IsEmpty == false)
  165. {
  166. NativeEGIDMultiMapper<UECSEntityComponent> mapper =
  167. entitiesDB.QueryNativeMappedEntities<UECSEntityComponent>(
  168. entitiesDB.FindGroups<UECSEntityComponent>(), Allocator.TempJob);
  169. Entities.ForEach((Entity id, ref UpdateUECSEntityAfterSubmission egidComponent) =>
  170. {
  171. mapper.Entity(egidComponent.egid).uecsEntity = id;
  172. }).ScheduleParallel();
  173. mapper.ScheduleDispose(Dependency);
  174. }
  175. return Dependency;
  176. }
  177. readonly SimpleEntitiesSubmissionScheduler _submissionScheduler;
  178. SubmissionEntitiesCommandBufferSystem _ECBSystem;
  179. readonly FasterList<SubmissionEngine> _engines;
  180. readonly FasterList<IUpdateBeforeSubmission> _beforeSubmissionEngines;
  181. readonly FasterList<IUpdateAfterSubmission> _afterSubmissionEngines;
  182. [DisableAutoCreation]
  183. class SubmissionEntitiesCommandBufferSystem : EntityCommandBufferSystem { }
  184. protected override void OnUpdate() { }
  185. EntityQuery _entityQuery;
  186. EntityCommandBuffer _ECB;
  187. }
  188. public interface ISveltoUECSSubmission
  189. {
  190. void Add(SubmissionEngine engine);
  191. void SubmitEntities(JobHandle jobHandle);
  192. IEnumerator SubmitEntitiesAsync(JobHandle jobHandle, uint maxEntities);
  193. }
  194. }
  195. #endif