Added ScheduleEntityParallel and IJobEntityParallel for parallel querying
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Misaki.HighPerformance" Version="1.0.1" />
|
<PackageReference Include="Misaki.HighPerformance" Version="1.0.1" />
|
||||||
|
<PackageReference Include="Misaki.HighPerformance.Jobs" Version="1.1.0" />
|
||||||
<PackageReference Include="Misaki.HighPerformance.LowLevel" Version="1.2.8" />
|
<PackageReference Include="Misaki.HighPerformance.LowLevel" Version="1.2.8" />
|
||||||
<PackageReference Include="Misaki.HighPerformance.Mathematics" Version="1.2.6" />
|
<PackageReference Include="Misaki.HighPerformance.Mathematics" Version="1.2.6" />
|
||||||
<PackageReference Include="System.IO.Hashing" Version="10.0.0" />
|
<PackageReference Include="System.IO.Hashing" Version="10.0.0" />
|
||||||
|
|||||||
@@ -1,15 +1,28 @@
|
|||||||
using Ghost.Test.Core;
|
using Ghost.Test.Core;
|
||||||
|
using Misaki.HighPerformance.Jobs;
|
||||||
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ghost.Entities.Test;
|
namespace Ghost.Entities.Test;
|
||||||
|
|
||||||
|
internal struct TestEntityQueryJob : IJobEntityParallel<Transform>
|
||||||
|
{
|
||||||
|
public readonly void Execute(Entity entity, ref Transform transform)
|
||||||
|
{
|
||||||
|
transform.position += new float3(10, 10, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public partial class ArcEntityTest : ITest
|
public partial class ArcEntityTest : ITest
|
||||||
{
|
{
|
||||||
private World _world = null!;
|
private World _world = null!;
|
||||||
|
private JobScheduler _jobScheduler = null!;
|
||||||
|
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
_world = World.Create();
|
_world = World.Create();
|
||||||
|
_jobScheduler = new JobScheduler(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Run()
|
public void Run()
|
||||||
@@ -20,23 +33,27 @@ public partial class ArcEntityTest : ITest
|
|||||||
var queryID = new QueryBuilder().WithAll<Transform>().Build(_world);
|
var queryID = new QueryBuilder().WithAll<Transform>().Build(_world);
|
||||||
ref var query = ref _world.GetEntityQueryReference(queryID);
|
ref var query = ref _world.GetEntityQueryReference(queryID);
|
||||||
|
|
||||||
query.ForEach<Transform>((ref t) =>
|
var testJob = new TestEntityQueryJob();
|
||||||
|
var handle = query.ScheduleEntityParallel<TestEntityQueryJob, Transform>(_jobScheduler, testJob, Allocator.Temp, 64, JobHandle.Invalid);
|
||||||
|
_jobScheduler.WaitComplete(handle);
|
||||||
|
|
||||||
|
query.ForEach<Transform>((e, ref t) =>
|
||||||
{
|
{
|
||||||
t.position = new float3(1, 2, 3);
|
Console.WriteLine($"Entity {e} Has Position: {t.position}");
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach (var chunk in query.GetChunkIterator())
|
//foreach (var chunk in query.GetChunkIterator())
|
||||||
{
|
//{
|
||||||
var transforms = chunk.GetComponentData<Transform>();
|
// var transforms = chunk.GetComponentData<Transform>();
|
||||||
var entities = chunk.GetEntities();
|
// var entities = chunk.GetEntities();
|
||||||
var bits = chunk.GetEnableBits<Transform>();
|
// var bits = chunk.GetEnableBits<Transform>();
|
||||||
|
|
||||||
var it = bits.GetIterator();
|
// var it = bits.GetIterator();
|
||||||
while (it.Next(out var index) && index < chunk.Count)
|
// while (it.Next(out var index) && index < chunk.Count)
|
||||||
{
|
// {
|
||||||
Console.WriteLine($"Entity {entities[index]} Updated Position: {transforms[index].position}");
|
// Console.WriteLine($"Entity {entities[index]} Updated Position: {transforms[index].position}");
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Cleanup()
|
public void Cleanup()
|
||||||
|
|||||||
@@ -52,6 +52,10 @@
|
|||||||
<LastGenOutput>ForEach.gen.cs</LastGenOutput>
|
<LastGenOutput>ForEach.gen.cs</LastGenOutput>
|
||||||
<Generator>TextTemplatingFileGenerator</Generator>
|
<Generator>TextTemplatingFileGenerator</Generator>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="Templates\EntityQuery.JobEntityParallel.tt">
|
||||||
|
<Generator>TextTemplatingFileGenerator</Generator>
|
||||||
|
<LastGenOutput>EntityQuery.JobEntityParallel.gen.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
<None Update="Templates\QueryBuilder.With.tt">
|
<None Update="Templates\QueryBuilder.With.tt">
|
||||||
<Generator>TextTemplatingFileGenerator</Generator>
|
<Generator>TextTemplatingFileGenerator</Generator>
|
||||||
<LastGenOutput>QueryBuilder.With.gen.cs</LastGenOutput>
|
<LastGenOutput>QueryBuilder.With.gen.cs</LastGenOutput>
|
||||||
@@ -68,6 +72,11 @@
|
|||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
<DependentUpon>EntityQuery.ForEach.tt</DependentUpon>
|
<DependentUpon>EntityQuery.ForEach.tt</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Update="Templates\EntityQuery.JobEntityParallel.gen.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>EntityQuery.JobEntityParallel.tt</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Update="Templates\ForEach.gen.cs">
|
<Compile Update="Templates\ForEach.gen.cs">
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
|
|||||||
@@ -231,37 +231,37 @@ public unsafe partial struct EntityQuery : IIdentifierType, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Identifier<World> _worldID;
|
|
||||||
private UnsafeList<Identifier<Archetype>> _matchingArchetypes;
|
|
||||||
|
|
||||||
internal EntityQueryMask _mask;
|
internal EntityQueryMask _mask;
|
||||||
|
|
||||||
internal EntityQuery(Identifier<World> worldID, EntityQueryMask mask)
|
private UnsafeList<Identifier<Archetype>> _matchingArchetypes;
|
||||||
|
private readonly Identifier<EntityQuery> _id;
|
||||||
|
private readonly Identifier<World> _worldID;
|
||||||
|
|
||||||
|
internal EntityQuery(Identifier<EntityQuery> id, Identifier<World> worldID, EntityQueryMask mask)
|
||||||
{
|
{
|
||||||
|
_id = id;
|
||||||
_worldID = worldID;
|
_worldID = worldID;
|
||||||
_mask = mask;
|
_mask = mask;
|
||||||
_matchingArchetypes = new UnsafeList<Identifier<Archetype>>(8, Allocator.Persistent);
|
_matchingArchetypes = new UnsafeList<Identifier<Archetype>>(8, Allocator.Persistent);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static bool IsEntityValid(byte* chunkBase, int entityIndex, ref readonly Archetype archetype, ref readonly EntityQueryMask mask)
|
private static bool IsEntityValid(byte* chunkBase, int entityIndex, ref readonly Archetype archetype, ref readonly EntityQueryMask mask)
|
||||||
{
|
{
|
||||||
// 1. Check "Require Enabled" (WithAll)
|
// 1. Check "Require Enabled" (WithAll)
|
||||||
// We iterate over the bits set in 'requireEnabled'
|
|
||||||
var it = mask.requireEnabled.GetIterator();
|
var it = mask.requireEnabled.GetIterator();
|
||||||
|
|
||||||
while (it.Next(out var id))
|
while (it.Next(out var id))
|
||||||
{
|
{
|
||||||
// Get the EnableBitmask for this component in this chunk
|
// Get the EnableBitmask for this component in this chunk
|
||||||
var layout = archetype.GetLayout(id).Value;
|
var layoutResult = archetype.GetLayout(id);
|
||||||
if (layout.enableBitsOffset == -1)
|
if (layoutResult.Status != ResultStatus.Success
|
||||||
{
|
|
||||||
// Not enableable, always true
|
// Not enableable, always true
|
||||||
|
|| layoutResult.Value.enableBitsOffset == -1)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check bit
|
// Check bit
|
||||||
if (!CheckBit(chunkBase + layout.enableBitsOffset, entityIndex))
|
if (!CheckBit(chunkBase + layoutResult.Value.enableBitsOffset, entityIndex))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -271,17 +271,18 @@ public unsafe partial struct EntityQuery : IIdentifierType, IDisposable
|
|||||||
it = mask.requireDisabled.GetIterator();
|
it = mask.requireDisabled.GetIterator();
|
||||||
while (it.Next(out var id))
|
while (it.Next(out var id))
|
||||||
{
|
{
|
||||||
var layout = archetype.GetLayout(id).Value;
|
var layoutResult = archetype.GetLayout(id);
|
||||||
|
if (layoutResult.Status != ResultStatus.Success)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// If component is not enableable, it is technically "Always Enabled",
|
// If component is not enableable, it is technically "Always Enabled",
|
||||||
// so it cannot satisfy "WithDisabled".
|
// so it cannot satisfy "WithDisabled".
|
||||||
if (layout.enableBitsOffset == -1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check bit (Must be 0)
|
// Check bit (Must be 0)
|
||||||
if (CheckBit(chunkBase + layout.enableBitsOffset, entityIndex))
|
if (layoutResult.Value.enableBitsOffset == -1
|
||||||
|
|| CheckBit(chunkBase + layoutResult.Value.enableBitsOffset, entityIndex))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -294,19 +295,15 @@ public unsafe partial struct EntityQuery : IIdentifierType, IDisposable
|
|||||||
var layoutResult = archetype.GetLayout(id);
|
var layoutResult = archetype.GetLayout(id);
|
||||||
if (layoutResult.Status != ResultStatus.Success)
|
if (layoutResult.Status != ResultStatus.Success)
|
||||||
{
|
{
|
||||||
// Component is absent, so it is not enabled.
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If component is not enableable, it is technically "Always Enabled",
|
// If component is not enableable, it is technically "Always Enabled",
|
||||||
// so it cannot satisfy "Reject if Enabled".
|
// so it cannot satisfy "Reject if Enabled".
|
||||||
if (layoutResult.Value.enableBitsOffset == -1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check bit (Must be 0)
|
// Check bit (Must be 0)
|
||||||
if (CheckBit(chunkBase + layoutResult.Value.enableBitsOffset, entityIndex))
|
if (layoutResult.Value.enableBitsOffset == -1
|
||||||
|
|| CheckBit(chunkBase + layoutResult.Value.enableBitsOffset, entityIndex))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -316,7 +313,7 @@ public unsafe partial struct EntityQuery : IIdentifierType, IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool CheckBit(byte* maskBase, int index)
|
internal static bool CheckBit(byte* maskBase, int index)
|
||||||
{
|
{
|
||||||
var byteIndex = index >> Chunk.BIT_SHIFT;
|
var byteIndex = index >> Chunk.BIT_SHIFT;
|
||||||
var bitIndex = index & Chunk.BIT_ALIGNMENT_MINUS_ONE;
|
var bitIndex = index & Chunk.BIT_ALIGNMENT_MINUS_ONE;
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
|
var pComp0 = (T0*)(basePtrs[0] + (sizeof(T0) * entityIndex));
|
||||||
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
|
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
|
||||||
|
|
||||||
action(ref *pComp0,ref *pComp1);
|
action(ref *pComp0, ref *pComp1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
|
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
|
||||||
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
|
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
|
||||||
|
|
||||||
action(ref *pComp0,ref *pComp1,ref *pComp2);
|
action(ref *pComp0, ref *pComp1, ref *pComp2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,7 +231,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
|
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
|
||||||
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
|
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
|
||||||
|
|
||||||
action(ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3);
|
action(ref *pComp0, ref *pComp1, ref *pComp2, ref *pComp3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,7 +294,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
|
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
|
||||||
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
|
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
|
||||||
|
|
||||||
action(ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4);
|
action(ref *pComp0, ref *pComp1, ref *pComp2, ref *pComp3, ref *pComp4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -359,7 +359,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
|
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
|
||||||
var pComp5 = (T5*)(basePtrs[5] + (sizeof(T5) * entityIndex));
|
var pComp5 = (T5*)(basePtrs[5] + (sizeof(T5) * entityIndex));
|
||||||
|
|
||||||
action(ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4,ref *pComp5);
|
action(ref *pComp0, ref *pComp1, ref *pComp2, ref *pComp3, ref *pComp4, ref *pComp5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -426,7 +426,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp5 = (T5*)(basePtrs[5] + (sizeof(T5) * entityIndex));
|
var pComp5 = (T5*)(basePtrs[5] + (sizeof(T5) * entityIndex));
|
||||||
var pComp6 = (T6*)(basePtrs[6] + (sizeof(T6) * entityIndex));
|
var pComp6 = (T6*)(basePtrs[6] + (sizeof(T6) * entityIndex));
|
||||||
|
|
||||||
action(ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4,ref *pComp5,ref *pComp6);
|
action(ref *pComp0, ref *pComp1, ref *pComp2, ref *pComp3, ref *pComp4, ref *pComp5, ref *pComp6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -495,7 +495,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp6 = (T6*)(basePtrs[6] + (sizeof(T6) * entityIndex));
|
var pComp6 = (T6*)(basePtrs[6] + (sizeof(T6) * entityIndex));
|
||||||
var pComp7 = (T7*)(basePtrs[7] + (sizeof(T7) * entityIndex));
|
var pComp7 = (T7*)(basePtrs[7] + (sizeof(T7) * entityIndex));
|
||||||
|
|
||||||
action(ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4,ref *pComp5,ref *pComp6,ref *pComp7);
|
action(ref *pComp0, ref *pComp1, ref *pComp2, ref *pComp3, ref *pComp4, ref *pComp5, ref *pComp6, ref *pComp7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -609,7 +609,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
|
var pComp1 = (T1*)(basePtrs[1] + (sizeof(T1) * entityIndex));
|
||||||
|
|
||||||
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
||||||
action(*pEntity, ref *pComp0,ref *pComp1);
|
action(*pEntity, ref *pComp0, ref *pComp1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -669,7 +669,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
|
var pComp2 = (T2*)(basePtrs[2] + (sizeof(T2) * entityIndex));
|
||||||
|
|
||||||
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
||||||
action(*pEntity, ref *pComp0,ref *pComp1,ref *pComp2);
|
action(*pEntity, ref *pComp0, ref *pComp1, ref *pComp2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -731,7 +731,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
|
var pComp3 = (T3*)(basePtrs[3] + (sizeof(T3) * entityIndex));
|
||||||
|
|
||||||
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
||||||
action(*pEntity, ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3);
|
action(*pEntity, ref *pComp0, ref *pComp1, ref *pComp2, ref *pComp3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -795,7 +795,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
|
var pComp4 = (T4*)(basePtrs[4] + (sizeof(T4) * entityIndex));
|
||||||
|
|
||||||
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
||||||
action(*pEntity, ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4);
|
action(*pEntity, ref *pComp0, ref *pComp1, ref *pComp2, ref *pComp3, ref *pComp4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -861,7 +861,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp5 = (T5*)(basePtrs[5] + (sizeof(T5) * entityIndex));
|
var pComp5 = (T5*)(basePtrs[5] + (sizeof(T5) * entityIndex));
|
||||||
|
|
||||||
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
||||||
action(*pEntity, ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4,ref *pComp5);
|
action(*pEntity, ref *pComp0, ref *pComp1, ref *pComp2, ref *pComp3, ref *pComp4, ref *pComp5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -929,7 +929,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp6 = (T6*)(basePtrs[6] + (sizeof(T6) * entityIndex));
|
var pComp6 = (T6*)(basePtrs[6] + (sizeof(T6) * entityIndex));
|
||||||
|
|
||||||
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
||||||
action(*pEntity, ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4,ref *pComp5,ref *pComp6);
|
action(*pEntity, ref *pComp0, ref *pComp1, ref *pComp2, ref *pComp3, ref *pComp4, ref *pComp5, ref *pComp6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -999,7 +999,7 @@ public unsafe partial struct EntityQuery
|
|||||||
var pComp7 = (T7*)(basePtrs[7] + (sizeof(T7) * entityIndex));
|
var pComp7 = (T7*)(basePtrs[7] + (sizeof(T7) * entityIndex));
|
||||||
|
|
||||||
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
var pEntity = (Entity*)(pChunkData + archetype.EntityIDsOffset + (sizeof(Entity) * entityIndex));
|
||||||
action(*pEntity, ref *pComp0,ref *pComp1,ref *pComp2,ref *pComp3,ref *pComp4,ref *pComp5,ref *pComp6,ref *pComp7);
|
action(*pEntity, ref *pComp0, ref *pComp1, ref *pComp2, ref *pComp3, ref *pComp4, ref *pComp5, ref *pComp6, ref *pComp7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2103
Ghost.Entities/Templates/EntityQuery.JobEntityParallel.gen.cs
Normal file
2103
Ghost.Entities/Templates/EntityQuery.JobEntityParallel.gen.cs
Normal file
File diff suppressed because it is too large
Load Diff
189
Ghost.Entities/Templates/EntityQuery.JobEntityParallel.tt
Normal file
189
Ghost.Entities/Templates/EntityQuery.JobEntityParallel.tt
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
<#@ template language="C#" #>
|
||||||
|
<#@ output extension="gen.cs" #>
|
||||||
|
<#@ assembly name="System.Core" #>
|
||||||
|
<#@ import namespace="System.Linq" #>
|
||||||
|
<#@ import namespace="System.Text" #>
|
||||||
|
<#@ include file="Helpers.ttinclude" #>
|
||||||
|
using Ghost.Core;
|
||||||
|
using Misaki.HighPerformance.Jobs;
|
||||||
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
|
|
||||||
|
namespace Ghost.Entities;
|
||||||
|
|
||||||
|
<# for (var i = 1; i <= Amount; i++)
|
||||||
|
{
|
||||||
|
var generics = AppendGenerics(i);
|
||||||
|
var restrictions = AppendGenericRestrictionsMultiline(i, "unmanaged, IComponent", 1);
|
||||||
|
#>
|
||||||
|
public interface IJobEntityParallel<<#= generics #>>
|
||||||
|
<#= restrictions #>
|
||||||
|
{
|
||||||
|
void Execute(Entity entity, <#= AppendParameters(i, "ref T{0} component{0}") #>);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal unsafe struct JobEntityBatch<TJob, <#= generics #>> : IJobParallelFor
|
||||||
|
where TJob : unmanaged, IJobEntityParallel<<#= generics #>>
|
||||||
|
<#= restrictions #>
|
||||||
|
{
|
||||||
|
public TJob userJob;
|
||||||
|
|
||||||
|
public UnsafeList<IntPtr> chunks;
|
||||||
|
public UnsafeList<int> chunkCount;
|
||||||
|
public UnsafeList<int> entityOffset;
|
||||||
|
|
||||||
|
<# for (var j = 0; j < i; j++){ #>
|
||||||
|
public UnsafeList<int> offsets<#= j #>;
|
||||||
|
public UnsafeList<int> bitsOffsets<#= j #>;
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
public void Execute(int loopIndex, int threadIndex)
|
||||||
|
{
|
||||||
|
// 1. Get the specific pChunk for this thread
|
||||||
|
var pChunk = (byte*)chunks[loopIndex];
|
||||||
|
var count = chunkCount[loopIndex];
|
||||||
|
|
||||||
|
<# for (var j = 0; j < i; j++){ #>
|
||||||
|
var off<#= j #> = offsets<#= j #>[loopIndex];
|
||||||
|
var enableOff<#= j #> = bitsOffsets<#= j #>[loopIndex];
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
var pEntity = (Entity*)(pChunk + entityOffset[loopIndex]);
|
||||||
|
<# for (var j = 0; j < i; j++){ #>
|
||||||
|
var ptr<#= j #> = (<#= "T" + j #>*)(pChunk + off<#= j #>);
|
||||||
|
<# } #>
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
<# for (var j = 0; j < i; j++){ #>
|
||||||
|
if (enableOff<#= j #> != -1 && !EntityQuery.CheckBit(pChunk + enableOff<#= j #>, i))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
userJob.Execute(pEntity[i], <#= AppendParameters(i, "ref ptr{0}[i]") #>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
public unsafe partial struct EntityQuery
|
||||||
|
{
|
||||||
|
<# for (var i = 1; i <= Amount; i++)
|
||||||
|
{
|
||||||
|
var generics = AppendGenerics(i);
|
||||||
|
var restrictions = AppendGenericRestrictionsMultiline(i, "unmanaged, IComponent", 2);
|
||||||
|
#>
|
||||||
|
private struct DisposeJobEntity<#= i #> : IJob
|
||||||
|
{
|
||||||
|
public UnsafeList<IntPtr> chunkList;
|
||||||
|
public UnsafeList<int> chunkEntityCounts;
|
||||||
|
public UnsafeList<int> entityOffsets;
|
||||||
|
|
||||||
|
<# for (var j = 0; j < i; j++){ #>
|
||||||
|
public UnsafeList<int> offsets<#= j #>;
|
||||||
|
public UnsafeList<int> bitsOffsets<#= j #>;
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
public void Execute(int threadIndex)
|
||||||
|
{
|
||||||
|
chunkList.Dispose();
|
||||||
|
chunkEntityCounts.Dispose();
|
||||||
|
entityOffsets.Dispose();
|
||||||
|
|
||||||
|
<# for (var j = 0; j < i; j++){ #>
|
||||||
|
offsets<#= j #>.Dispose();
|
||||||
|
bitsOffsets<#= j #>.Dispose();
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JobHandle ScheduleEntityParallel<TJob, <#= generics #>>(JobScheduler scheduler, TJob jobData, Allocator allocator, int batchSize, JobHandle dependency)
|
||||||
|
where TJob : unmanaged, IJobEntityParallel<<#= generics #>>
|
||||||
|
<#= restrictions #>
|
||||||
|
{
|
||||||
|
// 1. Flatten the World
|
||||||
|
var chunkList = new UnsafeList<IntPtr>(128, allocator);
|
||||||
|
var chunkEntityCounts = new UnsafeList<int>(128, allocator);
|
||||||
|
var entityOffsets = new UnsafeList<int>(128, allocator);
|
||||||
|
|
||||||
|
<# for (var j = 0; j < i; j++){ #>
|
||||||
|
var offsets<#= j #> = new UnsafeList<int>(128, allocator);
|
||||||
|
var bitsOffsets<#= j #> = new UnsafeList<int>(128, allocator);
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
// Iterate the Query's matching archetypes
|
||||||
|
foreach (var archID in _matchingArchetypes)
|
||||||
|
{
|
||||||
|
ref var arch = ref World.GetWorld(_worldID)
|
||||||
|
.GetValueOrThrow(ResultStatus.Success)
|
||||||
|
.GetArchetypeReference(archID);
|
||||||
|
|
||||||
|
if (arch.ChunkCount == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get offsets ONCE per archetype
|
||||||
|
<# for (var j = 0; j < i; j++){ #>
|
||||||
|
var layout<#= j #> = arch.GetLayout(ComponentTypeID<T<#= j #>>.value)
|
||||||
|
.GetValueOrThrow(ResultStatus.Success);
|
||||||
|
<# } #>
|
||||||
|
|
||||||
|
// Add all chunks from this archetype
|
||||||
|
for (var i = 0; i < arch.ChunkCount; i++)
|
||||||
|
{
|
||||||
|
ref var chunkRef = ref arch.GetChunkReference(i);
|
||||||
|
|
||||||
|
chunkList.Add((IntPtr)chunkRef.GetUnsafePtr());
|
||||||
|
chunkEntityCounts.Add(chunkRef.Count);
|
||||||
|
entityOffsets.Add(arch.EntityIDsOffset);
|
||||||
|
|
||||||
|
<# for (var j = 0; j < i; j++){ #>
|
||||||
|
offsets<#= j #>.Add(layout<#= j #>.offset);
|
||||||
|
bitsOffsets<#= j #>.Add(layout<#= j #>.enableBitsOffset);
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Create the Runner
|
||||||
|
var runner = new JobEntityBatch<TJob, <#= generics #>>
|
||||||
|
{
|
||||||
|
userJob = jobData,
|
||||||
|
chunks = chunkList,
|
||||||
|
chunkCount = chunkEntityCounts,
|
||||||
|
entityOffset = entityOffsets,
|
||||||
|
|
||||||
|
<# for (var j = 0; j < i; j++){ #>
|
||||||
|
offsets<#= j #> = offsets<#= j #>,
|
||||||
|
bitsOffsets<#= j #> = bitsOffsets<#= j #>,
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
};
|
||||||
|
|
||||||
|
var jobHandle = scheduler.ScheduleParallel(ref runner, chunkList.Count, batchSize, dependency);
|
||||||
|
|
||||||
|
// 3. Dispose the temp lists
|
||||||
|
var disposeJob = new DisposeJobEntity<#= i #>
|
||||||
|
{
|
||||||
|
chunkList = chunkList,
|
||||||
|
chunkEntityCounts = chunkEntityCounts,
|
||||||
|
entityOffsets = entityOffsets,
|
||||||
|
|
||||||
|
<# for (var j = 0; j < i; j++){ #>
|
||||||
|
offsets<#= j #> = offsets<#= j #>,
|
||||||
|
bitsOffsets<#= j #> = bitsOffsets<#= j #>,
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
};
|
||||||
|
|
||||||
|
scheduler.Schedule(ref disposeJob, jobHandle);
|
||||||
|
|
||||||
|
return jobHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
if (i > 0) sb.Append(", ");
|
if (i > 0) sb.Append(", ");
|
||||||
sb.Append(string.Format(template, i));
|
sb.Append(string.Format(template, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,27 +28,18 @@
|
|||||||
return AppendGenerics(amount, "T{0}");
|
return AppendGenerics(amount, "T{0}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public StringBuilder AppendGenericRefParameters(int amount)
|
public StringBuilder AppendParameters(int amount, string template)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
for (var localIndex = 0; localIndex < amount; localIndex++)
|
for (var localIndex = 0; localIndex < amount; localIndex++)
|
||||||
{
|
{
|
||||||
sb.Append($"ref T{localIndex} t{localIndex}Component,");
|
sb.Append(string.Format(template, localIndex));
|
||||||
|
if (localIndex < amount - 1)
|
||||||
|
{
|
||||||
|
sb.Append(", ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.Length--;
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringBuilder AppendRefParameters(int amount, string template)
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
for (var localIndex = 0; localIndex < amount; localIndex++)
|
|
||||||
{
|
|
||||||
sb.Append($"ref {string.Format(template, localIndex)},");
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.Length--;
|
|
||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +54,7 @@
|
|||||||
sb.Append(' ');
|
sb.Append(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +76,7 @@
|
|||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,6 +96,7 @@
|
|||||||
sb.Append(" && ");
|
sb.Append(" && ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +111,7 @@
|
|||||||
sb.Append(" && ");
|
sb.Append(" && ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +126,7 @@
|
|||||||
sb.Append(", ");
|
sb.Append(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,6 +141,7 @@
|
|||||||
sb.Append(", ");
|
sb.Append(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
#>
|
#>
|
||||||
@@ -148,7 +148,7 @@ public partial class World : IIdentifierType, IDisposable, IEquatable<World>
|
|||||||
internal Identifier<EntityQuery> CreateEntityQuery(EntityQueryMask mask, int maskHash)
|
internal Identifier<EntityQuery> CreateEntityQuery(EntityQueryMask mask, int maskHash)
|
||||||
{
|
{
|
||||||
var queryID = new Identifier<EntityQuery>(_entityQueries.Count);
|
var queryID = new Identifier<EntityQuery>(_entityQueries.Count);
|
||||||
_entityQueries.Add(new EntityQuery(_id, mask));
|
_entityQueries.Add(new EntityQuery(queryID, _id, mask));
|
||||||
_querieLookup.Add(maskHash, queryID);
|
_querieLookup.Add(maskHash, queryID);
|
||||||
|
|
||||||
ref var query = ref _entityQueries[queryID.value];
|
ref var query = ref _entityQueries[queryID.value];
|
||||||
|
|||||||
@@ -16,6 +16,12 @@
|
|||||||
<IsTrimmable>True</IsTrimmable>
|
<IsTrimmable>True</IsTrimmable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="RenderGraphModule\**" />
|
||||||
|
<EmbeddedResource Remove="RenderGraphModule\**" />
|
||||||
|
<None Remove="RenderGraphModule\**" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="runtime\win-x64\native\dxcompiler.dll" />
|
<None Remove="runtime\win-x64\native\dxcompiler.dll" />
|
||||||
<None Remove="runtime\win-x64\native\dxil.dll" />
|
<None Remove="runtime\win-x64\native\dxil.dll" />
|
||||||
@@ -48,8 +54,4 @@
|
|||||||
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
|
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="RenderGraphModule\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user