Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Compute shader async problem [Resolved]

Discussion in 'Shaders' started by Shinao, Jan 21, 2018.

  1. Shinao

    Shinao

    Joined:
    Mar 7, 2014
    Posts:
    36
    Hello,

    Here is how it goes :
    I use ComputeShader.Compute() which is instant because Unity does not wait for it to finish.
    If I want to wait for it, I can do ComputeBuffer.GetData().
    If my compute shader takes 50ms to execute, it makes sense that GetData() will wait 50ms and a bit more to retrieve the data.
    If I insert a Thread.Sleep(5) between Compute() and GetData(), in my opinion, GetData() should wait 5ms less than before, because the GPU had time to Compute() in the meantime.
    That's not the case though, GetData() waits the same amount of time.

    What am I not getting ?

    I've made a very minimal example of my problem that you can download.
    Increase "WorkLoad" to make the ComputeShader take more time to finish.

    Thanks
     

    Attached Files:

  2. Atair

    Atair

    Joined:
    Oct 16, 2015
    Posts:
    42
  3. Shinao

    Shinao

    Joined:
    Mar 7, 2014
    Posts:
    36
    No, I do not want to read data from the GPU to the CPU, what I want is to know why my Dispatch() is not truly async in my example, for that I have to use GetData() to wait for it.
     
  4. Zolden

    Zolden

    Joined:
    May 9, 2014
    Posts:
    141
    Unity does wait for GPU to finish its job on current Update(). It just doesn't wait inside Update(). Profiler shows that Gfx.WaitForPreset thing gets bigger linearly proportional to GPU load.

    CPU side thread works in parallel with GPU after a kernel is dispatched. For example, if I configured a kernel to run for 500 ms per update, Gfx.WaitForPreset will wait those 500 ms. But if I add Sleep(500), profiler will show that Update() takes 500 ms and no Gfx.WaitForPreset is involved. But in case of Sleep(250) Update() will take 250 ms, and Gfx.WaitForPreset will wait for another 250 ms.

    But GetData() is a different thing. If we add GetData() after Wait(600) ms, one Update() will take much more than 600 ms in total. Even though we are sure: GPU work only took 500 ms, and should be done after Sleep(600) ended. Why is this, why to wait more? Short answer: because gpu pipeline stall is involved. What does it mean? I don't know for sure.
     
  5. Shinao

    Shinao

    Joined:
    Mar 7, 2014
    Posts:
    36
    Bvenjamin likes this.
  6. aberroarman

    aberroarman

    Joined:
    Feb 1, 2019
    Posts:
    2
    My guess that your problem is that compute shader is not actually dispatched until Update() is completed OR GetData() is called. So, you enqueued your invocation into gfx dispatcher, then stopped your entire thread without exiting Update(), which took 5ms, then called GetData(), so gfx dispatcher now should process it's queue and it takes 50ms.
    You should instead call GetData first and then Dispatch (or just use new Unity version with async data reads). This way at the beginning of Update your data should be ready and wait to be sent to CPU memory and at the end of Update you'll dispatch your next invocation to compute shader to process at this frame. Of course that means that at your first Update invocation your data would be empty, but you can easily check it, skip processing and just dispatch your shader.
     
    randomdragon likes this.