Search Unity

[Request] ToBufferArray

Discussion in 'Entity Component System' started by dzamani, Mar 22, 2019.

  1. dzamani

    dzamani

    Joined:
    Feb 25, 2014
    Posts:
    122
    Hi,

    I've just switched to latest entities package and tried to update some of my remaining [Inject] to the new way.
    So I should have 2 options: either go the long way and use Chunks or for a bit less lines to write I could create a ComponentGroup and then use ToComponentArray, ToEntityArray and ToComponentDataArray.

    But it seems that there isn't any way to get BufferArray (BufferAccessor would be more accurate I think from the Chunk what I used with chunks) from component group since GetBufferArray was deprecated.

    Any plan to make that available ?

    Thanks!
     
  2. AriaBonczek

    AriaBonczek

    Unity Technologies

    Joined:
    Jul 20, 2018
    Posts:
    26
    I'm currently working on adding overloads to IJobForEach (previously IJobProcessComponentData) which will allow accessing buffers from those jobs. No ETA, but I'm hoping to finish it soon.

    The issue with ToComponentArray, ToEntityArray, ToComponentDataArray, etc is that they allocate memory and perform a copy, which can be a slow operation. I'll likely add one for completion's sake, but this will very rarely be the best way to access your component data. If you're writing main thread code, I recommend using Entities.ForEach/EntityQueryBuilder instead to iterate through your group (this already supports accessing DynamicBuffers). If you're writing job code, IJobForEach will be more desirable than indexing into arrays that require a copy.

    I'm planning to do a more extended post on this sometime in the near future.
     
    timmehhhhhhh and GilCat like this.
  3. dzamani

    dzamani

    Joined:
    Feb 25, 2014
    Posts:
    122
    From what I see, unless I go with chunks, you can't access DynamicBuffers from a ComponentGroup (now called EntityQuery).
    That's the use case I'm talking about:
    - On main thread
    - Without chunks
    - Access buffers

    If it's not something that will be added, then I will just make mine (a job going through a query and fetching all buffers matching the query and putting them in a BufferAccessor).

    It feels like the API deprecation push us to use chunks or ForEach but in the current state of ECS where we still have some hybrid things, having ToComponentArray, ToEntityArray, ToComponentDataArray and the missing ToBufferAccessor is something I feel like I can't go without.
     
    lclemens likes this.
  4. Xerioz

    Xerioz

    Joined:
    Aug 13, 2013
    Posts:
    104
    Same here, I really liked the simplicity of the previous approach, but then again after converting, it doesn't seem like the IChunk approach isn't any more complex than using IJob. It's just a bit uglier.

    Anyway, I was porting my code to IChunk recently and thought maybe the following snippet could be useful for someone in the future:

    Code (CSharp):
    1. // Old
    2. public struct IterateBufferTypeJob: IJob {
    3.            [DeallocateOnJobCompletion, ReadOnly] public NativeArray<MyComponentData> test1;
    4.            public BufferArray<MyBufferElementData> test2;
    5.  
    6.            public int Length;
    7.  
    8.            public void Execute () {
    9.                for (int i = 0; i != Length; i++) {
    10.                     //Do stuff
    11.                 }
    12.            }
    13. }
    14.  
    15. // New
    16. public struct IterateBufferTypeJob: IJobChunk {
    17.             [ReadOnly] public ArchetypeChunkComponentType<MyComponentData> test1Type;
    18.             public ArchetypeChunkBufferType<MyBufferElementData> test2Type;
    19.  
    20.             public void Execute (ArchetypeChunk chunk, int chunkIndex, int entityOffset)
    21.             {
    22.                 var test1 = chunk.GetNativeArray(test1Type);
    23.                 var test2 = chunk.GetBufferAccessor(test2Type);
    24.                 for (int i = 0; i < chunk.Count; i++) {
    25.                      //Do stuff
    26.                 }
    27.            }
    28. }
    29.  
     
  5. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Speaking about ForEach vs manual iteration, why is ForEach not supported in a JobComponentSystem if it's more performant?
     
  6. AriaBonczek

    AriaBonczek

    Unity Technologies

    Joined:
    Jul 20, 2018
    Posts:
    26
    You can use Entities.ForEach for this inside of a ComponentSystem. Here's a code example:

    Code (CSharp):
    1. Entities.WithAll<EcsIntElement>().ForEach((Entity e, DynamicBuffer<EcsIntElement> buffer) =>
    2.             {
    3.                
    4.             });
    As for doing this in a JobComponentSystem, it's something we're talking about. Doing work inside of a job (i.e. an IJobChunk or IJobForEach) will just about always be faster because of parallelization and Burst, but if you're using managed types, then ForEach will be faster than doing copies.

    And to reiterate, we are adding buffers to IJobForEach and a ToBufferAccessor. There is no concrete ETA, but this is what I'm currently working on so "soon" :)
     
    FROS7 and dzamani like this.
  7. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Looking at where we access entities on the main thread, we could probably get rid of all uses of ToComponentDataArray except for IJobParallelForTransform, where you guys even still use it.
     
    AriaBonczek likes this.
  8. dzamani

    dzamani

    Joined:
    Feb 25, 2014
    Posts:
    122
    Oh I misunderstood that you are also working on a ToBufferAccessor but also what you meant by using ForEach since I was thinking with the context of EntityQuery and it wasn't making sense to me, now it does.

    Thanks, I think I will switch to a ForEach for that part, I'm still a bit flexible for this specific issue.

    Well let's say you are a monster like me and you have 10 components on the same entity with 2 hybrid, 3 buffers and 5 componentdata. ForEach doesn't work in that case so having a manual way to handle things is useful. You could say that my issue is having too many components on the same entity but I could argue that it's context-specific and that in some case you need to have something like this to have some perfs.
     
  9. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    I'm not really in favor of second guessing use cases myself. But I'm hard pressed to think of use cases that could not be eliminated with a better design. Hybrid I think counts here, that's a choice you made. Now is it a good idea to force developers into a paradigm that isn't really even stable or supported well yet? Maybe, I mean now is the time when they are setting their architecture for the next decade, so I can see the argument for not supporting flows that in the future would be considered not the best practice.

    We have a few of these ourselves, ForEach right now would make life better on a practical level at this point in time. But if they chose not to support it I would understand, until I see a use case where it's not really a choice.
     
  10. timmehhhhhhh

    timmehhhhhhh

    Joined:
    Sep 10, 2013
    Posts:
    157
    it took me a while to figure out i needed DynamicBuffer<MyBufferElement> with Entities.ForEach (actually, i didn't figure it out, but i thankfully found this post). as i'm generally a bit slow, would it be possible to simplify this or make it more clear in the error / overloads what's going on?
     
    dzamani likes this.
  11. mikaelK

    mikaelK

    Joined:
    Oct 2, 2013
    Posts:
    284
    What the situation on this? I think getting buffers from the query is important, since right now I'm not sure how else you can create editor defined queries that are assembled at runtime.

    If Entities.ForEach could consume a query that would also help things.

    Edit. I guess WithEntityQueryOptions is worth a shot.
     
    Last edited: May 19, 2021