How to get ComponentDataFromEntity to a parallel job in Unity ECS?

3.9k Views Asked by At

I am trying to acces entity component data in a parallel job. The component data is of type PheromoneComponent. The struct that defines the job looks like this:

[UpdateBefore(typeof(PheromoneTrailsSystem))]
public class MovementSystem : JobComponentSystem
{
private EndSimulationEntityCommandBufferSystem endSimulationEntityCommandBuffer;


protected override void OnCreate()
{
    endSimulationEntityCommandBuffer = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
    base.OnCreate();
}


[BurstCompile]
struct MovementSpeedJob : IJobForEachWithEntity<Translation,Rotation, MovementComponent, QuadrantEntity, AntComponent>
{
    [ReadOnly] public float dT;
    [ReadOnly] public Unity.Mathematics.Random randGenerator;
    [ReadOnly] public long currentTimestamp;
    [ReadOnly] public int mapSizeHeight;
    [ReadOnly] public int mapSizeWidth;
    [ReadOnly] public NativeMultiHashMap<int, QuadrantData> quadrantMultiHashMap;
    [ReadOnly] public ComponentDataFromEntity<PheromoneComponent> pheromoneDataArray;
    //[NativeDisableParallelForRestriction] ComponentDataFromEntity<PheromoneComponent> 
    pheromoneDataArray;



    public EntityCommandBuffer.Concurrent entityCommandBuffer;

    public void Execute(Entity entity, int index, ref Translation translation, ref Rotation 
    rotation, ref MovementComponent movementComponent, ref QuadrantEntity quadrantEntity, 
    ref AntComponent antComponent){......}

The job is executed with the following instantiations:

protected override JobHandle OnUpdate(JobHandle inputDeps)
{
    var job = new MovementSpeedJob()
    {
        dT = Time.deltaTime,
        randGenerator = new 
        Unity.Mathematics.Random((uint)UnityEngine.Random.Range(1,100000)),
        currentTimestamp = DateTime.Now.Ticks,
        mapSizeHeight = GameState.GetMapSizeHeight(),
        mapSizeWidth = GameState.GetMapSizeWidth(),
        quadrantMultiHashMap = QuadrantSystem.quadrantMultiHashMap,
        entityCommandBuffer = 
        endSimulationEntityCommandBuffer.CreateCommandBuffer().ToConcurrent(),
        pheromoneDataArray = GetComponentDataFromEntity<PheromoneComponent>(true)


    };

    JobHandle jobHandle = job.Schedule(this, inputDeps);

    endSimulationEntityCommandBuffer.AddJobHandleForProducer(jobHandle);

    return jobHandle;

The code runs but I am getting the following error messages everytime update is called:

InvalidOperationException: The native container has been declared as [WriteOnly] in the job, 
but you are reading from it.
Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckReadAndThrowNoEarlyOut (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) <0x1ba8eccc0 + 0x00052> in <85963591c1a04aad836445db604e7807>:0
Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckReadAndThrow (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) (at /Users/builduser/buildslave/unity/build/Runtime/Export/Jobs/AtomicSafetyHandle.bindings.cs:148)
Unity.Entities.ComponentJobSafetyManager.CompleteWriteDependency (System.Int32 type) (at Library/PackageCache/[email protected]/Unity.Entities/ComponentJobManager.cs:386)
Unity.Entities.EntityManager.GetComponentData[T] (Unity.Entities.Entity entity) (at Library/PackageCache/[email protected]/Unity.Entities/EntityManagerAccessComponentData.cs:42)
AntBehaviourSystem+ExcretionJob.Execute (Unity.Transforms.Translation& translation, Unity.Transforms.Rotation& rotation, QuadrantEntity& quadrantEntity, AntComponent& antComponent) (at Assets/Scripts/Ant/Systems/AntBehaviourSystem.cs:39)
Unity.Entities.JobForEachExtensions+JobStruct_Process_CCCC`5[T,T0,T1,T2,T3].ExecuteChunk (Unity.Entities.JobForEachExtensions+JobStruct_Process_CCCC`5[T,T0,T1,T2,T3]& jobData, System.IntPtr bufferRangePatchData, System.Int32 begin, System.Int32 end, Unity.Entities.ArchetypeChunk* chunks, System.Int32* entityIndices) (at Library/PackageCache/[email protected]/Unity.Entities/IJobForEach.gen.cs:3576)
Unity.Entities.JobForEachExtensions+JobStruct_Process_CCCC`5[T,T0,T1,T2,T3].Execute (Unity.Entities.JobForEachExtensions+JobStruct_Process_CCCC`5[T,T0,T1,T2,T3]& jobData, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, Unity.Jobs.LowLevel.Unsafe.JobRanges& ranges, System.Int32 jobIndex) (at Library/PackageCache/[email protected]/Unity.Entities/IJobForEach.gen.cs:3541)

Since I never explicitly define the ComponentDataFromEntity as [WriteOnly] this error seems to say that there are some conflicts in the paralel job. Am I even passing ComponentDataFromEntity correctly? Are there any other pitfalls that I am not aware of? I have some other jobs that operate on PheromoneComponent but i have tried disabeling them and the error persist. Also I guess the ECS job system should take care that all job dependancies are completed before executing another job.

I have also tried with [NativeDisableParallelForRestriction] ComponentDataFromEntity<PheromoneComponent> instead of [ReadOnly] public ComponentDataFromEntity<PheromoneComponent> pheromoneDataArray; but no change.

Any help or explanation will be greatly appreciated!

1

There are 1 best solutions below

0
On

Edit (Solution): In my case, the issue was a conflict with a custom ReadOnly attribute I had in my project. I got rid of my custom attribute and everything works now.

I'm having the same issue and started a Unity forum thread, which has received as much attention as this question, sadly.

https://forum.unity.com/threads/readonly-errors-when-trying-to-use-componentdatafromentity.824799/

I'm starting to suspect that ComponentDataFromEntity just isn't supported inside ForEach jobs, but can't confirm it personally and don't know who can.