Search Unity

Buffers and Compute Shaders

Discussion in 'Scripting' started by Major, Jun 25, 2015.

  1. Major

    Major

    Joined:
    Jul 26, 2012
    Posts:
    69
    I am new to these, and I can't really find any good definition that is really clear on exactly what these are for. So what are buffers used for in Compute Shaders, and in what situations should they be used?
     
  2. Major

    Major

    Joined:
    Jul 26, 2012
    Posts:
    69
    if no one can provide help for this topic, I think Unity needs to make a detailed tutorial on the subject.
     
  3. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,175
    Last edited: Jun 29, 2015
  4. Major

    Major

    Joined:
    Jul 26, 2012
    Posts:
    69
  5. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    Don't worry, you can send whatever data to the compute shader you want to. Then you can modify it on the GPU if you want and then read it back into an array on the CPU side (in your C# code).

    This looks like a good introduction and tutorial: http://scrawkblog.com/2014/06/24/directcompute-tutorial-for-unity-introduction/

    I spent a couple of months a year ago writing a pretty complex compute shader and haven't done it since, so I'll try to recall the best I can:

    Buffers can be used to read from and write data to the graphics card. On the shader side you usually use a RWStructuredBuffer. On the CPU side it's "just a buffer" so to speak. (RW here means read/write). So for instance you create an array on the CPU side, fill it with data, then send it to your shader's RWStructuredBuffer with a call to SetBuffer(). Then you call Dispatch() which runs the shader. In the shader you then modify the RWStructuredBuffer if you want to, then read it back on the CPU side with GetBuffer() into whatever array you want. (I think that's how it worked, it's been about a year so I might be missing a detail or two off the top of my head).

    Here's what I did last summer:



    This is running a real time car engine simulation with the exhaust gas dynamics modelled to drive the audio. There are no sound files here, it's all generated procedurally on the fly from the physics of the gas dynamics of the car engine's exhaust system in real time. It's running at 500,000 cycles per second (imagine a Unity time step of only 0.000002 seconds), about 40 billion+ computations per second in all, way more than a CPU could do unless you have about 40 cores to spare. The only thing the CPU does here is render the squiggly lines and the numbers on the screen, the rest is all done in the compute shader. Compute shaders rock. :D

    So yeah, you can read and write data to/from the graphics card about any way you can imagine. There's a lot to learn though, be prepared to dig deep and spend the time to learn about thread groups, shared memory on the GPU, and so forth.
     
  6. Major

    Major

    Joined:
    Jul 26, 2012
    Posts:
    69
    Well then it seems that the data I am setting is not getting to the GPU. I did all those steps but it seems that the data in the buffer is always 0, even if I set it by script. Just in case I am doing something wrong here, this is the code I am using in the start function:

    buffer_0 = new ComputeBuffer(stars.Length, 12);
    int[] t = new int[]{8};
    buffer_0.SetData(t);
    shader.SetBuffer(0, "buffer", buffer_0);

    and this is the code I am using in update:

    shader.Dispatch(0, 1, 1, 1);

    and for the compute shader this is the buffer:

    RWStructuredBuffer<int> buffer;

    and in the main thread of the GPU I am using:

    tex0[int2(buffer[0], 0)] = float4(1,1,0,1);

    Does this look correct?

    I also followed a lot of those tutorials on that blog, but a lot of the ones on buffers use normal shaders as well. While I can follow along with the compute shader section and c# section, I still have problems when it comes to getting the buffers to actually work. Everything else I can get to work just fine, it's just the buffers.
     
    Last edited: Jul 1, 2015
  7. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    It's been over a year for me since I've looked at any of this so I can't say for sure, so double check what I say here. I'm just scanning my old engine simulation code here.

    1) Is that t[] array being initialized correctly?

    2) It's probably getting to the GPU but you're not reading it back. When you write to the RWStructuredBuffer buffer it looks like you're trying to access the buffer directly with the tex0[] call with the shader's buffer variable right in there. That won't work, you can't access the shader variable directly from the CPU side like that. You have to call GetData() to read the RWStructuredBuffer buffer[] back into another array on the CPU side if you want to use it there. Probably what you'll want to be doing is using SetData(t) like you're doing to initialize the buffer one time in Start() or similar, then after it's modified on the compute shader side you want to read it back into a different array with GetData(someOtherArray). Then use someOtherArray inside your tex0[].

    When I started out I did everything as simply as possible. I wrote out something like your t[] array to the graphics card with SetData() and then read it back into a second array using GetData(), then I just printed the results to the console with print(). Then I put the Dispatch() and GetData() call in a loop, changed the shader to add 1 to the buffer values and read them back each time in a loop and print() the results over and over in Update(). I think that tutorial I linked to probably does something similar on the later pages. It'd be worth a look if you haven't had a chance yet.

    This is what I used as a reference when I first started: http://answers.unity3d.com/questions/442604/reproducing-dx11-sdks-nbodygravity-example.html

    I didn't do the actual example (it's pretty big and nasty), but it shows how to do GetData and SetData, set up the ComputeBuffer and all that stuff. Probably the earlier link I posted will be more clear, but there it is just in case. I know it helped me anyway.
     
  8. Major

    Major

    Joined:
    Jul 26, 2012
    Posts:
    69
    Right so to get the data back to the CPU I should use GetData(). But what if I want to run the operation with the data sent from the CPU to the buffer, and just stop there. Simply put CPU sends pixel coordinates to the buffer, and the GPU uses those pixel coordinates to paint an image, say a square. Is there a similar GetData() function in HLSL? I want start out simple to understand these concepts so that I can later do something crazy awesome, like planet generation or volumetrics.
     
  9. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    Sorry, I wouldn't know where to begin rendering stuff with a compute buffer.

    As for the data stuff, the SetData and GetData functions are on the CPU side. The purpose of those as I understand them is to copy arrays to and from whatever buffers you have set up (RWStructuredBuffers for example) which is memory on the GPU instead of RAM. So there isn't any HLSL equivalent beause it needs to be done on the CPU side.

    You are free to just send data once and let the compute shader sit there modifying it over and over again. That's how my engine simulation works, there are hundreds of cells in the exhaust system that have a gas state. That stuff is just set up one time in Start(), every Dispatch call after that modifies it on the shader side on the RWStructuredBuffers which are what's sitting in GPU memory. (Actually it runs a loop in the shader 50,000 times or so, it's just crazy fast when you take advantage of groupshared memory.)
     
  10. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    (Dumb phone posted before I was done. Continuing.)

    Then I have other buffers that are used to create the graphs, but that's all done with OpenGL calls, not the compute shader, after getting the point data. So no, I don't even know how to render a cube with a compute shader, much less manipulate pixel data. Sorry.
     
  11. Major

    Major

    Joined:
    Jul 26, 2012
    Posts:
    69
    Okay, let me put it this way. How did you access the buffer on the GPU side of things?
     
  12. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    What you can't do though is use buffer inside of that tex array you have though unless that's defined somewhere else not shown there and it's being filled with a GetData call. There might be some way to pass that info to a pixel shader or something. I really don't know.
     
  13. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    Something like this:

    shaderBufferName(i) = 2;

    Replace parantheses with brackets, I'm on my phone which is a bit limited. It's pretty much like regular C# code. i is the thread index, so have a good read about those in the tutorial I posted. It looked like it covered that.
     
  14. NavyFish

    NavyFish

    Joined:
    Aug 16, 2013
    Posts:
    28
    Slightly off-topic but hopefully helpful question - is there a way to pass 'uniforms' (per-dispatch constants) to a compute shader? I'm currently saving them to a StructuredBuffer and reading them as a struct in the shader, but wasn't sure if there was a simpler method. Thanks!
     
    Last edited: Jul 16, 2015
  15. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
  16. NavyFish

    NavyFish

    Joined:
    Aug 16, 2013
    Posts:
    28
    A bit late, but hopefully I can help. If I understand your objective, it's to send data to the GPU, use a compute shader to do some processing on that data, and then use the results of that processing to draw something.

    The way to do this is to store the results of your computation into another ComputeBuffer. This ComputeBuffer should be attached to a material. Then, in the shader for that material, use a custom vertex or pixel shader to read values out of the ComputeBuffer and draw with them.

    I used the following sites to help me get going:

    http://kylehalladay.com/blog/tutorial/2014/06/27/Compute-Shaders-Are-Nifty.html
    http://scrawkblog.com/2014/06/26/directcompute-tutorial-for-unity-kernels-and-thread-groups/
     
    Todd-Wasson likes this.
  17. Jiraiyah

    Jiraiyah

    Joined:
    Mar 4, 2013
    Posts:
    175
    http://scrawkblog.com
    this website went down? DAMN it had few compute shader libraries I'm looking for, specially the perlin ones and the voroni one, any one can provide those compute shaders for me?
     
  18. dantistnfs

    dantistnfs

    Joined:
    Nov 28, 2016
    Posts:
    8
    Hey, i found this: http://qiita.com/scnsh it's reposts of scrawk's blog. Probably you will find what you want or some info on compute shaders.