I have a list of indices i’m filtering, and after that i would like to sort them. Something like:
void OnEnable()
{
var rng = new Unity.Mathematics.Random(123);
NativeList<int> indices = new NativeList<int>(10, Allocator.TempJob);
for (int i = 0; i < 10; i++)
indices.Add(rng.NextInt(100));
Debug.Log($"Before: {string.Join(',', indices.AsArray())}");
var handle = new FilterOdd().ScheduleFilter(indices, 32);
handle = indices.SortJob().Schedule(handle);
handle.Complete();
Debug.Log($"After: {string.Join(',', indices.AsArray())}");
indices.Dispose();
}
struct FilterOdd : IJobParallelForFilter
{
public bool Execute(int index) => index % 2 == 0;
}
This throws the following error:
Which i dont really understand, since i pass in the previous handle. The error also doesnt even mention any of the sort jobs.
When i sort indices.AsDeferredArray instead the results simply are invalid, not sorted. It does work when i call complete in between the jobs, but obviously i’d rather not.
Using the non-job variant, e.g. indices.Sort does work as expected.
A kind user on Discord helped me! I’m still a bit puzzled how it manages to do this, but constructing the job before filtering does make it work. E.g.:
Works, but this:
Doestnt. I’m not sure why, and it makes my code a bit harder to read. Ah well.
SortJob calls GetUnsafePtr(), which checks the safety handle at job creation. (Dependencies aren’t known until the job is scheduled.) Since the filter job is already scheduled, the safety check throws an error.
Upon another look, I think SortJob<T>(this NativeList<T> list) with a NativeList is likely to result in bugs, because it also gets list.Length() immediately, at job creation. That’s probably not intended, such as if you populate the list inside the first job. Instead, you want a job similar to this:
public struct SortJob<T> : IJob where T : unmanaged, IComparable<T>
{
public NativeList<T> list;
public void Execute()
{
list.Sort();
}
}
edit: However, the built-in struct SortJob is internally parallelized so it is better when you do know the length in advance.
edit2: In fact, Unity.Collections.SortJob<T>(this NativeList<T> list) totally bypasses the safety system after the job is created. There is no safety check that a SortJob doesn’t overwrite another job, so long as it is created first. I wouldn’t use it.