Search Unity

Using IJobParallelForFilter to eliminate certain vertices from a NativeList

Discussion in 'Entity Component System' started by Matt_De_Boss_Developer, May 18, 2019.

  1. Matt_De_Boss_Developer

    Matt_De_Boss_Developer

    Joined:
    Oct 17, 2014
    Posts:
    46
    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. TLRMatthew

    TLRMatthew

    Joined:
    Apr 10, 2019
    Posts:
    65
    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:
    46

    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. TLRMatthew

    TLRMatthew

    Joined:
    Apr 10, 2019
    Posts:
    65
    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:
    46
    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.
     
    TLRMatthew likes this.
  6. TLRMatthew

    TLRMatthew

    Joined:
    Apr 10, 2019
    Posts:
    65
    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.
     
    chadfranklin47 likes this.
  7. m506

    m506

    Joined:
    Dec 21, 2015
    Posts:
    93
    Does anyone know if IJobParallelForFilter is still running on the main thread or if its now running in parallel as of 2020.2?

    Thanks
     
    tonytopper and officialfonee like this.