Search Unity

Converting a ComputeBuffer To a NativeArray

Discussion in 'Data Oriented Technology Stack' started by GeorgeAdamon, Aug 5, 2019.

  1. GeorgeAdamon

    GeorgeAdamon

    Joined:
    May 31, 2017
    Posts:
    6
    Hello everyone,

    I am trying to use the ConvertExistingDataToNativeArray function, in order to pass the contents of a ComputeBuffer to a NativeArray<float>, avoiding the ComputeBuffer's GetData(T[]) function.

    My function so far looks like this (performs some calculations on a RenderTexture via a Compute Shader, then gets the results back as a ComputeBuffer):

    Code (CSharp):
    1.  public unsafe void GetCellStates(ref ComputeBuffer buffer, ref NativeArray<float> array, in RenderTexture tex)
    2.     {
    3.         readBackShader.SetTexture(getPixelsKernel,"Input", tex);
    4.         readBackShader.SetBuffer(getPixelsKernel, "Data", buffer);
    5.         readBackShader.Dispatch(getPixelsKernel, CA3DScript.CountX/16, CA3DScript.CountY/8, CA3DScript.CountZ/8);
    6.      
    7.         array = ConvertExistingDataToNativeArray<float>( buffer.GetNativeBufferPtr().ToPointer(), CA3DScript.totalCount * 4, Allocator.Persistent);
    8. }
    The problem is that I get a Null Reference Exception every time I try to do something with the NativeArray afterwards ( Copying to another array, accessing elements, passing it to a Job), although it has a non-zero length and IsCreated = true.

    NullReferenceException: Object reference not set to an instance of an object
    Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckReadAndThrow (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) (at C:/buildslave/unity/build/Runtime/Export/Jobs/AtomicSafetyHandle.bindings.cs:147)


    I don't have a good idea as to what might be wrong. Could some Pointer Wizard have a look ? :)

    Thanks in advance!
     
    Last edited: Aug 5, 2019
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,667
    After a
    NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray

    you also need a
    NativeArrayUnsafeUtility.SetAtomicSafetyHandle
     
    Josh4364 likes this.
  3. GeorgeAdamon

    GeorgeAdamon

    Joined:
    May 31, 2017
    Posts:
    6
    @tertle I'm glad I get the chance thank you for your huge contribution to the forums!
    Based on your suggestions in this thread i modified my code:

    Code (CSharp):
    1.    public unsafe void GetCellStates(out NativeArray<float> array)
    2.     {
    3.         array = ConvertExistingDataToNativeArray<float>( getPixelsBuffer.GetNativeBufferPtr().ToPointer(), CA3DScript.totalCount * 4, Allocator.Invalid);
    4.  
    5. #if ENABLE_UNITY_COLLECTIONS_CHECKS
    6.         SetAtomicSafetyHandle(ref array, AtomicSafetyHandle.Create());
    7. #endif
    8.     }
    However anytime I try to access the NativeArray outside the function that created it, ie in a Parallel Job (as [ReadOnly]), Unity throws a Null Reference exception:


    NullReferenceException: Object reference not set to an instance of an object
    Unity.Collections.LowLevel.Unsafe.UnsafeUtility.ReadArrayElement[T] (System.Void* source, System.Int32 index) (at C:/buildslave/unity/build/Runtime/Export/Unsafe/UnsafeUtilityPatched.cs:48)
    Unity.Collections.NativeArray`1[T].get_Item (System.Int32 index) (at C:/buildslave/unity/build/Runtime/Export/NativeArray/NativeArray.cs:139)
    CA3DInterface+AdditiveBlendJob.Execute (System.Int32 index) (at Assets/CA3DInterface.cs:265)
    Unity.Jobs.IJobParallelForExtensions+ParallelForJobStruct`1[T].Execute (T& jobData, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, Unity.Jobs.LowLevel.Unsafe.JobRanges& ranges, System.Int32 jobIndex) (at C:/buildslave/unity/build/Runtime/Jobs/Managed/IJobParallelFor.cs:43)
     
  4. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,154
    GetData is pulling data back to the CPU, from the GPU memory. You can't bypass this step.

    You have 2 options:
    * Use GetData and copy into NativeArray afterwards
    * Use https://docs.unity3d.com/ScriptReference/Rendering.AsyncGPUReadback.html, which also copies the data back from the GPU, but does it asynchronously. That is to say, it's not faster than GetData, but it doesn't block the main thread while it waits. So you can do other stuff and check back on the next frame, if it's ready yet. If you do need to block, this API also has a WaitForCompletion method, which may get you back to somewhere close to GetData performance, but with the bonus that you can get the data as a NativeArray, rather than the extra copy required with GetData.

    In summary, always try to avoid copying data back to the CPU from the GPU in performance critical code, unless you are willing to wait a couple of frames for it to arrive, in which case use the async api.
     
  5. crysicle

    crysicle

    Joined:
    Oct 24, 2018
    Posts:
    66
    Just my 5 cents. New API got introduced with 2019.3 which allows to not just get a NativeArray<> with AsyncGPUReadback, but also fill a NativeArray of your choice with "AsyncGPUReadback.RequestIntoNativeArray(ref NativeArray_1, ComputeBuffer)". I haven't used it myself, but this should allow to fill arrays with any allocation directly.
     
  6. GeorgeAdamon

    GeorgeAdamon

    Joined:
    May 31, 2017
    Posts:
    6
    richardkettlewell likes this.
  7. korzen303

    korzen303

    Joined:
    Oct 2, 2012
    Posts:
    172
    Hi,

    @richardkettlewell I get the async stuff bu I don't get why there is a SetData<T>(NativeArray<T> data) but no corresponding GetData<T>(NativeArray<T> data)? Could you please clarify?

    Thanks
     
    GeorgeAdamon likes this.
  8. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,154
    Which part of the scripting API are you referring to?
     
  9. korzen303

    korzen303

    Joined:
    Oct 2, 2012
    Posts:
    172
    ComputBuffer
     
  10. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,154
    It looks like we just haven’t added it yet. We can look at adding it.
     
    GeorgeAdamon likes this.
  11. GeorgeAdamon

    GeorgeAdamon

    Joined:
    May 31, 2017
    Posts:
    6
    That would be great, removing an unnecessary CopyTo() call.