Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

DrawMeshInstanced without data transfer overhead each frame (CommandBuffer?)

Discussion in 'General Graphics' started by james_unity988, Apr 23, 2019.

  1. james_unity988

    james_unity988

    Joined:
    Aug 10, 2018
    Posts:
    71
    Hi there,

    I am building a custom system for drawing lots of the same objects simultaneously, using MaterialPropertyBlock to customize how each object looks. However, most of the settings will be exactly the same from frame to frame, with only occasional slight adjustments to specific instances at runtime.

    My concern is that all this data is getting pushed to the GPU every single frame, which doesn't seem very efficient to me when there aren't many changes happening.

    My question is: can I re-use a CommandBuffer from one frame to another without the overhead of pushing new data to the GPU each frame?

    Thanks
     
  2. LennartJohansen

    LennartJohansen

    Joined:
    Dec 1, 2014
    Posts:
    2,394
    you can use DrawMeshInstanceIndirect and have the per item data in a structured buffer.
    This way all the instances are stored on the GPU and there is no extra copy.

    when you need to update some per item data you can use a compute shader to just update the needed indexes in the structured buffer.
     
  3. james_unity988

    james_unity988

    Joined:
    Aug 10, 2018
    Posts:
    71
    Woah, really? Can anyone be so kind as to point me to an example?
     
  4. LennartJohansen

    LennartJohansen

    Joined:
    Dec 1, 2014
    Posts:
    2,394
  5. james_unity988

    james_unity988

    Joined:
    Aug 10, 2018
    Posts:
    71
    That part I see, but what about using a Compute Shader to update individual values as opposed to re-uploading the whole buffer each time it changes?
     
  6. LennartJohansen

    LennartJohansen

    Joined:
    Dec 1, 2014
    Posts:
    2,394
    Lets say you have a compute buffer with a struct that holds the per item data of 100 000 instances you render.
    You then want to update 100 of them with new data. You know the index in the large buffer/array where you want the data updated.

    Make a new compute buffer with a count of 100 that holds the data you want to update and the index of the original instance in the large list.

    then make a compute shader you assign both the large and the new (100 item) compute buffer to.
    Dispatch the kernel and set it to run 100 times.

    when the compute shader runs it gets its own index, gets the struct from the (100 item) compute buffer.
    from that it gets the index in the large buffer and updates the per instance data.

    This way you only copy the changed data for the 100 items to the GPU and update the data in the large structured buffer.
     
  7. BakeMyCake

    BakeMyCake

    Joined:
    May 8, 2017
    Posts:
    175
    Pardon me for barging in on this discussion, but do you happen to know if there are any limitations to this approach? Do all gpus with compute shader support can do this?
     
  8. LennartJohansen

    LennartJohansen

    Joined:
    Dec 1, 2014
    Posts:
    2,394
    I think it should work on all. There is some limits per platform on how many buffers you can add to a compute shader but I think they all support at least 8.
     
    BakeMyCake likes this.
  9. james_unity988

    james_unity988

    Joined:
    Aug 10, 2018
    Posts:
    71
    More specifics can be found here: https://docs.unity3d.com/Manual/class-ComputeShader.html

    Some features are platform dependent.
     
  10. cert

    cert

    Joined:
    Feb 10, 2013
    Posts:
    24
    How can i update the large buffer? I think i have to use RWStructuredBuffer for the large buffer to have write access?