Search Unity

Resolved ComponentDataFromEntity dependency tracking and completing JobHandles

Discussion in 'Entity Component System' started by Rupture13, Dec 23, 2021.

  1. Rupture13

    Rupture13

    Joined:
    Apr 12, 2016
    Posts:
    131
    Aloha,

    I've noticed that for getting data from a singleton entity in a SystemBase to pass to a job, rewriting a
    [GetComponentData<T>(singletonEntity) and passing the componentData to the job] situation
    to a
    [GetComponentDataFromEntity<T>() and passing that struct and the singletonEntity to the job] situation
    results in fewer JobHandles.Completes being performed.

    My theory was that the actual access of the ComponentData does not happen on the main thread due to the rewrite, and therefore it doesn't have to do the JobHandle.Complete (or at least not until the job runs).

    However, in the manual, it is stated that
    (https://docs.unity3d.com/Packages/com.unity.entities@0.17/manual/ecs_job_dependencies.html)

    The ComponentDataFromEntity struct is described as a "native container" in the documentation. Does that mean that the ComponentDataFromEntity struct is one of those "other similar containers"?

    I'm worried now that my theory was wrong and the reason it results in fewer JobHandle.Completes is actually because the component dependencies between systems aren't properly tracked.

    So my questions are:
    • Can anyone shed some light on this?
    • Are the dependencies for the components in ComponentDataFromEntity properly tracked between systems and their corresponding jobs?
    • Why does GetComponentDataFromEntity produce fewer JobHandle.Completes compared to GetComponent (on the main thread)?
     
  2. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    Yes.
    GetComponentData needs to Complete all jobs that previously required write access to that ComponentData to avoid race conditions.
    GetComponentDataFromEntity doesn't. I am not fully familiar with the source code to explain exactly why, but I suspect that GetComponentDataFromEntity returns just a handle that is lazily evaluated at some point (between frames or between jobs, don't know exactly).
     
    Rupture13 likes this.
  3. Tony_Max

    Tony_Max

    Joined:
    Feb 7, 2017
    Posts:
    353
    wait what?! i thought that GetComponent is some sort of sugar and under the hood behaves like ComponentDataFromEntity
     
  4. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    I thought we were talking about using preparing to schedule a Job, not using Entities.ForEach
     
  5. Tony_Max

    Tony_Max

    Joined:
    Feb 7, 2017
    Posts:
    353
    what the difference between getting data before scheduling a job and getting data during ForEach?
     
  6. Rupture13

    Rupture13

    Joined:
    Apr 12, 2016
    Posts:
    131
    • A GetComponent inside a Scheduled or ScheduledParallel job converts it to a ComponentDataFromEntity access under the hood.
    • A GetComponent inside a Run job or outside of a job converts to an EntityManager.GetComponentData.
     
    brunocoimbra and xVergilx like this.
  7. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Because in the case of CDFE you do not access data in any way (read\write) calling GetCDFE push type to reader\writer fence for proper dependency tracking and provides you "lookup" (roughly speaking) which is just a struct with type index, safety handle and a pointer to entity component store which is exact place through which actual data will be accessed (and couple other utility fields). As result, there is no need to complete any dependencies (well technically it does once per type when type is pushed to fence the first time). And then you safely access data based on dependency chain inside jobs. But in case of GetSingleton\EntityMananger.GetComponentData, as was already pointed above - the system needs to complete previous write dependency to that type, for getting proper data at call time.