Search Unity

Adding a Blittable SharedComponentData that can be accessed in Jobs

Discussion in 'Entity Component System' started by Opeth001, Jun 14, 2019.

  1. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,117
    it will be Awesome if Unity add's a new Blittable SharedComponentData Type that can be used to Divide Entities in different chunks like the SCD but with the possibility to access it in Jobs at least for readOnly.

    in some cases systems will try to iterate over Huge numbers of entities that need to be separated via SCD which values are generated at runtime and the Data Contained still Blittable and for the moment it's not possible to add/read them inside jobs.

    it can be really usefull.
     
  2. Justin_Larrabee

    Justin_Larrabee

    Joined:
    Apr 24, 2018
    Posts:
    106
    I think this could be better solved by allowing more control over how the ECS job scheduler parallelizes IJobForEach. For heavy-weight jobs, it would be great to provide a suggested batch size, instead of assuming that per-chunk is ideal. Using SCD to split entities across chunks can very easily lead to a situation where you have one Entity per-chunk (for instance if you have more than one system using SCD to load balance).
     
    Opeth001 likes this.
  3. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,117
    i agree with you on adding a batch size param to the IJobForEach can give more freedom to the programmer to tweak for the perfect Entity count that need to be processed in each thread. but the IJobForEach is not assuming that per-chunk is ideal, that's what the IJobChunk is doing. but i still dont see how this can solve the problem of setting Blittable SCD inside Jobs.
    i think that everyone here is attracted to ECS for the same reason : Perfomance & Scalablity! this means a huge amount of entities ( probably millions), actually using SCD and Component TAGs to split those entities across chunks is good practice to make systems quickly found and iterate over them based on their Chunks. if this practice leads someone to a situation where he has one Entity per-chunk, that means the system is badly designed.
     
  4. RecursiveEclipse

    RecursiveEclipse

    Joined:
    Sep 6, 2018
    Posts:
    298
    Both of what you're asking is currently possible, though not necessarily as easy/simple as IJobForEach.

    You can pass an array/hashmap of ISharedComponentData to a job, as ISharedComponentData itself is blittable, this would be ReadOnly. You can build either one from EntityManager in OnUpdate().

    IJobParallelFor has a batch size argument. You can work with many chunks per batch(NativeArray<ArchetypeChunk>), or all entities depending what level of chunkage you have. Though I'll admit it does take a lot more code to set up.

    IIRC(and looking very briefly at the source again) queries are found on a matching archetype->chunk level, meaning by splitting chunks by changing SCD, you may actually be harming performance. Because, first, the changed entities need to be copied somewhere else, then there are more chunks to collect. Having more archetypes is good for queries(because that's what you're filtering), more chunks is not.

    Here is a function/extension I made a while back to convert SCD to a hashmap of <SCD_index, SCD>, since it still seems to be a PITA to do, you get the indexes from an ArchetypeChunk:

    Code (CSharp):
    1.  
    2. /// <summary>
    3. /// Get all indexes and shared component data of type T as a NativeHashMap.
    4. /// </summary>
    5. /// <typeparam name="T">NativeHashmap(int, T) of (sharedcomponent index, sharedcomponent type T)</typeparam>
    6. public static NativeHashMap<int, T> GetAllUniqueSharedComponentData<T>(
    7. this EntityManager entityManager, Allocator label) where T : struct, ISharedComponentData {
    8.     var componentData = new List<T>();
    9.     var componentSharedIndexes = new List<int>();
    10.     entityManager.GetAllUniqueSharedComponentData(componentData, componentSharedIndexes);
    11.     var result = new NativeHashMap<int, T>(capacity:componentData.Count, label:label);
    12.     for(int i = 0; i < componentSharedIndexes.Count; i++) {
    13.         result.TryAdd(componentSharedIndexes[i], componentData[i]);
    14.     }
    15.     return result;
    16. }
    17.  
     
    Last edited: Jun 15, 2019
    Opeth001 likes this.
  5. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,117
    Thanks @RecursiveEclipse ! that's a nice workaround.

    i think it can be cleaner if unity just create an overload of the
    chunk.GetSharedComponentData(ArchetypeChunkSharedComponentType, EntityManager)

    to be something like:
    chunk.GetSharedComponentData<Blittable_SCD>(ArchetypeChunkSharedComponentType)

    this way it can be directly used inside jobs without collecting all SCD inside a NativeHashMap.
    knowing that SCD List is self managed means the indexes can change at any time if no more entities are using it, so collecting Indexes and Types have to be proccessed on each system frame.