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.

228 lines
11KB

  1. #if UNITY_NATIVE
  2. using System;
  3. using DBC.ECS;
  4. using Svelto.Common;
  5. using Svelto.DataStructures;
  6. using Svelto.ECS.Internal;
  7. using Svelto.ECS.Native;
  8. namespace Svelto.ECS
  9. {
  10. public partial class EnginesRoot
  11. {
  12. NativeEntityRemove ProvideNativeEntityRemoveQueue<T>(string memberName) where T : IEntityDescriptor, new()
  13. {
  14. //DBC.ECS.Check.Require(EntityDescriptorTemplate<T>.descriptor.isUnmanaged(), "can't remove entities with not native types");
  15. //todo: remove operation array and store entity descriptor hash in the return value
  16. //todo I maybe able to provide a _nativeSwap.SwapEntity<entityDescriptor>
  17. //todo make this work with base descriptors too
  18. var descriptorComponentsToRemove = EntityDescriptorTemplate<T>.descriptor.componentsToBuild;
  19. _nativeRemoveOperations.Add(new NativeOperationRemove(
  20. descriptorComponentsToRemove, TypeCache<T>.type
  21. , memberName));
  22. return new NativeEntityRemove(_nativeRemoveOperationQueue, _nativeRemoveOperations.count - 1);
  23. }
  24. NativeEntitySwap ProvideNativeEntitySwapQueue<T>(string memberName) where T : IEntityDescriptor, new()
  25. {
  26. // DBC.ECS.Check.Require(EntityDescriptorTemplate<T>.descriptor.isUnmanaged(), "can't swap entities with not native types");
  27. //todo: remove operation array and store entity descriptor hash in the return value
  28. _nativeSwapOperations.Add(new NativeOperationSwap(EntityDescriptorTemplate<T>.descriptor.componentsToBuild
  29. , TypeCache<T>.type, memberName));
  30. return new NativeEntitySwap(_nativeSwapOperationQueue, _nativeSwapOperations.count - 1);
  31. }
  32. NativeEntityFactory ProvideNativeEntityFactoryQueue<T>(string caller) where T : IEntityDescriptor, new()
  33. {
  34. DBC.ECS.Check.Require(EntityDescriptorTemplate<T>.descriptor.IsUnmanaged()
  35. , "can't build entities with not native types");
  36. DBC.ECS.Check.Require(string.IsNullOrEmpty(caller) == false, "an invalid caller has been provided");
  37. //todo: remove operation array and store entity descriptor hash in the return value
  38. _nativeAddOperations.Add(new NativeOperationBuild(EntityDescriptorTemplate<T>.descriptor.componentsToBuild
  39. , TypeCache<T>.type, caller));
  40. return new NativeEntityFactory(_nativeAddOperationQueue, _nativeAddOperations.count - 1, _entityLocator);
  41. }
  42. void FlushNativeOperations(in PlatformProfiler profiler)
  43. {
  44. using (profiler.Sample("Native Remove Operations"))
  45. {
  46. var removeBuffersCount = _nativeRemoveOperationQueue.count;
  47. //todo, I don't like that this scans all the queues even if they are empty
  48. for (int i = 0; i < removeBuffersCount; i++)
  49. {
  50. ref var buffer = ref _nativeRemoveOperationQueue.GetBag(i);
  51. while (buffer.IsEmpty() == false)
  52. {
  53. var componentsIndex = buffer.Dequeue<uint>();
  54. var entityEGID = buffer.Dequeue<EGID>();
  55. ref NativeOperationRemove nativeRemoveOperation = ref _nativeRemoveOperations[componentsIndex];
  56. CheckRemoveEntityID(entityEGID, nativeRemoveOperation.entityDescriptorType
  57. , nativeRemoveOperation.caller);
  58. QueueRemoveEntityOperation(
  59. entityEGID, FindRealComponents(entityEGID, nativeRemoveOperation.components)
  60. , nativeRemoveOperation.caller);
  61. }
  62. }
  63. }
  64. using (profiler.Sample("Native Swap Operations"))
  65. {
  66. var swapBuffersCount = _nativeSwapOperationQueue.count;
  67. for (int i = 0; i < swapBuffersCount; i++)
  68. {
  69. ref var buffer = ref _nativeSwapOperationQueue.GetBag(i);
  70. while (buffer.IsEmpty() == false)
  71. {
  72. var componentsIndex = buffer.Dequeue<uint>();
  73. var entityEGID = buffer.Dequeue<DoubleEGID>();
  74. ref var nativeSwapOperation = ref _nativeSwapOperations[componentsIndex];
  75. CheckRemoveEntityID(entityEGID.@from, nativeSwapOperation.entityDescriptorType
  76. , nativeSwapOperation.caller);
  77. CheckAddEntityID(entityEGID.to, nativeSwapOperation.entityDescriptorType
  78. , nativeSwapOperation.caller);
  79. QueueSwapEntityOperation(entityEGID.@from, entityEGID.to
  80. , FindRealComponents(entityEGID.@from, nativeSwapOperation.components)
  81. , nativeSwapOperation.caller);
  82. }
  83. }
  84. }
  85. //todo: it feels weird that these builds in the transient entities database while it could build directly to the final one
  86. using (profiler.Sample("Native Add Operations"))
  87. {
  88. var addBuffersCount = _nativeAddOperationQueue.count;
  89. for (int i = 0; i < addBuffersCount; i++)
  90. {
  91. ref var buffer = ref _nativeAddOperationQueue.GetBag(i);
  92. //todo: I don't like to iterate a constant number of buffer and skip the empty ones
  93. while (buffer.IsEmpty() == false)
  94. {
  95. var componentsIndex = buffer.Dequeue<uint>();
  96. var egid = buffer.Dequeue<EGID>();
  97. var reference = buffer.Dequeue<EntityReference>();
  98. var componentCounts = buffer.Dequeue<uint>();
  99. Check.Assert(egid.groupID.isInvalid == false
  100. , "invalid group detected, are you using new ExclusiveGroupStruct() instead of new ExclusiveGroup()?");
  101. ref var nativeOperation = ref _nativeAddOperations[componentsIndex];
  102. #if DEBUG && !PROFILE_SVELTO
  103. var entityDescriptorType = nativeOperation.entityDescriptorType;
  104. CheckAddEntityID(egid, entityDescriptorType, nativeOperation.caller);
  105. #endif
  106. _entityLocator.SetReference(reference, egid);
  107. //todo: I reckon is not necessary to carry the components array in the native operation, it's enough to know the descriptor type
  108. //however I guess this can work only if the type is hashed, which could be done with the burst type hash
  109. var dic = EntityFactory.BuildGroupedEntities(egid, _groupedEntityToAdd
  110. , nativeOperation.components, null
  111. #if DEBUG && !PROFILE_SVELTO
  112. , entityDescriptorType
  113. #endif
  114. );
  115. var init = new EntityInitializer(egid, dic, reference);
  116. //only called if Init is called on the initialized (there is something to init)
  117. while (componentCounts > 0)
  118. {
  119. componentCounts--;
  120. var typeID = buffer.Dequeue<uint>();
  121. IFiller componentBuilder = EntityComponentIDMap.GetBuilderFromID(typeID);
  122. //after the typeID, I expect the serialized component
  123. componentBuilder.FillFromByteArray(init, buffer);
  124. }
  125. }
  126. }
  127. }
  128. }
  129. void AllocateNativeOperations()
  130. {
  131. _nativeRemoveOperations = new FasterList<NativeOperationRemove>();
  132. _nativeSwapOperations = new FasterList<NativeOperationSwap>();
  133. _nativeAddOperations = new FasterList<NativeOperationBuild>();
  134. }
  135. FasterList<NativeOperationRemove> _nativeRemoveOperations;
  136. FasterList<NativeOperationSwap> _nativeSwapOperations;
  137. FasterList<NativeOperationBuild> _nativeAddOperations;
  138. readonly AtomicNativeBags _nativeAddOperationQueue;
  139. readonly AtomicNativeBags _nativeRemoveOperationQueue;
  140. readonly AtomicNativeBags _nativeSwapOperationQueue;
  141. }
  142. readonly struct DoubleEGID
  143. {
  144. internal readonly EGID from;
  145. internal readonly EGID to;
  146. public DoubleEGID(EGID from1, EGID to1)
  147. {
  148. from = from1;
  149. to = to1;
  150. }
  151. }
  152. readonly struct NativeOperationBuild
  153. {
  154. internal readonly IComponentBuilder[] components;
  155. internal readonly Type entityDescriptorType;
  156. internal readonly string caller;
  157. public NativeOperationBuild
  158. (IComponentBuilder[] descriptorComponentsToBuild, Type entityDescriptorType, string caller)
  159. {
  160. this.entityDescriptorType = entityDescriptorType;
  161. components = descriptorComponentsToBuild;
  162. this.caller = caller;
  163. }
  164. }
  165. readonly struct NativeOperationRemove
  166. {
  167. internal readonly IComponentBuilder[] components;
  168. internal readonly Type entityDescriptorType;
  169. internal readonly string caller;
  170. public NativeOperationRemove
  171. (IComponentBuilder[] descriptorComponentsToRemove, Type entityDescriptorType, string caller)
  172. {
  173. this.caller = caller;
  174. components = descriptorComponentsToRemove;
  175. this.entityDescriptorType = entityDescriptorType;
  176. }
  177. }
  178. readonly struct NativeOperationSwap
  179. {
  180. internal readonly IComponentBuilder[] components;
  181. internal readonly Type entityDescriptorType;
  182. internal readonly string caller;
  183. public NativeOperationSwap
  184. (IComponentBuilder[] descriptorComponentsToSwap, Type entityDescriptorType, string caller)
  185. {
  186. this.caller = caller;
  187. components = descriptorComponentsToSwap;
  188. this.entityDescriptorType = entityDescriptorType;
  189. }
  190. }
  191. }
  192. #endif