Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

Using IJobParallelForFilter to eliminate certain vertices from a NativeList

Discussion in 'Data Oriented Technology Stack' started by Matt_De_Boss_Developer, May 18, 2019 at 2:58 AM.

  1. Matt_De_Boss_Developer

    Matt_De_Boss_Developer

    Joined:
    Oct 17, 2014
    Posts:
    25
    So at the current moment I am creating a NativeList of vertices that are being created inside of another job. This list is propagated with Vector4s with the "w" value of each Vector4 either being set to 0 or to 1 depending on whether that vertex will be kept or not. So I guess I main question is how should I do this with IJobParallelForFilter as doing it in the main thread takes a very long time. I can provide some code that I currently have if my explanation seems a bit too vague. Thanks!
     
  2. LastResortMatthew

    LastResortMatthew

    Joined:
    Apr 10, 2019
    Posts:
    25
    Note that IJobParallelForFilter seems to still run on the main thread right now, but it should be made multithreaded eventually; and at least this way you can burst compile it for some serious speed gains even on the main thread.

    Code (CSharp):
    1. using Unity.Jobs;
    2. using Unity.Entities;
    3. using Unity.Mathematics;
    4. using Unity.Collections;
    5. using Unity.Burst;
    6.  
    7. public class MySystem : JobComponentSystem
    8. {
    9.     [BurstCompile]
    10.     struct FilterVerticesJob : IJobParallelForFilter
    11.     {
    12.         [ReadOnly] public NativeArray<float4> Vertices;
    13.  
    14.         public bool Execute(int index)
    15.         {
    16.             return Vertices[index].w == 1;
    17.         }
    18.     }
    19.  
    20.     [BurstCompile]
    21.     struct BuildArrayJob : IJobParallelFor
    22.     {
    23.         [ReadOnly] public NativeArray<float4> UnfilteredVertices;
    24.         [ReadOnly] public NativeArray<int> FilteredIndices;
    25.  
    26.         public NativeArray<float4> FilteredVertices;
    27.  
    28.         public void Execute(int index)
    29.         {
    30.             FilteredVertices[index] = UnfilteredVertices[FilteredIndices[index]];
    31.         }
    32.     }
    33.  
    34.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    35.     {
    36.         // assume you already have this:
    37.         NativeList<float4> vertices = ;
    38.  
    39.         // List in which to store the valid indices
    40.         NativeList<int> filteredIndices = new NativeList<int>(Allocator.TempJob);
    41.  
    42.         // Populate filteredIndices (use ScheduleAppend because the list of indices starts empty)
    43.         var filterHandle = new FilterVerticesJob
    44.         {
    45.             Vertices = vertices,
    46.         }.ScheduleAppend(filteredIndices, vertices.Length, 32, inputDeps);
    47.         filterHandle.Complete();
    48.  
    49.         // Get out the valid vertices based on the filtered indices
    50.         var filteredVertices = new NativeArray<float4>(filteredIndices.Length, Allocator.TempJob);
    51.         var buildHandle = new BuildArrayJob
    52.         {
    53.             UnfilteredVertices = vertices,
    54.             FilteredIndices = filteredIndices,
    55.             FilteredVertices = filteredVertices
    56.         }.Schedule(filteredIndices.Length, 32, filterHandle);
    57.         buildHandle.Complete();
    58.  
    59.         // filteredVertices now contains only the vertices you wanted to keep
    60.         // Don't forget to dipose any TempJob-allocated NativeCollections!
    61.  
    62.         return buildHandle;
    63.     }
    64. }
     
  3. Matt_De_Boss_Developer

    Matt_De_Boss_Developer

    Joined:
    Oct 17, 2014
    Posts:
    25

    Works extremely well and is way faster than just simply looping through in the main thread even though it isn't run in parallel. However, is there some sort of way to call "buildHandle" without waiting for the job before it to sync and complete? Once again, thanks so much for the help.
     
  4. LastResortMatthew

    LastResortMatthew

    Joined:
    Apr 10, 2019
    Posts:
    25
    The build job relies on the result of the filter job, so you can't run them in parallel, if that's what you mean?
     
  5. Matt_De_Boss_Developer

    Matt_De_Boss_Developer

    Joined:
    Oct 17, 2014
    Posts:
    25
    Not exactly, for some reason I was under the impression that allocating a NativeArray between jobs would pose a huge performance decrease. I was wrong. Once again, thanks so much and I will be sure to mention you on further posts whenever I share some Marching Cubes samples.
     
    LastResortMatthew likes this.
  6. LastResortMatthew

    LastResortMatthew

    Joined:
    Apr 10, 2019
    Posts:
    25
    Oh yeah, if you expect
    filteredIndices
    to be large, then it'd probably be faster to initialize the array without clearing the memory, since you know you'll be explicitly assigning every value in BuildArrayJob:
    Code (CSharp):
    1. var filteredVertices = new NativeArray<float4>(filteredIndices.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
    If it's small then it won't make much difference.