NativeQueue and Burst

Does Burst not work with NativeQueue?

D:\UnityDevelopment\MapGenerator\Library\PackageCache\com.unity.collections@0.1.1-preview\Unity.Collections\NativeQueue.cs(97,17): error: The managed class type `Unity.Collections.NativeQueueBlockPoolData*` is not supported. Loading from a non-readonly static field `Unity.Collections.NativeQueueBlockPool.data` is not supported by burst
at Unity.Collections.NativeQueueBlockPool.get_QueueBlockPool() (at D:\UnityDevelopment\MapGenerator\Library\PackageCache\com.unity.collections@0.1.1-preview\Unity.Collections\NativeQueue.cs:97)
at Unity.Collections.NativeQueue`1<System.Int32>..ctor(Unity.Collections.NativeQueue`1<int>* this, Unity.Collections.Allocator label) (at D:\UnityDevelopment\MapGenerator\Library\PackageCache\com.unity.collections@0.1.1-preview\Unity.Collections\NativeQueue.cs:306)
at ContinentDetection.Execute(ContinentDetection* this) (at D:\UnityDevelopment\MapGenerator\Assets\Scripts\InitializationData\ContinentDetection.cs:156)
at Unity.Jobs.IJobExtensions.JobStruct`1<ContinentDetection>.Execute(ref ContinentDetection data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) (at C:\buildslave\unity\build\Runtime\Jobs\Managed\IJob.cs:30)


While compiling job: System.Void Unity.Jobs.IJobExtensions/JobStruct`1<ContinentDetection>::Execute(T&,System.IntPtr,System.IntPtr,Unity.Jobs.LowLevel.Unsafe.JobRanges&,System.Int32)

Allocation NativeQueue inside Burst - no. You only can pass NativeQueue in to job as field allocated outside.

1 Like

I just tried to do the same thing and got the same error message and read this post. So I made my own queue for use in bursted jobs. I’ve only lightly tested it so far. Please let me know if you try it and discover any bugs so I can fix them for my own projects too.

using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
public struct Queue<T> where T : unmanaged
{
    UnsafeList<T> list;
    int front;
    int back;
    public int Count => list.Length;
    public int Capacity => list.Capacity;
    public bool IsCreated => list.IsCreated;
    public bool IsEmpty => list.Length <= 0;
    public bool IsFull => list.Length >= list.Capacity;
    public Queue(Allocator alloc, int initialCapacity = 1)
    {
        list = new UnsafeList<T>(initialCapacity, alloc);
        front = 0;
        back = -1;
    }
    public void Enqueue(in T value)
    {
        if (IsFull)
        {
            DoubleCapacityAndCopyValues();
        }
        back = (back + 1) % Capacity;
        list[back] = value;
        list.Length++;
    }
    public bool TryDequeue(out T value)
    {
        if (IsEmpty)
        {
            value = default;
            return false;
        }
        int index = front;
        front = (front + 1) % Capacity;
        list.Length--;
        value = list[index];
        return true;
    }
    public bool TryPeek(out T value)
    {
        if (IsEmpty)
        {
            value = default;
            return false;
        }
        value = list[front];
        return true;
    }
    void DoubleCapacityAndCopyValues()
    {
        int oldCapacity = Capacity;
        list.SetCapacity(oldCapacity + 1);
        for (int i = 0; i < front; i++)
        {
            list[oldCapacity + i] = list[i];
        }
        back = front + oldCapacity - 1;
    }
    public void Dispose()
    {
        list.Dispose();
    }
    public JobHandle Dispose(JobHandle jobHandle)
    {
        return list.Dispose(jobHandle);
    }
}