From 55ef119aff3d8c51a28f65d3a16baa0a95ca1f52 Mon Sep 17 00:00:00 2001
From: DCFApixels <99481254+DCFApixels@users.noreply.github.com>
Date: Tue, 11 Mar 2025 14:30:33 +0800
Subject: [PATCH] add optimization with IEntityStorage to EcsMaskIterator
---
src/Collections/EcsSpan.cs | 14 +++++-
src/EcsMask.cs | 57 +++++++++++++++++++-----
src/EcsWorld.cs | 10 ++++-
src/EcsWorld.static.cs | 2 +-
src/Executors/EcsWhereExecutor.cs | 8 ++++
src/Executors/EcsWhereToGroupExecutor.cs | 4 ++
src/Executors/MaskQueryExecutor.cs | 4 +-
src/Executors/Queries.cs | 30 -------------
8 files changed, 83 insertions(+), 46 deletions(-)
diff --git a/src/Collections/EcsSpan.cs b/src/Collections/EcsSpan.cs
index 78f32f3..16aae99 100644
--- a/src/Collections/EcsSpan.cs
+++ b/src/Collections/EcsSpan.cs
@@ -24,7 +24,7 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _worldID == 0; }
}
- public int WorldID
+ public short WorldID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _worldID; }
@@ -43,6 +43,11 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return new EcsLongsSpan(this); }
}
+ public bool IsSourceEntities
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return this == EcsWorld.GetWorld(_worldID).GetCurrentEntities_Internal(); }
+ }
#if ENABLE_IL2CPP
[Il2CppSetOption(Option.ArrayBoundsChecks, true)]
#endif
@@ -180,7 +185,7 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _source.IsNull; }
}
- public int WorldID
+ public short WorldID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _source.WorldID; }
@@ -194,6 +199,11 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _source.Count; }
}
+ public bool IsSourceEntities
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return _source.IsSourceEntities; }
+ }
#if ENABLE_IL2CPP
[Il2CppSetOption(Option.ArrayBoundsChecks, true)]
#endif
diff --git a/src/EcsMask.cs b/src/EcsMask.cs
index cbbb53a..91149c4 100644
--- a/src/EcsMask.cs
+++ b/src/EcsMask.cs
@@ -498,7 +498,10 @@ namespace DCFApixels.DragonECS
/// slised _sortIncChunckBuffer
private readonly UnsafeArray _sortExcChunckBuffer;
+ private readonly bool _isSingleIncPoolWithEntityStorage;
+ private readonly bool _isHasAnyEntityStorage;
private readonly MaskType _maskType;
+
private enum MaskType : byte
{
Empty,
@@ -512,11 +515,6 @@ namespace DCFApixels.DragonECS
World = source;
Mask = mask;
- //_sortIncBuffer = UnsafeArray.FromArray(mask._incs);
- //_sortExcBuffer = UnsafeArray.FromArray(mask._excs);
- //_sortIncChunckBuffer = UnsafeArray.FromArray(mask._incChunckMasks);
- //_sortExcChunckBuffer = UnsafeArray.FromArray(mask._excChunckMasks);
-
var sortBuffer = new UnsafeArray(mask._incs.Length + mask._excs.Length);
var sortChunckBuffer = new UnsafeArray(mask._incChunckMasks.Length + mask._excChunckMasks.Length);
@@ -530,6 +528,16 @@ namespace DCFApixels.DragonECS
_sortExcChunckBuffer = sortChunckBuffer.Slice(mask._incChunckMasks.Length, mask._excChunckMasks.Length);
_sortExcChunckBuffer.CopyFromArray_Unchecked(mask._excChunckMasks);
+ _isHasAnyEntityStorage = false;
+ var pools = source.AllPools;
+ for (int i = 0; i < _sortIncBuffer.Length; i++)
+ {
+ var pool = pools[_sortIncBuffer.ptr[i]];
+ _isHasAnyEntityStorage |= pool is IEntityStorage;
+ if (_isHasAnyEntityStorage) { break; }
+ }
+
+ _isSingleIncPoolWithEntityStorage = Mask.Excs.Length <= 0 && Mask.Incs.Length == 1;
if (_sortExcBuffer.Length <= 0)
{
_maskType = mask.IsEmpty ? MaskType.Empty : MaskType.OnlyInc;
@@ -594,9 +602,26 @@ namespace DCFApixels.DragonECS
// Выражение мало IncCount < (AllEntitesCount - ExcCount) вероятно будет истинным.
// ExcCount = максимальное количество ентитей с исключеющим ограничением и IncCount = минимальоне количество ентитей с включающим ограничением
// Поэтому исключающее ограничение игнорируется для maxEntites.
-
return maxEntites;
}
+ private unsafe bool TryGetEntityStorage(out IEntityStorage storage)
+ {
+ if (_isHasAnyEntityStorage)
+ {
+ var pools = World.AllPools;
+ for (int i = 0; i < _sortIncBuffer.Length; i++)
+ {
+ var pool = pools[_sortIncBuffer.ptr[i]];
+ storage = pool as IEntityStorage;
+ if (storage != null)
+ {
+ return true;
+ }
+ }
+ }
+ storage = null;
+ return false;
+ }
#endregion
#region IterateTo
@@ -694,7 +719,6 @@ namespace DCFApixels.DragonECS
#endregion
#region Enumerator
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator()
{
if (_iterator.Mask.IsBroken)
@@ -706,7 +730,14 @@ namespace DCFApixels.DragonECS
{
return new Enumerator(_span.Slice(0, 0), _iterator);
}
- return new Enumerator(_span, _iterator);
+ if (_iterator.TryGetEntityStorage(out IEntityStorage storage))
+ {
+ return new Enumerator(storage.ToSpan(), _iterator);
+ }
+ else
+ {
+ return new Enumerator(_span, _iterator);
+ }
}
#if ENABLE_IL2CPP
@@ -827,7 +858,6 @@ namespace DCFApixels.DragonECS
#endregion
#region Enumerator
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator()
{
if (_iterator.Mask.IsBroken)
@@ -839,7 +869,14 @@ namespace DCFApixels.DragonECS
{
return new Enumerator(_span.Slice(0, 0), _iterator);
}
- return new Enumerator(_span, _iterator);
+ if (_iterator.TryGetEntityStorage(out IEntityStorage storage))
+ {
+ return new Enumerator(storage.ToSpan(), _iterator);
+ }
+ else
+ {
+ return new Enumerator(_span, _iterator);
+ }
}
#if ENABLE_IL2CPP
diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs
index 3c36bf6..6639c98 100644
--- a/src/EcsWorld.cs
+++ b/src/EcsWorld.cs
@@ -130,7 +130,7 @@ namespace DCFApixels.DragonECS
get
{
ReleaseDelEntityBufferAll();
- return _entityDispenser.UsedToEcsSpan(ID);
+ return GetCurrentEntities_Internal();
}
}
public int PoolsCount
@@ -1167,6 +1167,14 @@ namespace DCFApixels.DragonECS
}
}
#endregion
+
+ #region Internal
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal EcsSpan GetCurrentEntities_Internal()
+ {
+ return _entityDispenser.UsedToEcsSpan(ID);
+ }
+ #endregion
}
#region Callbacks Interface
diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs
index 2798fd8..1311bd8 100644
--- a/src/EcsWorld.static.cs
+++ b/src/EcsWorld.static.cs
@@ -73,7 +73,7 @@ namespace DCFApixels.DragonECS
var world = _worlds[i];
if (world == null) { continue; }
- if(world.IsDestroyed == false)
+ if (world.IsDestroyed == false)
{
world.Destroy();
}
diff --git a/src/Executors/EcsWhereExecutor.cs b/src/Executors/EcsWhereExecutor.cs
index bc9bc50..9cb4df3 100644
--- a/src/Executors/EcsWhereExecutor.cs
+++ b/src/Executors/EcsWhereExecutor.cs
@@ -91,6 +91,10 @@ namespace DCFApixels.DragonECS.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsSpan ExecuteFor(EcsSpan span)
{
+ if (span.IsSourceEntities)
+ {
+ return Execute();
+ }
ExecuteFor_Iternal(span);
return new EcsSpan(World.ID, _filteredEntities, _filteredEntitiesCount);
}
@@ -105,6 +109,10 @@ namespace DCFApixels.DragonECS.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsSpan ExecuteFor(EcsSpan span, Comparison comparison)
{
+ if (span.IsSourceEntities)
+ {
+ return Execute(comparison);
+ }
ExecuteFor_Iternal(span);
ArraySortHalperX.Sort(_filteredEntities, comparison, _filteredEntitiesCount);
return new EcsSpan(World.ID, _filteredEntities, _filteredEntitiesCount);
diff --git a/src/Executors/EcsWhereToGroupExecutor.cs b/src/Executors/EcsWhereToGroupExecutor.cs
index 8511206..8f9d046 100644
--- a/src/Executors/EcsWhereToGroupExecutor.cs
+++ b/src/Executors/EcsWhereToGroupExecutor.cs
@@ -90,6 +90,10 @@ namespace DCFApixels.DragonECS.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsReadonlyGroup ExecuteFor(EcsSpan span)
{
+ if (span.IsSourceEntities)
+ {
+ return Execute();
+ }
ExecuteFor_Iternal(span);
return _filteredGroup;
}
diff --git a/src/Executors/MaskQueryExecutor.cs b/src/Executors/MaskQueryExecutor.cs
index d6f70f2..96e786a 100644
--- a/src/Executors/MaskQueryExecutor.cs
+++ b/src/Executors/MaskQueryExecutor.cs
@@ -120,7 +120,7 @@ namespace DCFApixels.DragonECS.Core
_world = mask.World;
_maskInc = mask._incs;
_maskExc = mask._excs;
- _versions = UnmanagedArrayUtility.New(1 + mask._incs.Length + mask._excs.Length);
+ _versions = UnmanagedArrayUtility.NewAndInit(1 + mask._incs.Length + mask._excs.Length);
}
public bool Check()
{
@@ -176,7 +176,7 @@ namespace DCFApixels.DragonECS.Core
long* ptr = _versions;
var slots = _world._poolSlots;
- bool result = true;
+ bool result = _maskInc.Length > 0 || _maskExc.Length > 0;
foreach (var slotIndex in _maskInc)
{
ptr++;
diff --git a/src/Executors/Queries.cs b/src/Executors/Queries.cs
index 171386f..96d0eed 100644
--- a/src/Executors/Queries.cs
+++ b/src/Executors/Queries.cs
@@ -16,11 +16,6 @@ namespace DCFApixels.DragonECS
where TAspect : new()
where TCollection : IEntityStorage
{
- if (ReferenceEquals(entities, entities.World))
- {
- entities.World.GetQueryCache(out EcsWhereExecutor executor, out aspect);
- return executor.Execute();
- }
return entities.ToSpan().Where(out aspect);
}
public static EcsSpan Where(this EcsReadonlyGroup group, out TAspect aspect)
@@ -38,11 +33,6 @@ namespace DCFApixels.DragonECS
public static EcsSpan Where(this TCollection entities, IComponentMask mask)
where TCollection : IEntityStorage
{
- if (ReferenceEquals(entities, entities.World))
- {
- var executor = entities.World.GetExecutorForMask(mask);
- return executor.Execute();
- }
return entities.ToSpan().Where(mask);
}
public static EcsSpan Where(this EcsReadonlyGroup group, IComponentMask mask)
@@ -61,11 +51,6 @@ namespace DCFApixels.DragonECS
where TAspect : new()
where TCollection : IEntityStorage
{
- if (ReferenceEquals(entities, entities.World))
- {
- entities.World.GetQueryCache(out EcsWhereExecutor executor, out aspect);
- return executor.Execute(comparison);
- }
return entities.ToSpan().Where(out aspect, comparison);
}
public static EcsSpan Where(this EcsReadonlyGroup group, out TAspect aspect, Comparison comparison)
@@ -83,11 +68,6 @@ namespace DCFApixels.DragonECS
public static EcsSpan Where(this TCollection entities, IComponentMask mask, Comparison comparison)
where TCollection : IEntityStorage
{
- if (ReferenceEquals(entities, entities.World))
- {
- EcsWhereExecutor executor = entities.World.GetExecutorForMask(mask);
- return executor.Execute(comparison);
- }
return entities.ToSpan().Where(mask, comparison);
}
public static EcsSpan Where(this EcsReadonlyGroup group, IComponentMask mask, Comparison comparison)
@@ -106,11 +86,6 @@ namespace DCFApixels.DragonECS
where TAspect : new()
where TCollection : IEntityStorage
{
- if (ReferenceEquals(entities, entities.World))
- {
- entities.World.GetQueryCache(out EcsWhereToGroupExecutor executor, out aspect);
- return executor.Execute();
- }
return entities.ToSpan().WhereToGroup(out aspect);
}
public static EcsReadonlyGroup WhereToGroup(this EcsReadonlyGroup group, out TAspect aspect)
@@ -128,11 +103,6 @@ namespace DCFApixels.DragonECS
public static EcsReadonlyGroup WhereToGroup(this TCollection entities, IComponentMask mask)
where TCollection : IEntityStorage
{
- if (ReferenceEquals(entities, entities.World))
- {
- EcsWhereToGroupExecutor executor = entities.World.GetExecutorForMask(mask);
- return executor.Execute();
- }
return entities.ToSpan().WhereToGroup(mask);
}
public static EcsReadonlyGroup WhereToGroup(this EcsReadonlyGroup group, IComponentMask mask)