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

NavmeshQuery in a IJobParallelFor impossible?

Discussion in 'Entity Component System' started by LesterZw, Feb 19, 2019.

  1. LesterZw

    LesterZw

    Joined:
    Apr 8, 2015
    Posts:
    6
    The official documentation for NavMeshQuery states that it can be used with IJobParallelFor:

    "NavMeshQuery operations can be executed inside jobs (IJob, IJobParallelFor), as opposed to the operations in the NavMesh-related structures."

    But i don't see how this could be the case,
    • Sharing a NavMeshQuery between parallel jobs is not possible since BeginFindPath,UpdateFindPath,EndFindPath write to the NavMeshQuery
    • NavMeshQuery is not a blittable type, NativeArray<NavMeshQuery> is a no go
    • Reference types are not allowed in jobs, NavMeshQuery[] is a no go
    • Creating a NavMeshQuery within the job is not possible since it would require NavMeshWorld(unsafe) and allocates native memory

    Am i missing something or is NavMeshQuery simply not useable with IJobParallelFor despite the documentation stating it is?
     
  2. Micz84

    Micz84

    Joined:
    Jul 21, 2012
    Posts:
    436
  3. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,626
    Correct. When I looked at this a while back I couldn't think of a good way to use I IJobParallelFor with NavMeshQuery at this stage. The documentation did confuse me for a bit as well.

    I suspect with a few pointers and some hacks I could probably get them to work with a IJobParallelFor, but instead I think the current approach is to just to queue them 1 per IJob and execute them all in parallel.

    Code (CSharp):
    1.             var handles = new NativeArray<JobHandle>(this.queries.Count, Allocator.TempJob);
    2.  
    3.             int index = 0;
    4.  
    5.             foreach (var query in this.queries)
    6.             {
    7.                 var updateQueryJob = new UpdateQueryJob
    8.                 {
    9.                     Waypoints = this.GetBufferFromEntity<Waypoint>(),
    10.                     EntityCommandBuffer = this.barrier.CreateCommandBuffer(),
    11.                     Request = query.Value.Request,
    12.                     Query = query.Value.NavMeshQuery,
    13.                 };
    14.  
    15.                 handles[index] = updateQueryJob.Schedule();
    16.                 index++;
    17.             }
    18.  
    19.             var handle = JobHandle.CombineDependencies(handles);
    20.  
    21.             handles.Dispose();
    22.  
    23.             return handle;
     
    hippocoder likes this.
  4. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    Yep agree with @tertle, I'm also been confused by docs, and I also use IJob-s scheduled in parallel. For now It's only one correct approach with navigation by NavMeshQuery.
     
    hippocoder likes this.
  5. LesterZw

    LesterZw

    Joined:
    Apr 8, 2015
    Posts:
    6
    Thank you for your response @tertle, my current implementation is similar.

    Am i correct to assume that under the hood the job system will still batch the Execute()'s and push those batches to multiple Native Jobs in the Job Queue?
     
  6. jammarman

    jammarman

    Joined:
    Feb 15, 2017
    Posts:
    7
    In the above example, how can you easily access the results of each job? ParallelFor lets all the jobs write to the same array, and I might be wrong but it seems that native arrays are the only way to return from a job, does this mean the only way to return the result from each job is to declare as many native arrays as I have jobs? Would I literally have to manually declare them all?



    I've been trying to get my head around this for days any help would be much appreciated.
     
  7. LesterZw

    LesterZw

    Joined:
    Apr 8, 2015
    Posts:
    6
    @jammarman
    In the example given by Tertle a DynamicBuffer is used which stores Waypoint data on a per entity basis.(you can write to the dynamicbuffer from a job,add elements etc).

    Creating as many native arrays as you have jobs and assigning them per job would also work in this case since the job which is scheduled in Tertle's example is not a ParallelFor job (Its not possible to use NavmeshQuery with Parallel type jobs for now)

    Id recommend using a DynamicBuffer though.
     
    jammarman likes this.
  8. reeseschultz

    reeseschultz

    Joined:
    Apr 1, 2018
    Posts:
    21
    This topic's approaching a year old, but I figured I'd chime in to say I'm getting pretty sweet performance out of a pointer-based method. In my NavMeshQuerySystem, on startup I now populate a public
    NativeArray
    of structs respectively pointing to their own
    NavMeshQuery
    , ordered by thread index. I inject that system into my NavPlanSystem. It uses the Entities.ForEach syntactic sugar, so I simply pass said
    NativeArray
    to
    WithNativeDisableParallelForRestriction
    . I also grab the native thread index, and then I only access each
    NavMeshQuery
    pointer by that index within a given, Burst-compiled "NavPlanJob." The UnsafeUtility is invaluable for this.



    I should mention that the linked code supports my drag-and-droppable navigation scripts, which are part of my demos on GitHub. Here's a link to the user guide specifically for my DOTS-based navigation. In my so-called "NavPerformanceDemo," which uses the nav scripts, I can spawn tens of thousands of path-finding agents with little detriment to performance. But I actually created the scripts first and foremost for the auto-jumping and surface movement features you see in the above gif of the "NavMovingJumpDemo" (btw, the camera is not moving). With these scripts you can set surfaces as "jumpable" from one another during authoring, so agents can use their currently-detected surface below them to know where they can jump. Obviously there are still issues and corner cases to work out, so PRs are welcome.

    Anyway, ideally my code demystifies how to go about this in a performant and reasonably idiomatic manner.
     
    Last edited: Feb 25, 2020
    Dinamytes and DeadNinja like this.