Search Unity

  1. Get all the Unite Berlin 2018 news on the blog.
    Dismiss Notice
  2. Unity 2018.2 has arrived! Read about it here.
    Dismiss Notice
  3. Improve your Unity skills with a certified instructor in a private, interactive classroom. Learn more.
    Dismiss Notice
  4. ARCore is out of developer preview! Read about it here.
    Dismiss Notice
  5. Magic Leap’s Lumin SDK Technical Preview for Unity lets you get started creating content for Magic Leap One™. Find more information on our blog!
    Dismiss Notice
  6. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

How to get an Entity in IJobProcessComponentData?

Discussion in 'Entity Component System and C# Job system' started by 5argon, May 22, 2018.

  1. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    382
    I like the convenience of `IJobProcessComponentData`, but often I would like to use the Entity ID that host the component data that is coming in via `ref` argument. Any way to get it?

    (Seeing that we can do `EntityArray` in struct component group I guess this might be possible "naturally", in some ways)

    It is the biggest pain point when I want to remove/add some component tags along the way in a job along with `EntityCommandBuffer` generated from a `BarrierSystem` before starting the job. Only this prevents me from using `IJobProcessComponentData` in many more places in my game.

    This is not possible as `Entity` is not an `IComponentData`
    Code (CSharp):
    1. struct Job : IJobProcessComponentData<SomeComponentData,Entity>
     
    Last edited: May 22, 2018
  2. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    157
    dirty workaround (pseudocode):
    Code (CSharp):
    1. struct Self : IComponentData { public Entity value; }
    2.  
    3. struct Job1 : IJob {
    4.     [ReadOnly] public EntityArray entities;
    5.     [WriteOnly] public ComponentDataFromEntity<Self> self;
    6.     void Execute() { foreach (var e in entities) self[e] = new Self{value = e}; } // or add component
    7. }
    8. struct Job2 : IJobProcessComponentData<SomeComponentData,Self>{...}
     
    starikcetin likes this.
  3. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    382
    Thank you, I get your idea!

    But unfortunately just now I encountered a more serious problem about `EntityCommandBuffer` (used with parallel job) :

    When I do add `[ReadOnly]` to `EntityCommandBuffer` now I can't even use `.AddComponent` :

    `.AddComponent` is "writing" it seems?

    The concept of `EntityCommandBuffer` is to queue up for execution together "later", so I expect no reason that concurrent command queuing would be invalid.. maybe the only way to use command buffer (in a job) is via a single threaded job?
     
  4. Cyberwiz15

    Cyberwiz15

    Joined:
    Nov 10, 2016
    Posts:
    45
    From what I understand the EntityCommandBuffer is nothing more than a buffer of commands to be executed on an entity. The current api allows for creating an entity and then adding/setting component values on the entity without specifying which entity this will be set on. In this case it's important for the buffer to execute commands in order. Writing to the buffer in parallel would thus mean some commands could get mixed up.

    There's also methods to specify the entity you're writing to and if you're altering/adding more than one component one would ideally want to bundle these together as to not have to jump back and forth in memory if parallel writes had cause these to be split up as well.

    I believe this the reason to be why it currently does not support writes from Parallel jobs.

    Please don't misinterpret the [ReadOnly] attribute. It's not meant to "bypass" the error that you get at the start, it's more to help the JobSystem better handle parallel jobs. Some data-structures aren't thread-safe, but they can be read from without having race conditions. So if you're decorating the EntityCommandBuffer field with [ReadOnly] you're implying that your job is only planning to read from that structure, in which case the JobSystem can smartly schedule the jobs in such a way that writes won't cause race conditions.

    There might be a way to get around this, but that would entail having a buffer for each possible thread this would run on. After some digging I've found that adding the ENABLE_UNITY_COLLECTIONS_CHECKS symbol in Unity should disable these checks, but that would mean you'd have to find a way to create a buffer for each thread in order to not have strange behaviour when the job does execute.

    The other way would be to do this type of work in a single threaded job as you've mentioned.

    EDIT: Please do not that specifying ENABLE_UNITY_COLLECTIONS_CHECKS will take the training wheels off with regards to the JobSystem checking for incorrect job schedules. Do this only if you have a good understanding of how you'll be writing to collections.
     
    Last edited: May 22, 2018
    5argon likes this.
  5. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    3,922
    Currently EntityCommandBuffer can only be used from IJob.
     
    avvie and 5argon like this.
  6. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    382
    @Cyberwiz15 Thanks for the explanation!!

    Ok, I will keep it in mind while selecting job types.