Search Unity

Resizing StructuredBuffer

Discussion in 'Shaders' started by m506, Jan 9, 2021.

  1. m506

    m506

    Joined:
    Dec 21, 2015
    Posts:
    93
    Hi there;

    I have a script that creates a ComputeBuffer that maps to a StructuredBuffer in a shader, which works fine.

    The problem is that sometimes the instances count changes which forces me to recreate the ComputeBuffer, which is time consuming and generate GC depending on the number of instances, so I checked that there is a function called "SetCounterValue()" but I couldn't make it work properly.

    Is there any way of resizing the StructuredBuffer count so that I can reuse it? If not, can I change the buffer type (Apend/Consume/Counter) and achieve the same effect via script?

    Thank you for your time
     
    deus0 likes this.
  2. deus0

    deus0

    Joined:
    May 12, 2015
    Posts:
    256
    I am asking myself this right now too haha.
     
  3. Neto_Kokku

    Neto_Kokku

    Joined:
    Feb 15, 2018
    Posts:
    1,751
    You don't have to use the full buffer. If your instance count is managed in your C# code, you can just make a large enough buffer for your worst case scenario and pass the instance count to the shader telling it how many instances there are in the buffer (as long as that number is smaller than the actual buffer size, of course).

    If you don't know in advance your maximum number of instances, you can use a "growth" strategy which reduces the number of times you re-create the buffer, at the cost of having unused space in the buffer.

    For example, you could start the buffer with a fixed amount, and if the number of instances go beyond that amount you recreate the buffer with double the original size, or increase the size by fixed increments (I like to do both: start up doubling then cap size increments to a fixed value to prevent the buffer from becoming too massive at large element counts, but you need to fine tune to your use case, of course).
     
    deus0 likes this.
  4. deus0

    deus0

    Joined:
    May 12, 2015
    Posts:
    256
    Hey thank you for the reply, the growth strategy will work for my grass shader, but certainly not for my particles that change too rapidly!
    Edit: On second thought it will still reduce bigger changes, so may be worth it. Do you think it saves gpu processing?
     
  5. Neto_Kokku

    Neto_Kokku

    Joined:
    Feb 15, 2018
    Posts:
    1,751
    The GPU doesn't care how large the buffer is in terms of processing. If you have a known maximum number of particles, you can just allocate a buffer large enough to fit your worst case and just use the portion you need.
     
    deus0 likes this.
  6. deus0

    deus0

    Joined:
    May 12, 2015
    Posts:
    256
    I'm building a sandbox so those things aren't known. I wouldn't want to inflate my games usage of GPU ram and up the games tech requirements!

    I think the buffer is a stack in memory so I then it's not possible I guess to resize. Recreation only perhaps. I haven't tested for larger particles yet, but I imagine resizing 1gb of particle memory alot would be expensive?
     
  7. comettailz

    comettailz

    Joined:
    Feb 1, 2022
    Posts:
    14
    You could recreate the buffer at certain states/events - but probably not a good idea to do this every frame.
    You will be blocking the GPU until the buffer is created, where as its best to setup the buffer once on start (with the maximum possible size, as mentioned in the thread) and let the GPU do its work uninterrupted every frame (by reading and writing to a portion of this buffer)

    At start, you can create a vertex buffer with the maximum possible vertex count for the base geometry.

    This vertex buffer, along with the argsbuffer (vertex count, instance count, offsets) can be populated in realtime using a compute shader.
    And you could then use "CommandBuffer.DrawProceduralIndirect" for indirect-drawing.
     
    Last edited: Feb 19, 2022
  8. Neto_Kokku

    Neto_Kokku

    Joined:
    Feb 15, 2018
    Posts:
    1,751
    Well, you need to set a limit somewhere. Your game will probably crash on some machines if you get to a large enough buffer that either hits the maximum size available for that GPU/API or run out of VRAM.

    Also, no, there's no resizing. You need to create a new buffer and copy everything over from the old buffer, which means that you need to have enough memory available for both old and new buffer to exist during the process. So if you have a 900mb buffer and now you want to "resize" to 1gb, you'll use 1.9gb of memory temporarily. By the way, this is how C# lists work too under the hood: there's an internal buffer, which is usually larger than the item count, and when it needs to grow it must create a new buffer, copy the content over, then delete the old buffer.
     
    jjbish likes this.