CommandBuffer.RequestAsyncReadbackIntoNativeArray size of buffer error

I want to read a texture into a native array. It is my understanding that the following code should be perfectly fine:

ReadExample(CommandBuffer cmd, RenderTexture source)
{
    var pixels = new NativeArray<byte>(source.width * source.height * 4, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);

    cmd.RequestAsyncReadbackIntoNativeArray(ref pixels, source, 0, (request) =>
    {
        pixels.Dispose();
    });
}

And yet when I run this, I receive Size of buffer cannot be larger than the nativeArray to read into. error.

The full stack trace:

Size of buffer cannot be larger than the nativeArray to read into.
UnityEngine.StackTraceUtility:ExtractStackTrace ()
UnityEngine.Rendering.ScriptableRenderContext:Submit_Internal ()
UnityEngine.Rendering.ScriptableRenderContext:Submit ()
UnityEngine.Rendering.HighDefinition.HDRenderPipeline:Render (UnityEngine.Rendering.ScriptableRenderContext,System.Collections.Generic.List`1<UnityEngine.Camera>) (at Library/PackageCache/com.unity.render-pipelines.high-definition@12.1.3/Runtime/RenderPipeline/HDRenderPipeline.cs:1906)
UnityEngine.Rendering.RenderPipeline:InternalRender (UnityEngine.Rendering.ScriptableRenderContext,System.Collections.Generic.List`1<UnityEngine.Camera>)
UnityEngine.Rendering.RenderPipelineManager:smile:oRenderLoop_Internal (UnityEngine.Rendering.RenderPipelineAsset,intptr,System.Collections.Generic.List`1<UnityEngine.Camera/RenderRequest>,Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle)
UnityEditor.EditorGUIUtility:RenderPlayModeViewCamerasInternal (UnityEngine.RenderTexture,int,UnityEngine.Vector2,bool,bool)
UnityEditor.PlayModeView:RenderView (UnityEngine.Vector2,bool)
UnityEditor.GameView:OnGUI ()
UnityEditor.HostView:InvokeOnGUI (UnityEngine.Rect)
UnityEditor.DockArea:smile:rawView (UnityEngine.Rect)
UnityEditor.DockArea:OldOnGUI ()
UnityEngine.UIElements.IMGUIContainer:smile:oOnGUI (UnityEngine.Event,UnityEngine.Matrix4x4,UnityEngine.Rect,bool,UnityEngine.Rect,System.Action,bool)
UnityEngine.UIElements.IMGUIContainer:HandleIMGUIEvent (UnityEngine.Event,UnityEngine.Matrix4x4,UnityEngine.Rect,System.Action,bool)
UnityEngine.UIElements.IMGUIContainer:smile:oIMGUIRepaint ()
UnityEngine.UIElements.UIR.RenderChainCommand:ExecuteNonDrawMesh (UnityEngine.UIElements.UIR.DrawParams,single,System.Exception&)
UnityEngine.UIElements.UIR.UIRenderDevice:EvaluateChain (UnityEngine.UIElements.UIR.RenderChainCommand,UnityEngine.Material,UnityEngine.Material,UnityEngine.Texture,UnityEngine.Texture,single,Unity.Collections.NativeSlice`1<UnityEngine.UIElements.UIR.Transform3x4>,Unity.Collections.NativeSlice`1<UnityEngine.Vector4>,UnityEngine.MaterialPropertyBlock,bool,System.Exception&)
UnityEngine.UIElements.UIR.RenderChain:Render ()
UnityEngine.UIElements.UIRRepaintUpdater:Update ()
UnityEngine.UIElements.VisualTreeUpdater:UpdateVisualTreePhase (UnityEngine.UIElements.VisualTreeUpdatePhase)
UnityEngine.UIElements.Panel:UpdateForRepaint ()
UnityEngine.UIElements.Panel:Repaint (UnityEngine.Event)
UnityEngine.UIElements.UIElementsUtility:smile:oDispatch (UnityEngine.UIElements.BaseVisualElementPanel)
UnityEngine.UIElements.UIElementsUtility:UnityEngine.UIElements.IUIElementsUtility.ProcessEvent (int,intptr,bool&)
UnityEngine.UIElements.UIEventRegistration:ProcessEvent (int,intptr)
UnityEngine.UIElements.UIEventRegistration/<>c:<.cctor>b__1_2 (int,intptr)
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)

[C:\buildslave\unity\build\Runtime\Graphics\AsyncGPUReadbackManaged.cpp line 336]

@richardkettlewell I saw you on another forum talking about an AsyncGPUReadback error so I though I would add you here as well.

what format is the RenderTexture?

That source is the screen texture and we use it for a post processing effect.

This code works perfectly fine when the Color Buffer Format in the quality settings is R11G11B10, but in our highest quality settings it is set to R16G16B16A16. Thank you so much! Sorry for taking your time with this one, I should have spotted it.

This makes me wonder though: if you read back an R11G11B10 texture into a NativeArray, I assume you get incorrect results, with every 4 bytes being in the format: R8, R3G5, G6B2, B8. If so, would NativeArray capture these values in the right format, or simple capture 1 float for every pixel in the format R11G11B10? Neither does much good: how do I go about capturing the NativeArray correctly?

Hi,

If you use NativeArray or any compatible , this will not perform a conversion of data, it is really just a reinterpretation, so yes it will only be the R11G11B10 data reinterpreted as float. What you can do is requesting Uint32 and extract RGB data manually with bitwise operations.

It’s worth noting that Async readback also supports some actual data conversion for textures. You can specify a destination texture format when performing a request, in that case the data on GPU will be converted to that format (if they differ). Not all conversions are supported and, if not, you’ll get a request with the error flag set. Also note that the conversion comes at a cost on the render thread

2 Likes