Search Unity

Forced 3 frames on compute buffer readback regardless of how long those frames are.

Discussion in 'Shaders' started by michal_gjk, Dec 27, 2020.

  1. michal_gjk

    michal_gjk

    Joined:
    Aug 13, 2016
    Posts:
    69
    EDIT: Bug Report Case: 1304040

    When running even the simplest ComputeShader and then reading the result back with AsyncReadback it seems obvious the readback is forced to wait 2 or 3 frames.
    What's really weird about it is that this happens regardless of whether V-blank is ON or not. In other words with v-blank OFF readback "only" waits about 3 * 3ms = 9ms but with v-blank set to "every other" it waits 3 * 33ms = 100ms.
    I hope it's plain to see this makes Compute unnecessarily cumbersome to use in low FPS scenarios.

    I didn't report this as a bug yet because I'm not sure if it's not forced by the driver / architecture somehow.

    Unity 2018.2 as well as 2020.2
    Windows 10 x64
    Direct 3D 11

    example code:

    Note: Command Buffer is used!

    ComputeReadbackTest.cs

    Code (CSharp):
    1.  
    2. using System;
    3. using System.Collections.Generic;
    4. using System.Threading;
    5.  
    6. using UnityEngine;
    7. using UnityEngine.Rendering;
    8.  
    9.  
    10. public class ComputeReadbackTest : MonoBehaviour
    11. {
    12.   private ComputeShader testShader;
    13.   private int CSMainKernelIndex;
    14.   private int resultBuffID;
    15.   private ComputeBuffer resultCB;
    16.   private int frame;
    17.   private volatile bool nextDispatchOK = true;
    18.  
    19.  
    20.   private void Start()
    21.   {
    22.     testShader = Resources.Load<ComputeShader>("TestComputeShader");
    23.     CSMainKernelIndex = testShader.FindKernel("CSMain");
    24.     resultBuffID = Shader.PropertyToID("Result");
    25.     resultCB = new ComputeBuffer(1, 16, ComputeBufferType.Default);
    26.     testShader.SetBuffer(CSMainKernelIndex, resultBuffID, resultCB);
    27.   }
    28.  
    29.   private void Update()
    30.   {
    31.     if(!nextDispatchOK)
    32.       return;
    33.  
    34.     nextDispatchOK = false;
    35.     CommandBuffer commandBuffer = new CommandBuffer();
    36.     commandBuffer.DispatchCompute(testShader, CSMainKernelIndex, 1, 1, 1);
    37.     frame = Time.frameCount;
    38.  
    39.     // 2018.2 or newer
    40.     commandBuffer.RequestAsyncReadback(resultCB, AsyncGPUReadbackCallback);
    41.  
    42.     Graphics.ExecuteCommandBuffer(commandBuffer);
    43.  
    44.     if(nextDispatchOK)
    45.       Debug.Log("Callback called.");
    46.   }
    47.  
    48.   private void AsyncGPUReadbackCallback(AsyncGPUReadbackRequest req)
    49.   {
    50.     nextDispatchOK = true;
    51.  
    52.     if(req.hasError)
    53.       Debug.LogError("Readback error!");
    54.  
    55.     if(frame == Time.frameCount)
    56.       Debug.Log("Same frame!");
    57.     else
    58.       Debug.Log("start frame: " + frame + "; end frame: " + Time.frameCount);
    59.   }
    60. }
    61.  
    TestComputeShader.compute

    Code (CSharp):
    1.  
    2. #pragma kernel CSMain
    3.  
    4. RWStructuredBuffer<float4> Result;
    5.  
    6. [numthreads(1, 1, 1)]
    7. void CSMain(uint3 id : SV_DispatchThreadID)
    8. {
    9.     Result[id.x] = float4(id.x & id.y, (id.x & 15) / 15.0, (id.y & 15) / 15.0, 0.0);
    10. }
    11.  
     
    Last edited: Jan 6, 2021
  2. michal_gjk

    michal_gjk

    Joined:
    Aug 13, 2016
    Posts:
    69
    Issue doesn't seem to raise any interest on the forum so I decided to report it. Hopefully more luck in the issue tracker.