Search Unity

Work arounds for command buffer slowness

Discussion in 'Entity Component System' started by jdtec, Aug 14, 2019.

  1. jdtec

    jdtec

    Joined:
    Oct 25, 2017
    Posts:
    302
    Command buffers in jobs are generally slow because they can't be bursted.

    I've got around this so far by:

    1) Separating logic out in jobs where possible - although if you still have the command buffer job doing just command buffer stuff it still seems slow.
    2) Adding component data changes to a queue/list and delaying until the next frame to use EntityManager to do the work instead on the main thread.

    Both introduce code bloat though. It would be great if anyone from Unity could give us some estimate as to when EntityCommandBuffer will be support burst...?

    Do other people have any more ideas or workarounds for command buffer usage?
     
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,759
    They already stated that the framework for EntityCommandBuffer to work in burst is done in 19.3 (it's not supported yes as at least of a11.)

    I've always just done B.1) but not do it next frame, I just use a ECB on a IJob dequeuing so it's done in same frame.

    For tag components I've done it enough over time that I wrote a generic job at some point to do it.

    Code (CSharp):
    1.     /// <summary>
    2.     /// Iterate a queue of entities and add a default <see cref="T"/> component to them.
    3.     /// </summary>
    4.     /// <typeparam name="T">The component type to add.</typeparam>
    5. /*#if UNITY_2019_3_OR_NEWER
    6.     [Unity.Burst.BurstCompile]
    7. #endif*/
    8.     public struct AddComponentJob<T> : IJob
    9.         where T : struct, IComponentData
    10.     {
    11.         /// <summary>
    12.         /// The queue of entities to add the <see cref="T"/> component to.
    13.         /// </summary>
    14.         public NativeQueue<Entity> Entities;
    15.  
    16.         /// <summary>
    17.         /// The entity command buffer.
    18.         /// </summary>
    19.         public EntityCommandBuffer EntityCommandBuffer;
    20.  
    21.         /// <inheritdoc/>
    22.         public void Execute()
    23.         {
    24.             while (this.Entities.TryDequeue(out var entity))
    25.             {
    26.                 this.EntityCommandBuffer.AddComponent(entity, default(T));
    27.             }
    28.         }
    29.     }
    Code (CSharp):
    1.     /// <summary>
    2.     /// Iterate a queue of entities and remove the <see cref="T"/> component from them.
    3.     /// </summary>
    4.     /// <typeparam name="T">The component type to remove.</typeparam>
    5. /*#if UNITY_2019_3_OR_NEWER
    6.     [Unity.Burst.BurstCompile]
    7. #endif*/
    8.     public struct RemoveComponentJob<T> : IJob
    9.         where T : struct, IComponentData
    10.     {
    11.         /// <summary>
    12.         /// The queue of entities to remove the <see cref="T"/> component from.
    13.         /// </summary>
    14.         public NativeQueue<Entity> Entities;
    15.  
    16.         /// <summary>
    17.         /// The <see cref="EntityCommandBuffer"/>.
    18.         /// </summary>
    19.         public EntityCommandBuffer EntityCommandBuffer;
    20.  
    21.         /// <inheritdoc />
    22.         public void Execute()
    23.         {
    24.             while (this.Entities.TryDequeue(out var entity))
    25.             {
    26.                 this.EntityCommandBuffer.RemoveComponent<T>(entity);
    27.             }
    28.         }
    29.     }
    The real solution is C) though, avoid having to need ECB. Minimize archetype changes and / or use the batch api.
     
    MostHated, Opeth001 and jdtec like this.