Skip to content

Instantly share code, notes, and snippets.

@Defunctionalize
Last active July 15, 2020 10:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Defunctionalize/9a5bf89dae26ae8016ead1e1128b0bc5 to your computer and use it in GitHub Desktop.
Save Defunctionalize/9a5bf89dae26ae8016ead1e1128b0bc5 to your computer and use it in GitHub Desktop.
non working combinatorial approach to multithreading. see comments for link to working, though less parallel, version
using System.Linq;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
public struct MyComponent : IComponentData
{
public float threshold;
public bool closeEnough;
}
public class CheckAllPairsSystem : SystemBase
{
[BurstCompile]
struct CheckAllPairsJob : IJobParallelFor
{
[DeallocateOnJobCompletion] public NativeArray<ArchetypeChunk> Chunks;
[DeallocateOnJobCompletion] public NativeArray<int2> Combos;
public ArchetypeChunkComponentType<Translation> TranslationType;
[ReadOnly] public ArchetypeChunkComponentType<MyComponent> MyComponentType;
public void Execute(int comboIndex)
{
var combo = Combos[comboIndex];
var chunk = Chunks[combo.x];
var chunk2 = Chunks[combo.y];
var translations = chunk.GetNativeArray(TranslationType);
var translations2 = chunk2.GetNativeArray(TranslationType);
var mycomponents = chunk.GetNativeArray(MyComponentType);
var mycomponents2 = chunk2.GetNativeArray(MyComponentType);
var instanceCount = chunk.Count;
var instanceCount2 = chunk2.Count;
for (int i = 0; i < instanceCount; i++)
{
for (int j = 0; j < instanceCount2; j++)
{
// if checking against the same chunk, dont check against the same index,
// because that would be the same entity
if (combo.x == combo.y && i == j) { continue; }
var a = mycomponents[i];
var aTrans = translations[i];
var b = mycomponents2[j];
var bTrans = translations2[j];
var distance = math.distance(aTrans.Value, bTrans.Value);
a.closeEnough = a.closeEnough || distance < a.threshold;
b.closeEnough = b.closeEnough || distance < b.threshold;
}
}
}
}
EntityQuery query;
protected override void OnCreate()
{
query = GetEntityQuery(typeof(MyComponent), ComponentType.ReadOnly<Translation>());
}
protected override void OnUpdate()
{
var translationType = GetArchetypeChunkComponentType<Translation>(true);
var myComponentType = GetArchetypeChunkComponentType<MyComponent>();
var chunks = query.CreateArchetypeChunkArray(Allocator.TempJob);
var comboSeq = (
from i in Enumerable.Range(0, chunks.Length)
from j in Enumerable.Range(0, chunks.Length)
select new int2(i, j)).ToArray();
var combos = new NativeArray<int2>(comboSeq.Length, Allocator.TempJob);
combos.CopyFrom(comboSeq);
var checkAlignedJob = new CheckAllPairsJob()
{
Chunks = chunks,
Combos = combos,
MyComponentType = myComponentType,
TranslationType = translationType
};
checkAlignedJob.Schedule(combos.Length,32, this.Dependency);
}
}
@Defunctionalize
Copy link
Author

I'm not necessarily saying this is an appropriate choice for implementing this in a game, but would this work?
It seems like this is adhering to all the constraints of the Burst compiler.

Points of note:
My job stuct execute function is indexing into 2 chunks in memory instead of one -- will that screw anything up? Will this still be fast?
Will the sub batching logic (chunk.Count is a subbatch) screw up this plan? Is this actually guaranteed to check all pairs of entities?
Is there anything better I can be doing than those duplicated variables (translations, translations2 etc)? I'm scared of breaking Burst..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment