Search Unity

Bug Deferred Job arrays (from NativeList) don't work when cast to a NativeSlice

Discussion in 'Entity Component System' started by jperry_oddgames, Nov 3, 2022.

  1. jperry_oddgames

    jperry_oddgames

    Joined:
    Sep 18, 2017
    Posts:
    62
    Case number: IN-21886

    Description of the bug:
    I have two jobs that work in succession. Both are scheduled at the same time.
    Job 1 modifies a NativeList.
    Job 2 operates on said list's results.
    I use the
    NativeList<>.AsDeferredJobArray
    method to get a NativeArray for Job 2, as mentioned in the documentation.
    Job 2 has a field of type NativeArray, for which it behaves expectedly. If this is changed to a NativeSlice, the slice will be empty when the job executes.

    Expected behaviour:
    Given that
    NativeArray<T>
    can implicitly cast to
    NativeSlice<T>
    , I would expect that the job should operate on the correct data in either situation.

    Reproduction:
    1. Run the project and observe the resulting log message stating that the WorkerJob operated on a valid number of elements.
    2. Change the type of the
    WorkerJob.values
    field from NativeArray to NativeSlice (comment/uncomment the two lines there).
    3. Run the project again and observe that the WorkerJob now operates on zero elements.

    Sample code:

    Code (CSharp):
    1. using Unity.Burst;
    2. using Unity.Collections;
    3. using Unity.Jobs;
    4. using UnityEngine;
    5.  
    6. namespace DeferredNativeSliceRepro
    7. {
    8.     public class EntryPoint : MonoBehaviour
    9.     {
    10.         private void Start()
    11.         {
    12.             int count = 100;
    13.  
    14.             // Populate a native list with the same values duplicated many times
    15.             var nativeList = new NativeList<int>(count * 5, Allocator.TempJob);
    16.             for (int i = 0; i < count; i++)
    17.             {
    18.                 nativeList.Add(1);
    19.                 nativeList.Add(2);
    20.                 nativeList.Add(3);
    21.                 nativeList.Add(4);
    22.                 nativeList.Add(5);
    23.             }
    24.  
    25.             // Start a job to get a distinct set (remove the duplicates)
    26.             var distinctJob = new DistinctValuesJob()
    27.             {
    28.                 values = nativeList
    29.             };
    30.             var distinctHandle = distinctJob.Schedule();
    31.  
    32.             // Get deferred array, will have results after distinct job finishes
    33.             var deferredData = nativeList.AsDeferredJobArray();
    34.  
    35.             var result = new NativeArray<int>(1, Allocator.TempJob);
    36.             var workerJob = new WorkerJob()
    37.             {
    38.                 // If 'values' is a NativeSlice, this will implicitly cast but will not work.
    39.                 values = deferredData,
    40.                 result = result
    41.             };
    42.             var handle = workerJob.Schedule(dependsOn: distinctHandle);
    43.             handle.Complete();
    44.  
    45.             Debug.Log($"Worker job operated on {workerJob.result[0]} elements.");
    46.  
    47.             // Resource clean up
    48.             nativeList.Dispose();
    49.             result.Dispose();
    50.         }
    51.     }
    52.  
    53.     [BurstCompile]
    54.     public struct DistinctValuesJob : IJob
    55.     {
    56.         public NativeList<int> values;
    57.  
    58.         public void Execute()
    59.         {
    60.             var set = new NativeParallelHashSet<int>(capacity: values.Length, Allocator.Temp);
    61.  
    62.             for (int i = 0; i < values.Length; ++i)
    63.             {
    64.                 int value = values[i];
    65.                 if (!set.Add(value))
    66.                 {
    67.                     values.RemoveAt(i);
    68.                     --i;
    69.                 }
    70.             }
    71.  
    72.             set.Dispose();
    73.         }
    74.     }
    75.  
    76.     [BurstCompile]
    77.     public struct WorkerJob : IJob
    78.     {
    79.         public NativeArray<int> values;
    80.         //public NativeSlice<int> values;
    81.  
    82.         public NativeArray<int> result;
    83.  
    84.         public void Execute()
    85.         {
    86.             result[0] = values.Length;
    87.         }
    88.     }
    89. }
    90.  
     
  2. jperry_oddgames

    jperry_oddgames

    Joined:
    Sep 18, 2017
    Posts:
    62
    Update: Unity has now confirmed this is a bug & has transferred it to the team to be fixed
     
    kdchabuk likes this.
  3. jperry_oddgames

    jperry_oddgames

    Joined:
    Sep 18, 2017
    Posts:
    62
    Unity has updated the bug report with the following info

    Fix version/s: Pending
    Resolution Notes: *Bug is fixed in:
    2020.3.26f1.1459_a93835ac10a1