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.

189 lines
8.9KB

  1. using Svelto.DataStructures;
  2. using Svelto.ECS.Internal;
  3. namespace Svelto.ECS
  4. {
  5. public partial class EnginesRoot
  6. {
  7. internal class DoubleBufferedEntitiesToAdd
  8. {
  9. const int MaximumNumberOfItemsPerFrameBeforeToClear = 100;
  10. internal void Swap()
  11. {
  12. Swap(ref current, ref other);
  13. Swap(ref currentEntitiesCreatedPerGroup, ref otherEntitiesCreatedPerGroup);
  14. }
  15. void Swap<T>(ref T item1, ref T item2)
  16. {
  17. var toSwap = item2;
  18. item2 = item1;
  19. item1 = toSwap;
  20. }
  21. public void ClearOther()
  22. {
  23. //do not clear the groups created so far, they will be reused, unless they are too many!
  24. var otherCount = other.count;
  25. if (otherCount > MaximumNumberOfItemsPerFrameBeforeToClear)
  26. {
  27. FasterDictionary<RefWrapperType, ITypeSafeDictionary>[] otherValuesArray = other.unsafeValues;
  28. for (int i = 0; i < otherCount; ++i)
  29. {
  30. var safeDictionariesCount = otherValuesArray[i].count;
  31. ITypeSafeDictionary[] safeDictionaries = otherValuesArray[i].unsafeValues;
  32. {
  33. for (int j = 0; j < safeDictionariesCount; ++j)
  34. {
  35. //clear the dictionary of entities create do far (it won't allocate though)
  36. safeDictionaries[j].Dispose();
  37. }
  38. }
  39. }
  40. //reset the number of entities created so far
  41. otherEntitiesCreatedPerGroup.FastClear();
  42. other.FastClear();
  43. return;
  44. }
  45. {
  46. FasterDictionary<RefWrapperType, ITypeSafeDictionary>[] otherValuesArray = other.unsafeValues;
  47. for (int i = 0; i < otherCount; ++i)
  48. {
  49. var safeDictionariesCount = otherValuesArray[i].count;
  50. ITypeSafeDictionary[] safeDictionaries = otherValuesArray[i].unsafeValues;
  51. //do not remove the dictionaries of entities per type created so far, they will be reused
  52. if (safeDictionariesCount <= MaximumNumberOfItemsPerFrameBeforeToClear)
  53. {
  54. for (int j = 0; j < safeDictionariesCount; ++j)
  55. {
  56. //clear the dictionary of entities create do far (it won't allocate though)
  57. safeDictionaries[j].FastClear();
  58. }
  59. }
  60. else
  61. {
  62. for (int j = 0; j < safeDictionariesCount; ++j)
  63. {
  64. //clear the dictionary of entities create do far (it won't allocate though)
  65. safeDictionaries[j].Dispose();
  66. }
  67. otherValuesArray[i].FastClear();
  68. }
  69. }
  70. //reset the number of entities created so far
  71. otherEntitiesCreatedPerGroup.FastClear();
  72. }
  73. }
  74. //Before I tried for the third time to use a SparseSet instead of FasterDictionary, remember that
  75. //while group indices are sequential, they may not be used in a sequential order. Sparseset needs
  76. //entities to be created sequentially (the index cannot be managed externally)
  77. internal FasterDictionary<uint, FasterDictionary<RefWrapperType, ITypeSafeDictionary>> current;
  78. internal FasterDictionary<uint, FasterDictionary<RefWrapperType, ITypeSafeDictionary>> other;
  79. /// <summary>
  80. /// To avoid extra allocation, I don't clear the groups, so I need an extra data structure
  81. /// to keep count of the number of entities built this frame. At the moment the actual number
  82. /// of entities built is not used
  83. /// </summary>
  84. FasterDictionary<ExclusiveGroupStruct, uint> currentEntitiesCreatedPerGroup;
  85. FasterDictionary<ExclusiveGroupStruct, uint> otherEntitiesCreatedPerGroup;
  86. readonly FasterDictionary<uint, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>
  87. _entityComponentsToAddBufferA =
  88. new FasterDictionary<uint, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>();
  89. readonly FasterDictionary<uint, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>
  90. _entityComponentsToAddBufferB =
  91. new FasterDictionary<uint, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>();
  92. readonly FasterDictionary<ExclusiveGroupStruct, uint> _entitiesCreatedPerGroupA = new FasterDictionary<ExclusiveGroupStruct, uint>();
  93. readonly FasterDictionary<ExclusiveGroupStruct, uint> _entitiesCreatedPerGroupB = new FasterDictionary<ExclusiveGroupStruct, uint>();
  94. public DoubleBufferedEntitiesToAdd()
  95. {
  96. currentEntitiesCreatedPerGroup = _entitiesCreatedPerGroupA;
  97. otherEntitiesCreatedPerGroup = _entitiesCreatedPerGroupB;
  98. current = _entityComponentsToAddBufferA;
  99. other = _entityComponentsToAddBufferB;
  100. }
  101. public void Dispose()
  102. {
  103. {
  104. var otherValuesArray = other.unsafeValues;
  105. for (int i = 0; i < other.count; ++i)
  106. {
  107. var safeDictionariesCount = otherValuesArray[i].count;
  108. var safeDictionaries = otherValuesArray[i].unsafeValues;
  109. //do not remove the dictionaries of entities per type created so far, they will be reused
  110. for (int j = 0; j < safeDictionariesCount; ++j)
  111. {
  112. //clear the dictionary of entities create do far (it won't allocate though)
  113. safeDictionaries[j].Dispose();
  114. }
  115. }
  116. }
  117. {
  118. var currentValuesArray = current.unsafeValues;
  119. for (int i = 0; i < current.count; ++i)
  120. {
  121. var safeDictionariesCount = currentValuesArray[i].count;
  122. var safeDictionaries = currentValuesArray[i].unsafeValues;
  123. //do not remove the dictionaries of entities per type created so far, they will be reused
  124. for (int j = 0; j < safeDictionariesCount; ++j)
  125. {
  126. //clear the dictionary of entities create do far (it won't allocate though)
  127. safeDictionaries[j].Dispose();
  128. }
  129. }
  130. }
  131. }
  132. internal void IncrementEntityCount(ExclusiveGroupStruct groupID)
  133. {
  134. currentEntitiesCreatedPerGroup.GetOrCreate(groupID)++;
  135. }
  136. internal bool AnyEntityCreated()
  137. {
  138. return currentEntitiesCreatedPerGroup.count > 0;
  139. }
  140. internal bool AnyOtherEntityCreated()
  141. {
  142. return otherEntitiesCreatedPerGroup.count > 0;
  143. }
  144. internal void Preallocate
  145. (ExclusiveGroupStruct groupID, uint numberOfEntities, IComponentBuilder[] entityComponentsToBuild)
  146. {
  147. void PreallocateDictionaries(FasterDictionary<uint, FasterDictionary<RefWrapperType, ITypeSafeDictionary>> fasterDictionary1)
  148. {
  149. FasterDictionary<RefWrapperType, ITypeSafeDictionary> group =
  150. fasterDictionary1.GetOrCreate((uint) groupID, () => new FasterDictionary<RefWrapperType, ITypeSafeDictionary>());
  151. foreach (var componentBuilder in entityComponentsToBuild)
  152. {
  153. var entityComponentType = componentBuilder.GetEntityComponentType();
  154. var safeDictionary = @group.GetOrCreate(new RefWrapperType(entityComponentType)
  155. , () => componentBuilder.CreateDictionary(numberOfEntities));
  156. componentBuilder.Preallocate(safeDictionary, numberOfEntities);
  157. }
  158. }
  159. PreallocateDictionaries(current);
  160. PreallocateDictionaries(other);
  161. currentEntitiesCreatedPerGroup.GetOrCreate(groupID);
  162. otherEntitiesCreatedPerGroup.GetOrCreate(groupID);
  163. }
  164. }
  165. }
  166. }