Search Issue Tracker

By Design

Votes

1

Found in

2021.3.39f1

2022.3.32f1

6000.0.5f1

Issue ID

UUM-73357

Regression

No

Read/Write error is thrown when making an AsyncGPUReadback request to a Native Array the second time

--

-

How to reproduce:
1. Open the “IN-77561_repro“ project
2. Open the “SampleScene“
3. Enter Play Mode
4. Observe the Console

Expected result: Read/Write error is thrown
Actual result: Read/Write error is not thrown

Reproducible with: 2021.3.39f1, 2022.3.32f1, 6000.0.5f1

Reproducible on: Windows 10
Not reproducible on: No other environment tested

Error: AsyncGPUReadback - NativeArray does not have read/write access
UnityEngine.Rendering.AsyncGPUReadback:RequestIntoNativeArray<byte> (Unity.Collections.NativeArray{{1<byte>&,UnityEngine.Texture,int,System.Action}}1<UnityEngine.Rendering.AsyncGPUReadbackRequest>)

  1. Resolution Note:

    This issue appears to arise from the user-provided script not properly waiting for the readback request and job to complete before requesting another readback.

    The `Update()` method in the original script:

    void Update()
    {
    switch (state)
    {
    case EState.StartReadback:
    {
    Debug.Log("Starting new request");
    request = AsyncGPUReadback.RequestIntoNativeArray(ref _data, texture, mipIndex: 0);
    state = EState.WaitReadback;
    break;
    }
    case EState.WaitReadback:
    {
    if (request.done)
    {
    request.WaitForCompletion();
    state = EState.WaitForFrames;
    framesCounter = 0;
    Assert.IsFalse(request.hasError);
    state = EState.StartJob;
    }
    break;
    }
    case EState.StartJob:
    {
    jobHandle = new Job(_data).Schedule();
    state = EState.WaitJob;
    break;
    }
    case EState.WaitForFrames:
    {
    framesCounter++;
    if (framesCounter > 30)
    {
    state = EState.StartReadback;
    }
    break;
    }
    case EState.WaitJob:
    {
    if (jobHandle.IsCompleted)
    {
    jobHandle.Complete();
    state = EState.StartReadback;
    }
    break;
    }
    default: throw new ArgumentOutOfRangeException();
    }
    }

    An updated version of this the `Update()` method that doesn't show any errors:

    void Update()
    {
    switch (state)
    {
    case EState.StartReadback:
    {
    Debug.Log("Starting new request");
    request = AsyncGPUReadback.RequestIntoNativeArray(ref _data, texture, mipIndex: 0);
    state = EState.WaitReadback;
    break;
    }
    case EState.WaitReadback:
    {
    // Change: wait for request completion if the request has not yet completed
    if (!request.done)
    {
    request.WaitForCompletion();
    state = EState.WaitForFrames;
    framesCounter = 0;
    Assert.IsFalse(request.hasError);
    state = EState.StartJob;
    }
    break;
    }
    case EState.StartJob:
    {
    jobHandle = new Job(_data).Schedule();
    state = EState.WaitJob;
    break;
    }
    case EState.WaitForFrames:
    {
    framesCounter++;
    if (framesCounter > 30)
    {
    state = EState.StartReadback;
    }
    break;
    }
    case EState.WaitJob:
    {
    // Change: wait for job completion if the job has not yet completed
    if (!jobHandle.IsCompleted)
    {
    jobHandle.Complete();
    state = EState.StartReadback;
    }
    break;
    }
    default: throw new ArgumentOutOfRangeException();
    }
    }

    The prior version was not performing the calls to `request.WaitForCompletion()` or `jobHandle.Complete()` as expected resulting in errors when trying to readback again before the native array is done being used.

Comments (1)

  1. citizen-erased

    Sep 27, 2024 16:13

    Thank you for the reply. Unfortunately I don't have access to the submitted bug report project anymore. I also cannot download a copy of the project from the weblinks on the unity3d.atlassian.net page.

    I'm not sure the resolution note solves the problem. The originally submitted code was designed to read data over multiple frames but the proposed solution blocks on both the async readback and the job.

    From the pasted original snippet the code does call jobHandle.Complete() before attempting to start another request. request.WaitForCompletion() should also not be called because it's blocking. The code checked AsyncGPUReadbackRequest.done to determine when it was complete.

Add comment

Log in to post comment