Search Unity

Two questions about Barriers and EntityCommandBuffer

Discussion in 'Entity Component System' started by BanJaxe, Nov 12, 2018.

  1. BanJaxe

    BanJaxe

    Joined:
    Nov 20, 2017
    Posts:
    47
    I'm trying to understand command buffers and the job system.

    1) [Inject] will be removed in a future ECS release. How can you access a barrier to create a command buffer without the attribute? All the docs still use [Inject] from what I can see.

    2) Should you call CreateCommandBuffer() every update or can you cache the buffer? Caching seems to work but maybe it will become invalidated/disposed at some point?

    Thanks
     
    Antypodish likes this.
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    World.Active.GetOrCreateManager<YourBarrierClass>(); in OnCreateManager()
     
  3. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    For JobComponentSystem I have a concern that inject-less barriers would not work correctly, because in the code I see lines like


    Code (CSharp):
    1.             // Notify all injected barrier systems that they will need to sync on any jobs we spawned.
    2.             // This is conservative currently - the barriers will sync on too much if we use more than one.
    3.             for (int i = 0; i < m_BarrierList.Length; ++i)
    4.             {
    5.                 m_BarrierList[i].AddJobHandleForProducer(outputJob);
    6.             }
    Which it works with injected barriers.

    Code (CSharp):
    1.         protected sealed override void OnBeforeCreateManagerInternal(World world)
    2.         {
    3.             base.OnBeforeCreateManagerInternal(world);
    4.  
    5.             m_BarrierList = ComponentSystemInjection.GetAllInjectedManagers<BarrierSystem>(this, world);
    6.         }
    If you add barriers not by injection, then they will update like normal systems and playback commands from ECB but won't call complete on your scheduled jobs. And then commands which you queued up in-job may execute at the same time while the job is still running? (If the barrier's update came before the job finished)


    Barrier deallocate all of its ECB on its time to update, so you need to remake the ECB. Caching should not work past the barrier's update point.
     
  4. BanJaxe

    BanJaxe

    Joined:
    Nov 20, 2017
    Posts:
    47
    Thanks both.

    I missed that somehow. I didn't realise EntityManager, ComponentSystem and BarrierSystem are all actually the same base class ScriptBehaviourManager. The naming is a bit confusing to me.


    Good to know.
     
  5. dartriminis

    dartriminis

    Joined:
    Feb 3, 2017
    Posts:
    157
    You are correct, you must use [Inject] with JobComponentSystem, I don't think there is any workaround for this yet. If you just get/create the system from the World, you will eventually end up with job dependency error ("... you must call complete on ... before you can read/write to the ... safely").
     
  6. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    never access
    World.Active
    from inside systems unless you really mean that.
    systems have a
    World
    property that points to their world, which may be or not be the active world.
     
  7. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
  8. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    Yeah this is an issue and will cause a dependency issue eventually which I found out the hard way.

    I'm using a
    T GetBarrier<T>(this JobComponentSystem componentSystem)
    extension to handle this for now so I can remove all injects. This just manually adds it to the m_BarrierList.

    When we get proper support I should be able to do a quick search/replace to fix it.

    Code (CSharp):
    1. // <copyright file="JobComponentSystemExtensions.cs" company="Timothy Raines">
    2. //     Copyright (c) Timothy Raines. All rights reserved.
    3. // </copyright>
    4.  
    5. namespace BovineLabs.Common.Utility
    6. {
    7.     using System;
    8.     using System.Reflection;
    9.     using Unity.Entities;
    10.  
    11.     /// <summary>
    12.     /// Extensions for the <see cref="JobComponentSystem"/>.
    13.     /// </summary>
    14.     public static class JobComponentSystemExtensions
    15.     {
    16.         private static bool setup;
    17.         private static PropertyInfo _worldPropertyInfo;
    18.         private static FieldInfo barrierListFieldInfo;
    19.  
    20.         /// <summary>
    21.         /// Gets or creates a barrier and correctly adds it to the barrier list.
    22.         /// </summary>
    23.         /// <typeparam name="T">The type of the barrier to get or create.</typeparam>
    24.         /// <param name="componentSystem">The <see cref="JobComponentSystem"/>.</param>
    25.         /// <returns>The barrier.</returns>
    26.         public static T GetBarrier<T>(this JobComponentSystem componentSystem)
    27.             where T : BarrierSystem
    28.         {
    29.             if (!setup)
    30.             {
    31.                 Setup();
    32.             }
    33.  
    34.             var world = (World)_worldPropertyInfo.GetValue(componentSystem);
    35.             var barrierList = (BarrierSystem[])barrierListFieldInfo.GetValue(componentSystem);
    36.  
    37.             Array.Resize(ref barrierList, barrierList.Length + 1);
    38.  
    39.             var barrier = world.GetOrCreateManager<T>();
    40.             barrierList[barrierList.Length - 1] = barrier;
    41.  
    42.             barrierListFieldInfo.SetValue(componentSystem, barrierList);
    43.  
    44.             return barrier;
    45.         }
    46.  
    47.         private static void Setup()
    48.         {
    49.             _worldPropertyInfo = CreateWorldGet();
    50.             barrierListFieldInfo = CreateBarrierListGet();
    51.  
    52.             setup = true;
    53.         }
    54.  
    55.         private static PropertyInfo CreateWorldGet()
    56.         {
    57.             var propertyInfo = typeof(ComponentSystemBase).GetProperty("World", BindingFlags.NonPublic | BindingFlags.Instance);
    58.  
    59.             if (propertyInfo == null)
    60.             {
    61.                 throw new NullReferenceException("World changed");
    62.             }
    63.  
    64.             return propertyInfo;
    65.         }
    66.  
    67.         private static FieldInfo CreateBarrierListGet()
    68.         {
    69.             var fieldInfo = typeof(JobComponentSystem).GetField("m_BarrierList", BindingFlags.NonPublic | BindingFlags.Instance);
    70.  
    71.             if (fieldInfo == null)
    72.             {
    73.                 throw new NullReferenceException("m_BarrierList changed");
    74.             }
    75.  
    76.             return fieldInfo;
    77.         }
    78.     }
    79. }
    80.  
     
    Last edited: Nov 18, 2018
  9. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    May I ask Unity devs (i.e. @Joachim_Ante ) for comment upon that matter?

    Is it best to stick with injection for now, or any of above proposed solutions are more appropriate?
     
    NotaNaN, NityaSattva, T-Zee and 3 others like this.
  10. S_Darkwell

    S_Darkwell

    Joined:
    Oct 20, 2013
    Posts:
    320
    Hello!

    I'm interested in knowing this as well!

    Be well!
    - S
     
    jgp80 and NotaNaN like this.