Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug Weird behavior with CopyFromComponentDataArray: data doesn't update in debugger & some systems

Discussion in 'Entity Component System' started by yondercode, Jul 10, 2020.

  1. yondercode

    yondercode

    Joined:
    Jun 11, 2018
    Posts:
    27
    UPDATE: In my case, this is caused by
    CopyFromComponentDataArray
    not updating the chunk's component type change versions.

    Editing CopyComponentArrayToChunks does the trick for me.

    Code (CSharp):
    1. [BurstCompile]
    2. unsafe struct CopyComponentArrayToChunks : IJobChunk
    3. {
    4.     [NativeDisableUnsafePtrRestriction] public byte* ComponentData;
    5.     public int TypeIndex;
    6.  
    7.     public void Execute(ArchetypeChunk chunk, int chunkIndex, int entityOffset)
    8.     {
    9.         var archetype = chunk.Archetype.Archetype;
    10.         var indexInTypeArray = ChunkDataUtility.GetIndexInTypeArray(archetype, TypeIndex);
    11.         var typeOffset = archetype->Offsets[indexInTypeArray];
    12.         var typeSize = archetype->SizeOfs[indexInTypeArray];
    13.  
    14.         var dst = chunk.m_Chunk->Buffer + typeOffset;
    15.         var src = ComponentData + (entityOffset * typeSize);
    16.         var copySize = typeSize * chunk.Count;
    17.  
    18.         UnsafeUtility.MemCpy(dst, src, copySize);
    19.  
    20.         var chunkPtr = chunk.m_Chunk;
    21.  
    22.         var entityComponentStore = chunkPtr->Archetype->EntityComponentStore;
    23.         var globalSystemVersion = entityComponentStore->GlobalSystemVersion;
    24.  
    25.         chunkPtr->SetChangeVersion(indexInTypeArray, globalSystemVersion);
    26.     }
    27. }
    It does not feel right to modify the package source. But I do think this modification is the correct behavior though. Since
    CopyFromComponentDataArray
    is obviously a write operation, it has to update the chunk versions after copying.

    ===== original post =====

    I don't know if this is a bug or I did something wrong. Consider the following test system:

    Code (CSharp):
    1. public struct TestDataComponent : IComponentData
    2. {
    3.     public int Value;
    4. }
    5.  
    6. public class TestQuerySystem : SystemBase
    7. {
    8.     protected override void OnCreate()
    9.     {
    10.         base.OnCreate();
    11.         EntityManager.CreateEntity(EntityManager.CreateArchetype(typeof(TestDataComponent)));
    12.     }
    13.  
    14.     protected override void OnUpdate()
    15.     {
    16.         var query = EntityManager.CreateEntityQuery(typeof(TestDataComponent));
    17.  
    18.         var entities = query.ToEntityArray(Allocator.TempJob);
    19.         var testDataComponents = query.ToComponentDataArray<TestDataComponent>(Allocator.TempJob);
    20.  
    21.         for (int i = 0; i < testDataComponents.Length; i++)
    22.         {
    23.             testDataComponents[i] = new TestDataComponent { Value = testDataComponents[i].Value + 1 };
    24.             //EntityManager.SetComponentData(entities[i], new TestDataComponent { Value = testDataComponents[i].Value + 1 }); // "traditional" method, works correctly
    25.         }
    26.  
    27.         query.CopyFromComponentDataArray(testDataComponents);
    28.  
    29.         // Below is the code to check wether the component values has been updated
    30.         var newQuery = EntityManager.CreateEntityQuery(typeof(TestDataComponent));
    31.         var newComponents = newQuery.ToComponentDataArray<TestDataComponent>(Allocator.TempJob);
    32.  
    33.         Debug.Log("Component value in array: " + testDataComponents[0].Value);
    34.         Debug.Log("Component value in entity: " + EntityManager.GetComponentData<TestDataComponent>(entities[0]).Value);
    35.         Debug.Log("Component value in new query: " + newComponents[0].Value);
    36.  
    37.         // All debug output shows the correct updated value
    38.  
    39.         entities.Dispose();
    40.         newComponents.Dispose();
    41.         testDataComponents.Dispose();
    42.     }
    43. }
    It's a simple system that the increments the value inside
    TestDataComponent
    by one every frame. All debug output from my test code shows that the values have been updated correctly.

    However the values in Entity Debugger is weird. It's basically not updating unless I hover my mouse over it.



    And if I use
    CopyFromComponentDataArray
    for
    Translation
    s, not only the values in the debugger not updating unless I'm hovering my mouse,
    LocalToWorld
    does not update unless a structural change happen.



    (In the end of the video I did a structural change over the entity)

    As you can see
    WorldRenderBounds
    also did not update. However all of my systems that read the
    Translation
    s values directly through query (not through
    LocalToWorld
    ) got the correct values. Also I want to add that I tried rearranging the execution order of the system that alter
    Translation
    s using
    CopyFromComponentDataArray
    before and after
    TransformSystemGroup
    but the issue still persists.

    If I use
    SetComponentData
    and a loop to set the values of each entities, everything works fine though.

    My environment:
    Unity 2019.4.3f1
    Entities 0.11.1 preview.4
    DOTS Editor 0.8.0 preview.1
    Burst turned off
    JobsDebugger On
    LeakDetection Full
     
    Last edited: Jul 12, 2020
  2. yondercode

    yondercode

    Joined:
    Jun 11, 2018
    Posts:
    27
    Well I think I know why this behavior is happening. It seems that
    CopyFromComponentDataArray
    does not change the chunk's component change version even though the entity query uses
    ReadWrite
    for the component types?

    How to make a batched set operation that updates the change version then?
     
    Last edited: Jul 11, 2020
  3. yondercode

    yondercode

    Joined:
    Jun 11, 2018
    Posts:
    27
    I managed to make
    CopyFromComponentDataArray
    updates the chunk's component type change version by modifying
    CopyComponentArrayToChunks
    in
    Unity.Entities/Iterators/ChunkDataGatherJobs
    .

    Code (CSharp):
    1. [BurstCompile]
    2. unsafe struct CopyComponentArrayToChunks : IJobChunk
    3. {
    4.     [NativeDisableUnsafePtrRestriction] public byte* ComponentData;
    5.     public int TypeIndex;
    6.  
    7.     public void Execute(ArchetypeChunk chunk, int chunkIndex, int entityOffset)
    8.     {
    9.         var archetype = chunk.Archetype.Archetype;
    10.         var indexInTypeArray = ChunkDataUtility.GetIndexInTypeArray(archetype, TypeIndex);
    11.         var typeOffset = archetype->Offsets[indexInTypeArray];
    12.         var typeSize = archetype->SizeOfs[indexInTypeArray];
    13.  
    14.         var dst = chunk.m_Chunk->Buffer + typeOffset;
    15.         var src = ComponentData + (entityOffset * typeSize);
    16.         var copySize = typeSize * chunk.Count;
    17.  
    18.         UnsafeUtility.MemCpy(dst, src, copySize);
    19.  
    20.         var chunkPtr = chunk.m_Chunk;
    21.  
    22.         var entityComponentStore = chunkPtr->Archetype->EntityComponentStore;
    23.         var globalSystemVersion = entityComponentStore->GlobalSystemVersion;
    24.  
    25.         chunkPtr->SetChangeVersion(indexInTypeArray, globalSystemVersion);
    26.     }
    27. }
    This modification fixes all of my issues above. I think this is how
    CopyFromComponentDataArray
    should behave since it's obviously a write operation.