Mirror of Svelto.ECS because we're a fan of it
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

263 satır
12KB

  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. //while caching is good to avoid over creating dictionaries that may be reused, the side effect
  10. //is that I have to iterate every time up to 100 dictionaries during the flushing of the build entities
  11. //even if there are 0 entities inside.
  12. const int MAX_NUMBER_OF_GROUPS_TO_CACHE = 100;
  13. const int MAX_NUMBER_OF_TYPES_PER_GROUP_TO_CACHE = 100;
  14. public DoubleBufferedEntitiesToAdd()
  15. {
  16. var entitiesCreatedPerGroupA = new FasterDictionary<ExclusiveGroupStruct, uint>();
  17. var entitiesCreatedPerGroupB = new FasterDictionary<ExclusiveGroupStruct, uint>();
  18. var entityComponentsToAddBufferA =
  19. new FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>();
  20. var entityComponentsToAddBufferB =
  21. new FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>();
  22. _currentNumberEntitiesCreatedPerGroup = entitiesCreatedPerGroupA;
  23. _lastNumberEntitiesCreatedPerGroup = entitiesCreatedPerGroupB;
  24. currentComponentsToAddPerGroup = entityComponentsToAddBufferA;
  25. lastComponentsToAddPerGroup = entityComponentsToAddBufferB;
  26. }
  27. public void ClearLastAddOperations()
  28. {
  29. var numberOfGroupsAddedSoFar = lastComponentsToAddPerGroup.count;
  30. var componentDictionariesPerType = lastComponentsToAddPerGroup.unsafeValues;
  31. //TODO: rewrite the caching logic with the new RecycleOrAdd dictionary functionality
  32. //I still do not want to cache too many groups
  33. //If we didn't create too many groups, we keep them alive, so we avoid the cost of creating new dictionaries
  34. //during future submissions, otherwise we clean up everything
  35. if (numberOfGroupsAddedSoFar > MAX_NUMBER_OF_GROUPS_TO_CACHE)
  36. {
  37. for (var i = 0; i < numberOfGroupsAddedSoFar; ++i)
  38. {
  39. var componentTypesCount = componentDictionariesPerType[i].count;
  40. var componentTypesDictionary = componentDictionariesPerType[i].unsafeValues;
  41. {
  42. for (var j = 0; j < componentTypesCount; ++j)
  43. //dictionaries of components may be native so they need to be disposed
  44. //before the references are GCed
  45. componentTypesDictionary[j].Dispose();
  46. }
  47. }
  48. //reset the number of entities created so far
  49. _lastNumberEntitiesCreatedPerGroup.Clear();
  50. lastComponentsToAddPerGroup.Clear();
  51. return;
  52. }
  53. for (var i = 0; i < numberOfGroupsAddedSoFar; ++i)
  54. {
  55. var componentTypesCount = componentDictionariesPerType[i].count;
  56. ITypeSafeDictionary[] componentTypesDictionary = componentDictionariesPerType[i].unsafeValues;
  57. for (var j = 0; j < componentTypesCount; ++j)
  58. //clear the dictionary of entities created so far (it won't allocate though)
  59. componentTypesDictionary[j].Clear();
  60. //if we didn't create too many component for this group, I reuse the component arrays
  61. if (componentTypesCount <= MAX_NUMBER_OF_TYPES_PER_GROUP_TO_CACHE)
  62. {
  63. for (var j = 0; j < componentTypesCount; ++j)
  64. componentTypesDictionary[j].Clear();
  65. }
  66. else
  67. {
  68. //here I have to dispose, because I am actually clearing the reference of the dictionary
  69. //with the next line.
  70. for (var j = 0; j < componentTypesCount; ++j)
  71. componentTypesDictionary[j].Dispose();
  72. componentDictionariesPerType[i].Clear();
  73. }
  74. }
  75. //reset the number of entities created so far
  76. _lastNumberEntitiesCreatedPerGroup.Clear();
  77. // _totalEntitiesToAdd = 0;
  78. }
  79. public void Dispose()
  80. {
  81. {
  82. var otherValuesArray = lastComponentsToAddPerGroup.unsafeValues;
  83. for (var i = 0; i < lastComponentsToAddPerGroup.count; ++i)
  84. {
  85. int safeDictionariesCount = otherValuesArray[i].count;
  86. ITypeSafeDictionary[] safeDictionaries = otherValuesArray[i].unsafeValues;
  87. //do not remove the dictionaries of entities per type created so far, they will be reused
  88. for (var j = 0; j < safeDictionariesCount; ++j)
  89. //clear the dictionary of entities create do far (it won't allocate though)
  90. safeDictionaries[j].Dispose();
  91. }
  92. }
  93. {
  94. var currentValuesArray = currentComponentsToAddPerGroup.unsafeValues;
  95. for (var i = 0; i < currentComponentsToAddPerGroup.count; ++i)
  96. {
  97. int safeDictionariesCount = currentValuesArray[i].count;
  98. ITypeSafeDictionary[] safeDictionaries = currentValuesArray[i].unsafeValues;
  99. //do not remove the dictionaries of entities per type created so far, they will be reused
  100. for (var j = 0; j < safeDictionariesCount; ++j)
  101. //clear the dictionary of entities create do far (it won't allocate though)
  102. safeDictionaries[j].Dispose();
  103. }
  104. }
  105. _currentNumberEntitiesCreatedPerGroup = null;
  106. _lastNumberEntitiesCreatedPerGroup = null;
  107. lastComponentsToAddPerGroup = null;
  108. currentComponentsToAddPerGroup = null;
  109. }
  110. internal bool AnyEntityCreated()
  111. {
  112. return _currentNumberEntitiesCreatedPerGroup.count > 0;
  113. }
  114. internal bool AnyPreviousEntityCreated()
  115. {
  116. return _lastNumberEntitiesCreatedPerGroup.count > 0;
  117. }
  118. internal void IncrementEntityCount(ExclusiveGroupStruct groupID)
  119. {
  120. _currentNumberEntitiesCreatedPerGroup.GetOrAdd(groupID)++;
  121. // _totalEntitiesToAdd++;
  122. }
  123. // public uint NumberOfEntitiesToAdd()
  124. // {
  125. // return _totalEntitiesToAdd;
  126. // }
  127. internal void Preallocate
  128. (ExclusiveGroupStruct groupID, uint numberOfEntities, IComponentBuilder[] entityComponentsToBuild)
  129. {
  130. void PreallocateDictionaries
  131. (FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>> dic)
  132. {
  133. var group = dic.GetOrAdd(
  134. groupID, () => new FasterDictionary<RefWrapperType, ITypeSafeDictionary>());
  135. foreach (var componentBuilder in entityComponentsToBuild)
  136. {
  137. var entityComponentType = componentBuilder.GetEntityComponentType();
  138. var safeDictionary = group.GetOrAdd(new RefWrapperType(entityComponentType)
  139. , () => componentBuilder
  140. .CreateDictionary(numberOfEntities));
  141. componentBuilder.Preallocate(safeDictionary, numberOfEntities);
  142. }
  143. }
  144. PreallocateDictionaries(currentComponentsToAddPerGroup);
  145. PreallocateDictionaries(lastComponentsToAddPerGroup);
  146. _currentNumberEntitiesCreatedPerGroup.GetOrAdd(groupID);
  147. _lastNumberEntitiesCreatedPerGroup.GetOrAdd(groupID);
  148. }
  149. internal void Swap()
  150. {
  151. Swap(ref currentComponentsToAddPerGroup, ref lastComponentsToAddPerGroup);
  152. Swap(ref _currentNumberEntitiesCreatedPerGroup, ref _lastNumberEntitiesCreatedPerGroup);
  153. }
  154. static void Swap<T>(ref T item1, ref T item2)
  155. {
  156. (item2, item1) = (item1, item2);
  157. }
  158. public OtherComponentsToAddPerGroupEnumerator GetEnumerator()
  159. {
  160. return new OtherComponentsToAddPerGroupEnumerator(lastComponentsToAddPerGroup
  161. , _lastNumberEntitiesCreatedPerGroup);
  162. }
  163. //Before I tried for the third time to use a SparseSet instead of FasterDictionary, remember that
  164. //while group indices are sequential, they may not be used in a sequential order. Sparseset needs
  165. //entities to be created sequentially (the index cannot be managed externally)
  166. internal FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>
  167. currentComponentsToAddPerGroup;
  168. FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>
  169. lastComponentsToAddPerGroup;
  170. /// <summary>
  171. /// To avoid extra allocation, I don't clear the groups, so I need an extra data structure
  172. /// to keep count of the number of entities built this frame. At the moment the actual number
  173. /// of entities built is not used
  174. /// </summary>
  175. FasterDictionary<ExclusiveGroupStruct, uint> _currentNumberEntitiesCreatedPerGroup;
  176. FasterDictionary<ExclusiveGroupStruct, uint> _lastNumberEntitiesCreatedPerGroup;
  177. //uint _totalEntitiesToAdd;
  178. }
  179. }
  180. struct OtherComponentsToAddPerGroupEnumerator
  181. {
  182. public OtherComponentsToAddPerGroupEnumerator
  183. (FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>
  184. lastComponentsToAddPerGroup
  185. , FasterDictionary<ExclusiveGroupStruct, uint> otherNumberEntitiesCreatedPerGroup)
  186. {
  187. _lastComponentsToAddPerGroup = lastComponentsToAddPerGroup;
  188. _lastNumberEntitiesCreatedPerGroup = otherNumberEntitiesCreatedPerGroup.GetEnumerator();
  189. Current = default;
  190. }
  191. public bool MoveNext()
  192. {
  193. while (_lastNumberEntitiesCreatedPerGroup.MoveNext())
  194. {
  195. var current = _lastNumberEntitiesCreatedPerGroup.Current;
  196. if (current.value > 0) //there are entities in this group
  197. {
  198. var value = _lastComponentsToAddPerGroup[current.key];
  199. Current = new GroupInfo()
  200. {
  201. group = current.key
  202. , components = value
  203. };
  204. return true;
  205. }
  206. }
  207. return false;
  208. }
  209. public GroupInfo Current { get; private set; }
  210. //cannot be read only as they will be modified by MoveNext
  211. readonly FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>
  212. _lastComponentsToAddPerGroup;
  213. SveltoDictionaryKeyValueEnumerator<ExclusiveGroupStruct, uint,
  214. ManagedStrategy<SveltoDictionaryNode<ExclusiveGroupStruct>>, ManagedStrategy<uint>,
  215. ManagedStrategy<int>>
  216. _lastNumberEntitiesCreatedPerGroup;
  217. }
  218. struct GroupInfo
  219. {
  220. public ExclusiveGroupStruct group;
  221. public FasterDictionary<RefWrapperType, ITypeSafeDictionary> components;
  222. }
  223. }