Improve ecs query performance;
This commit is contained in:
42
Ghost.Entities/Query/QueryBuilder.cs
Normal file
42
Ghost.Entities/Query/QueryBuilder.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Ghost.Core;
|
||||
|
||||
namespace Ghost.Entities.Query;
|
||||
|
||||
public struct QueryBuilder
|
||||
{
|
||||
private QueryFilter _filter;
|
||||
|
||||
public QueryBuilder()
|
||||
{
|
||||
_filter = new QueryFilter();
|
||||
}
|
||||
|
||||
public QueryBuilder WithAll<T>()
|
||||
{
|
||||
_filter._all.Add(TypeHandle.Get<T>());
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryBuilder WithAny<T>()
|
||||
{
|
||||
_filter._any.Add(TypeHandle.Get<T>());
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryBuilder WithAbsent<T>()
|
||||
{
|
||||
_filter._absent.Add(TypeHandle.Get<T>());
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryBuilder WithDisabled<T>()
|
||||
{
|
||||
_filter._disabled.Add(TypeHandle.Get<T>());
|
||||
return this;
|
||||
}
|
||||
|
||||
public readonly QueryFilter Build()
|
||||
{
|
||||
return _filter;
|
||||
}
|
||||
}
|
||||
@@ -1,98 +1,98 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Entities.Components;
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ghost.Entities.Query;
|
||||
|
||||
[Flags]
|
||||
internal enum FilterMode
|
||||
public struct QueryFilter : IDisposable
|
||||
{
|
||||
All = 1 << 0,
|
||||
Any = 1 << 1,
|
||||
Absent = 1 << 2,
|
||||
Disabled = 1 << 3,
|
||||
}
|
||||
private readonly Stack.Scope _scope;
|
||||
|
||||
internal readonly struct FilterEntry(TypeHandle id, FilterMode mode)
|
||||
{
|
||||
public readonly TypeHandle typeHandle = id;
|
||||
public readonly FilterMode mode = mode;
|
||||
}
|
||||
internal UnsafeList<TypeHandle> _all;
|
||||
internal UnsafeList<TypeHandle> _any;
|
||||
internal UnsafeList<TypeHandle> _absent;
|
||||
internal UnsafeList<TypeHandle> _disabled;
|
||||
|
||||
internal struct QueryFilter()
|
||||
{
|
||||
internal List<TypeHandle> _all = new(6);
|
||||
internal List<TypeHandle> _any = new(6);
|
||||
internal List<TypeHandle> _absent = new(6);
|
||||
internal List<TypeHandle> _disabled = new(6);
|
||||
public QueryFilter()
|
||||
{
|
||||
_scope = AllocationManager.CreateStackScope();
|
||||
|
||||
public readonly UnsafeBitSet ComputeFilterBitMask(World world)
|
||||
_all = new UnsafeList<TypeHandle>(4, Allocator.Stack);
|
||||
_any = new UnsafeList<TypeHandle>(4, Allocator.Stack);
|
||||
_absent = new UnsafeList<TypeHandle>(4, Allocator.Stack);
|
||||
_disabled = new UnsafeList<TypeHandle>(4, Allocator.Stack);
|
||||
}
|
||||
|
||||
public readonly UnsafeBitSet ComputeFilterBitMask(World world, Allocator allocator)
|
||||
{
|
||||
UnsafeBitSet allMask = default;
|
||||
UnsafeBitSet anyMask = default;
|
||||
UnsafeBitSet absentMask = default;
|
||||
|
||||
using var scope = AllocationManager.CreateStackScope();
|
||||
|
||||
foreach (var typeHandle in _all)
|
||||
{
|
||||
var mask = world.ComponentStorage.GetOrCreateMask(typeHandle);
|
||||
|
||||
if (!allMask.IsCreated)
|
||||
{
|
||||
allMask = new UnsafeBitSet(mask.Length, Allocator.Stack, AllocationOption.Clear);
|
||||
allMask.SetAll();
|
||||
}
|
||||
|
||||
allMask.AndOperation(mask);
|
||||
}
|
||||
|
||||
foreach (var typeHandle in _any)
|
||||
{
|
||||
var mask = world.ComponentStorage.GetOrCreateMask(typeHandle);
|
||||
|
||||
if (!anyMask.IsCreated)
|
||||
{
|
||||
anyMask = new UnsafeBitSet(mask.Length, Allocator.Stack, AllocationOption.Clear);
|
||||
}
|
||||
|
||||
anyMask.OrOperation(mask);
|
||||
}
|
||||
|
||||
foreach (var typeHandle in _absent)
|
||||
{
|
||||
var mask = world.ComponentStorage.GetOrCreateMask(typeHandle);
|
||||
|
||||
if (!absentMask.IsCreated)
|
||||
{
|
||||
absentMask = new UnsafeBitSet(mask.Length, Allocator.Stack, AllocationOption.Clear);
|
||||
}
|
||||
|
||||
absentMask.OrOperation(mask);
|
||||
}
|
||||
|
||||
var result = new UnsafeBitSet(world.EntityManager.EntityCount, Allocator.Persistent);
|
||||
var result = new UnsafeBitSet(world.EntityManager.EntityCount, allocator);
|
||||
result.SetAll();
|
||||
|
||||
if (allMask.IsCreated)
|
||||
using (AllocationManager.CreateStackScope())
|
||||
{
|
||||
result.AndOperation(allMask);
|
||||
allMask.Dispose();
|
||||
}
|
||||
foreach (var typeHandle in _all)
|
||||
{
|
||||
var mask = world.ComponentStorage.GetOrCreateMask(typeHandle);
|
||||
|
||||
if (anyMask.IsCreated)
|
||||
{
|
||||
result.AndOperation(anyMask);
|
||||
anyMask.Dispose();
|
||||
}
|
||||
if (!allMask.IsCreated)
|
||||
{
|
||||
allMask = new UnsafeBitSet(mask.Length, Allocator.Stack, AllocationOption.None);
|
||||
allMask.SetAll();
|
||||
}
|
||||
|
||||
if (absentMask.IsCreated)
|
||||
{
|
||||
result.AndOperation(~absentMask);
|
||||
absentMask.Dispose();
|
||||
allMask.AndOperation(mask);
|
||||
}
|
||||
|
||||
foreach (var typeHandle in _any)
|
||||
{
|
||||
var mask = world.ComponentStorage.GetOrCreateMask(typeHandle);
|
||||
|
||||
if (!anyMask.IsCreated)
|
||||
{
|
||||
anyMask = new UnsafeBitSet(mask.Length, Allocator.Stack);
|
||||
}
|
||||
|
||||
anyMask.OrOperation(mask);
|
||||
}
|
||||
|
||||
foreach (var typeHandle in _absent)
|
||||
{
|
||||
var mask = world.ComponentStorage.GetOrCreateMask(typeHandle);
|
||||
|
||||
if (!absentMask.IsCreated)
|
||||
{
|
||||
absentMask = new UnsafeBitSet(mask.Length, Allocator.Stack);
|
||||
}
|
||||
|
||||
absentMask.OrOperation(mask);
|
||||
}
|
||||
|
||||
if (allMask.IsCreated)
|
||||
{
|
||||
result.AndOperation(allMask);
|
||||
}
|
||||
|
||||
if (anyMask.IsCreated)
|
||||
{
|
||||
result.AndOperation(anyMask);
|
||||
}
|
||||
|
||||
if (absentMask.IsCreated)
|
||||
{
|
||||
result.AndOperation(~absentMask);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public readonly void Dispose()
|
||||
{
|
||||
_scope.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,12 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ghost.Entities.Query;
|
||||
|
||||
public interface IQueryTypeParameter
|
||||
public interface IQueryTypeParameter<T>
|
||||
where T : IComponentData
|
||||
{
|
||||
}
|
||||
|
||||
public ref struct CompRef<T> : IQueryTypeParameter
|
||||
public ref struct CompRef<T> : IQueryTypeParameter<T>
|
||||
where T : IComponentData
|
||||
{
|
||||
internal ref T _value;
|
||||
@@ -42,7 +43,7 @@ public ref struct CompRef<T> : IQueryTypeParameter
|
||||
}
|
||||
}
|
||||
|
||||
public ref struct CompRO<T> : IQueryTypeParameter
|
||||
public readonly ref struct CompRO<T> : IQueryTypeParameter<T>
|
||||
where T : IComponentData
|
||||
{
|
||||
internal readonly ref T _value;
|
||||
|
||||
Reference in New Issue
Block a user