From 95eecf98e58e53ce725536911687e8df9ca810e7 Mon Sep 17 00:00:00 2001 From: DCFApixels <99481254+DCFApixels@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:30:23 +0800 Subject: [PATCH] impl pages for EcsGroup --- src/Collections/EcsGroup.cs | 165 +++++++++++++++++++++++++++++------ src/Internal/ArrayUtility.cs | 19 ++++ 2 files changed, 158 insertions(+), 26 deletions(-) diff --git a/src/Collections/EcsGroup.cs b/src/Collections/EcsGroup.cs index 4c80aee..0423750 100644 --- a/src/Collections/EcsGroup.cs +++ b/src/Collections/EcsGroup.cs @@ -179,17 +179,49 @@ namespace DCFApixels.DragonECS #endregion } + public unsafe partial class EcsWorld + { + private int*[] _groupSparsePagePool = new int*[64]; + private int _groupSparsePagePoolCount = 0; + internal int* TakePage() + { + if(_groupSparsePagePoolCount <= 0) + { + var x = UnmanagedArrayUtility.NewAndInit(EcsGroup.PAGE_SIZE); + return x; + } + return _groupSparsePagePool[--_groupSparsePagePoolCount]; + } + internal void ReternPage(int* page) + { + if (_groupSparsePagePoolCount >= _groupSparsePagePool.Length) + { + var old = _groupSparsePagePool; + _groupSparsePagePool = new int*[_groupSparsePagePoolCount << 1]; + for (int j = 0; j < old.Length; j++) + { + _groupSparsePagePool[j] = old[j]; + } + } + _groupSparsePagePool[_groupSparsePagePoolCount++] = page; + } + } + #if ENABLE_IL2CPP [Il2CppSetOption(Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] #endif [DebuggerTypeProxy(typeof(DebuggerProxy))] //TODO переработать EcsGroup в структуру-обертку, чтобы когда вызывается Release то можно было занулить эту структуру, а может не перерабатывать, есть проблема с боксингом - public class EcsGroup : IDisposable, IEnumerable, IEntityStorage, ISet + public unsafe class EcsGroup : IDisposable, IEnumerable, IEntityStorage, ISet { + internal const int PAGE_SIZE = Page.SIZE; + private EcsWorld _source; private int[] _dense; - private int[] _sparse; //Старший бит занят временной маркировкой в операциях над множествами + private Page* _sparse; //Старший бит занят временной маркировкой в операциях над множествами + private int _pagesCount; + private int _totalCapacity; private int _count = 0; internal bool _isReleased = true; @@ -241,17 +273,17 @@ namespace DCFApixels.DragonECS #endif return _dense[++index]; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - // TODO добавить лок енумератора на изменение -#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (index < 0 || index >= Count) { Throw.ArgumentOutOfRange(); } -#endif - var oldValue = _dense[index]; - _dense[index] = value; - _sparse[oldValue] = 0; - } +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// set +// { +// // TODO добавить лок енумератора на изменение +//#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS +// if (index < 0 || index >= Count) { Throw.ArgumentOutOfRange(); } +//#endif +// var oldValue = _dense[index]; +// _dense[index] = value; +// _sparse[oldValue] = 0; +// } } #endregion @@ -266,7 +298,10 @@ namespace DCFApixels.DragonECS _source = world; _source.RegisterGroup(this); _dense = new int[denseCapacity]; - _sparse = new int[world.Capacity]; + //_sparse = new int[world.Capacity]; + _totalCapacity = world.Capacity; + _pagesCount = CalcSparseSize(_totalCapacity); + _sparse = UnmanagedArrayUtility.NewAndInit(_pagesCount); } public void Dispose() { @@ -278,12 +313,22 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Has(int entityID) { - return _sparse[entityID] != 0; + //return _sparse[entityID] != 0; + Page* page = _sparse + (entityID >> Page.SHIFT); + + ReadOnlySpan span = default; + if (page->Indexes != null) + { + span = new ReadOnlySpan(page->Indexes, Page.SIZE); + } + return page->Indexes != null && page->Indexes[entityID & Page.MASK] != 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int IndexOf(int entityID) { - return _sparse[entityID]; + //return _sparse[entityID]; + Page* page = _sparse + (entityID >> Page.SHIFT); + return page->Indexes != null ? page->Indexes[entityID & Page.MASK] : -1; } #endregion @@ -312,7 +357,19 @@ namespace DCFApixels.DragonECS Array.Resize(ref _dense, _dense.Length << 1); } _dense[_count] = entityID; - _sparse[entityID] = _count; + + //_sparse[entityID] = _count; + Page* page = _sparse + (entityID >> Page.SHIFT); + if(page->Indexes == null) + { + page->Indexes = _source.TakePage(); + if(page->Indexes == null) + { + + } + } + page->Indexes[entityID & Page.MASK] = _count; + page->Count++; } public void RemoveUnchecked(int entityID) @@ -334,9 +391,22 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Remove_Internal(int entityID) { - _dense[_sparse[entityID]] = _dense[_count]; - _sparse[_dense[_count--]] = _sparse[entityID]; - _sparse[entityID] = 0; + //_dense[_sparse[entityID]] = _dense[_count]; + //_sparse[_dense[_count--]] = _sparse[entityID]; + //_sparse[entityID] = 0; + + Page* page = _sparse + (entityID >> Page.SHIFT); + int localEntityID = entityID & Page.MASK; + + _dense[page->Indexes[localEntityID]] = _dense[_count]; + + int localLastIndex = _dense[_count--]; + int* lastPageArray = (_sparse + (localLastIndex >> Page.SHIFT))->Indexes; + localLastIndex = localLastIndex & Page.MASK; + + lastPageArray[localLastIndex] = page->Indexes[localEntityID]; + page->Indexes[localEntityID] = 0; + page->Count--; } public void RemoveUnusedEntityIDs() @@ -358,10 +428,26 @@ namespace DCFApixels.DragonECS { return; } - for (int i = 1; i <= _count; i++) + //for (int i = 1; i <= _count; i++) + //{ + // _sparse[_dense[i]] = 0; + //} + for (int i = 0; i < _pagesCount; i++) { - _sparse[_dense[i]] = 0; + var page = _sparse + i; + if (page->Indexes != null) + { + //TODO тут надо оптимизировать отчисткой не всего а по dense списку + for (int j = 0; j < Page.SIZE; j++) + { + page->Indexes[j] = 0; + } + _source.ReternPage(page->Indexes); + page->Indexes = null; + } + page->Count = 0; } + _count = 0; } #endregion @@ -1251,17 +1337,20 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Mark_Internal(int entityID) { - _sparse[entityID] |= int.MinValue; + throw new NotImplementedException(); + //_sparse[entityID] |= int.MinValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool IsMark_Internal(int entityID) { - return (_sparse[entityID] & int.MinValue) == int.MinValue; + throw new NotImplementedException(); + //return (_sparse[entityID] & int.MinValue) == int.MinValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Unmark_Internal(int entityID) { - _sparse[entityID] &= int.MaxValue; + throw new NotImplementedException(); + //_sparse[entityID] &= int.MaxValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ClearUnmarked_Internal() @@ -1302,7 +1391,11 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void OnWorldResize_Internal(int newSize) { - Array.Resize(ref _sparse, newSize); + //Array.Resize(ref _sparse, newSize); + _totalCapacity = newSize; + var oldPagesCount = _pagesCount; + _pagesCount = CalcSparseSize(_totalCapacity); + _sparse = UnmanagedArrayUtility.ResizeAndInit(_sparse, oldPagesCount, _pagesCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void OnReleaseDelEntityBuffer_Internal(ReadOnlySpan buffer) @@ -1352,5 +1445,25 @@ namespace DCFApixels.DragonECS public DebuggerProxy(EcsReadonlyGroup group) : this(group.GetSource_Internal()) { } } #endregion + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //private static (int, int) GetPage(int index) + //{ + // int pageIndex = index >> Page.SIZE; + // return (_sparse + pageIndex, index & Page.MASK); + //} + private static int CalcSparseSize(int capacity) + { + return (capacity >> Page.SHIFT) + ((capacity & Page.MASK) == 0 ? 0 : 1); + } + private struct Page + { + public const int SHIFT = 6; // 64 + public const int SIZE = 1 << SHIFT; + public const int MASK = SIZE - 1; + + public int* Indexes; + public int Count; + } } } \ No newline at end of file diff --git a/src/Internal/ArrayUtility.cs b/src/Internal/ArrayUtility.cs index 43aac30..88ddfde 100644 --- a/src/Internal/ArrayUtility.cs +++ b/src/Internal/ArrayUtility.cs @@ -188,6 +188,7 @@ namespace DCFApixels.DragonECS.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T* New(int capacity) where T : unmanaged { + Console.WriteLine($"{typeof(T).Name} - {Marshal.SizeOf()} - {capacity} - {Marshal.SizeOf() * capacity}"); return (T*)Marshal.AllocHGlobal(Marshal.SizeOf() * capacity).ToPointer(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -254,6 +255,24 @@ namespace DCFApixels.DragonECS.Internal new IntPtr(oldPointer), new IntPtr(MetaCache.Size * newCount))).ToPointer(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T* ResizeAndInit(void* oldPointer, int oldSize, int newSize) where T : unmanaged + { + int sizeT = MetaCache.Size; + T* result = (T*)Marshal.ReAllocHGlobal( + new IntPtr(oldPointer), + new IntPtr(sizeT * newSize)).ToPointer(); + Init((byte*)result, sizeT * oldSize, sizeT * newSize); + return result; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Init(byte* pointer, int startByteIndex, int endByteIndex) + { + for (int i = startByteIndex; i < endByteIndex; i++) + { + *(pointer + i) = 0; + } + } } public static class CollectionUtility