Search Unity

GraphicsBuffer, Mesh vertices and Compute shaders

Discussion in 'General Graphics' started by Ignifex, Nov 14, 2019.

  1. Ignifex

    Ignifex

    Joined:
    May 6, 2015
    Posts:
    11
    I am working on a project that performs manual skinning for meshes. For performance reasons this is currently running on the GPU through Compute Shaders. The resulting vertices are fed to a vertex shader through Compute Buffers. This is clearly not ideal. I would much prefer a way to update the mesh data directly, on the GPU, so that no changes to shaders are needed.

    I noticed that a new GraphicsBuffer type has been introduced recently, which is used to supply an index buffer in a call to DrawProcedural.
    Are there are any plans to allow users to get the GraphicsBuffer containing the vertex data of a mesh? And will GraphicsBuffer be compatible with Compute Shaders?

    I realize this has been asked before, for instance in this topic:
    https://forum.unity.com/threads/graphicsbuffer-and-mesh.636631/
    However, seeing as how that topic is in an archived beta section, I wanted to request this feature here as well.
     
    deus0 and LooperVFX like this.
  2. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Hey! Yes it's planned, and we are actually doing some work at the moment to move this feature request forwards.
     
  3. Ignifex

    Ignifex

    Joined:
    May 6, 2015
    Posts:
    11
    Thank you, that is great to hear!
     
    richardkettlewell likes this.
  4. JiangBaiShi

    JiangBaiShi

    Joined:
    Aug 3, 2019
    Posts:
    27
    Really look forward to this, Hopefully we could finally use graphics buffer to do some serious graphics stuff in unity
     
  5. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Our current alpha (2020.1) contains improvements in this area:
    * All API that takes a ComputeBuffer now can take GraphicsBuffer too
    * Can write to a GraphicsBuffer from Compute then use it in Graphics.DrawProcedural as an index buffer, by creating the buffer with Target.Index | Target.Raw flags.

    I'm not sure if the mesh API has the required pieces in it yet to let you read/write its vertices in a compute shader though. I'll ask the team :)
     
    alpha_rat and Egad_McDad like this.
  6. JiangBaiShi

    JiangBaiShi

    Joined:
    Aug 3, 2019
    Posts:
    27
    Thanks for reply! actually I want to know how to use GraphicsBuffers with "Vertex" and "Index", or are they just useless flags for now?
     
  7. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    You should be able to create a buffer with index | raw, fill it in from a compute shader then use it with DrawMeshProcedural.

    Same for vertex except that one is currently useless because I don’t think any unity api let’s you use the buffer you can build in compute.
     
  8. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    862
    Hi @richardkettlewell GraphicsBuffer is great news. Does it / will it support append/consume buffers with varying dynamic count?
     
  9. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Yes. It's everything that ComputeBuffer ever was, plus the ability to behave like things that have nothing to do with Compute, such as Vertex and Index Buffers.

    For example, you should be able to fill a buffer in Compute, then draw that same buffer like it was a Vertex Buffer. (data appears in the shader as POSITION, COLOR, TEXCOORD0, etc) That's the goal we are working towards, and having a buffer type that doesn't have "Compute" in the name is an important step towards that.
     
    fherbst, deus0, Egad_McDad and 2 others like this.
  10. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    862
    @richardkettlewell Excellent! For me, that's the best news from Unity in a long while. That, and multicompile for ComputeShaders.

    It would be great to have examples of use in the Unity docs.
     
    ChristopherKerr and Opeth001 like this.
  11. JonRurka

    JonRurka

    Joined:
    Nov 19, 2012
    Posts:
    35
    So what I am getting from this is the GraphicsBuffer can be used to render an index array generated from the compute buffer with Graphics.DrawProcedural?

    But in the material shader, I should be able to use the "uint vertexId : SV_VertexI" vertex program input to read from a Compute Buffer containing the vertex positions, and set the vert position from inside the vertex program.

    I will test this out at some point soon...
     
    cecarlsen and richardkettlewell like this.
  12. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    862
    I just tired out GraphicBuffer indices in 2020.1.0b5 and it seems to work as expected.
    https://github.com/cecarlsen/HowToDrawATriangle

    Now a couple of questions come to mind @richardkettlewell

    1) When can we expect to see GraphicsBuffer.Target.Vertex to be working in a public beta?

    2) Am I correct that a GraphicsBuffer.Target.Vertex will finally make it possible to use DrawProcedural and ShaderGraph together? If the vertices are provided like a mesh with vertex shader semantics I don't see why not.

    3) What is the fate of ComputeBuffer? Will it be phased out? GraphicsBuffer.Target seems to cover what ComputeBufferType did and more. So why keep it? And if that is the case, why didn't you expand the features of ComputeBuffer instead of adding a new type?
     
    Egad_McDad likes this.
  13. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    1) Sorry I don't know when it will land, or how hard we are pushing to add this ability at the moment.

    2) For this, all I think is needed is for Shader Graph to let you work with the vertex index semantic (SV_VertexID in DX11, each platform has its own name for it) I don't think GraphicsBuffer/ComputeBuffer is related at all

    3) Yes ComputeBuffer will (one day...) disappear. But usage is almost 100% today. So it is not any day soon. Why not extend ComputeBuffer? Because ComputeBuffer is badly named - it implies it has something to do with Compute and Compute Shaders. GraphicsBuffer is for any type of rendering buffer. Extending ComputeBuffer would be confusing.
     
    Egad_McDad likes this.
  14. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    862
    Push, push, we need this =)

    If GraphicBuffer vertices support vertex shader semantics, wouldn't that eliminate the need for binding custom vertex ComputeBuffers to shaders for use with DrawProcedural? And wound't that mean that default shaders as well as ShaderGraph compiled shaders would accept GraphicBuffer verticies through DrawProcedural just like they accept Meshes through MeshFilter and MeshRenderer?

    Good to know.
     
    deus0 and CyRaid like this.
  15. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    I passed it along to the team :)

    Oh I guess you are meaning if we also added a new script API version of DrawProcedural that took a "vertex" GraphicsBuffer, rather than our current options of Index, and vert/instance counts? Yeah if we also added that, you could draw meshes with only DrawProcedural, and they would work with ShaderGraph because ShaderGraph understands the common vertex inputs like position, texcoord, normal etc.
     
    adamhill likes this.
  16. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    862
    Thank you.

    Exactly! This is exactly what we need. It would be an amazing feature for anyone working with procedural/generative content. There are many benefits from doing this ... perhaps the greatest being that that code for GPU bound procedural content creation can be decoupled from specific SRPs, or perhaps that every existing shader would work with GPU bound procedural content. Currently, it is a pain to write DrawProcedural compatible shaders for HDRP. And for URP, although there is an API for it, things like shadows are not even supported at the moment.
     
  17. JonRurka

    JonRurka

    Joined:
    Nov 19, 2012
    Posts:
    35
    In this example, you set the vertex from inside the compute shader and it can be read from inside the graphics shader with the DrawProcedural call. However, you set the GraphicsBuffer from inside C# rather than inside the compute shader. Was this due the same issue I came across? The issue I'm having with the version I made for my project, however, is that when I create a graphics Buffer for indices (using sizeof(int)), Assign it to a RWStructuredBuffer<int>, I am unable to pull data out of the compute shader. If, in the C# end, I turn

    GraphicsBuffer g_buff = new GraphicsBuffer(GraphicsBuffer.Target.Index, indexBuff_size, sizeof(int));

    to

    ComputeBuffer g_buff = new ComputeBuffer(indexBuff_size, sizeof(int));

    It works; With ComputeBuffer g_buff.GetData(), I get an array with valid data. With the GraphicsBuffer, I get an array of all zeros.

    richardkettlewell, is GraphicsBuffer actually able to be written to from a compute shader yet?
     
  18. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    It depends. In 2019.3, it can only be used as an index buffer.
    In 2020.1, yes, you can write to them in compute shaders.

    You haven't set up this graphics buffer to be writable from compute. you have only said you want to use it as an index buffer. You probably need to add GraphicsBuffer.Target.Raw, to write from compute (assuming it is declared as a RWByteAddressBuffer in the compute shader. Use Structured instead of Raw if its a RWStructuredBuffer inside the shader.)
    But this requires Unity 2020.1.
     
    deus0 likes this.
  19. CyRaid

    CyRaid

    Joined:
    Mar 31, 2015
    Posts:
    134
    Aww nuts. I could currently really use the vertex target support for my project. Definitely need the ability to generate vertices from compute. :)
     
  20. Nexusmaster

    Nexusmaster

    Joined:
    Jun 13, 2015
    Posts:
    365
    Hi Richard,
    thanks for the help! However when I try to use
    Code (CSharp):
    1. var indexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Index | GraphicsBuffer.Target.Structured, count, sizeof(int));
    I get following errors:
    Failed to create Compute Buffer UAV, HRESULT: 0x80070057
    Failed to create Compute Buffer SRV, HRESULT: 0x80070057

    When I use GraphicsBuffer.Target.Raw instead of GraphicsBuffer.Target.Structured it works, but I like to use a RWStructuredBuffer ... any idea how to fix that?

    Btw.: I'm using Unity 2020.1.0.b13.

    Also Graphics.DrawProceduralIndirect(_goMat, _mesh.bounds, MeshTopology.Triangles, _indexBuffer, _bufferWithArgs); is not working!

    Best regards,
    Chris
     
    Last edited: Jun 29, 2020
  21. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    I think it's a limitation of some platforms (eg DirectX 11 on windows does not allow this combination, so it is impossible for Unity to support it.)

    It would be better if we provided a better error message tho.

    It means you must also use [RW]ByteAddressBuffer in your shaders.
     
  22. eagle555

    eagle555

    Joined:
    Aug 28, 2011
    Posts:
    2,705
    Also looking forward to be able to write vertex data in compute. You have an ETA when or Unity version where this will be available?
     
  23. Lecks

    Lecks

    Joined:
    May 13, 2013
    Posts:
    18
    I think you missed CommandBuffer.SetComputeBufferCounterValue
     
    richardkettlewell likes this.
  24. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    You're right :( I'm sorting that out right now, for 2020.2 at least. Probably too late for 2020.1.
     
    Lecks likes this.
  25. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    So.. management don't want to take the fix for 2020.2. Risk avoidance and all that... so if you want/need it in the Unity 2020.2 (or envisage needing it in the Unity 2020 LTS), can you log a bug, reply here with the case number, and I can try to use that to change their minds. If it's important to you.
     
  26. Lecks

    Lecks

    Joined:
    May 13, 2013
    Posts:
    18
    It would just allow for some slight optimization in my case that might not even make any difference (I can reset the counter outside the command buffer).

    What I would really like is a way to use ShaderGraph with data created in a compute shader. This could be done with:
    A. DrawProceduralIndirect that lets you set a vertex buffer/vertex description.
    B. A way to set Mesh data directly from ComputeBuffers or GraphicsBuffers.
    C. Nodes in ShaderGraph for SV_VertexID and a custom struct array.
    I think A would be simplest/most user friendly, followed by B then C.

    Correct me if I'm wrong, but I believe currently to do this you need to:
    - Copy the data back to the CPU and set it on a Mesh.
    OR
    - Export the HLSL for the ShaderGraph and modify it to use the custom vertex array/SV_VertexID.
    OR
    - I haven't tried this, but I guess if a compute shader packed the data into texture(s), a constant vertex buffer with fixed UVs could be used to index them.
     
    lemeto123 likes this.
  27. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Me too!

    I assume it must be on their roadmap, but I don't know personally. you could probably ask here to get a definitive answer on when this feature might appear: https://forum.unity.com/forums/shader-graph.346/

    Indeed today it requires copying back to a mesh, which is horribly inefficient. Copy to the CPU just to send it back to the GPU in a format that ShaderGraph can accept...
     
    LooperVFX likes this.
  28. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    862
    richardkettlewell likes this.
  29. GameDeveloper1111

    GameDeveloper1111

    Joined:
    Jul 24, 2020
    Posts:
    100
    I, too, would like the ability to generate vertices in a compute shader without having to send them to the CPU and back.

    My use case is extending the HDRP Lit shader with a vertex shader. One solution without modifying the HDRP Lit shader code could be to simulate a vertex shader via a compute shader, but something like GraphicsBuffer.Target.Vertex is needed. (Using Shader Graph won't work for me here since I need the actual HDRP Lit shader, not Shader Graph's Lit base.)

    The post about my use case is here:
    https://forum.unity.com/threads/adding-a-vertex-shader-to-lit.1037011/
     
  30. DanielZeller

    DanielZeller

    Joined:
    Nov 18, 2014
    Posts:
    18
    Could you please give a ComputeShader example of how to write triangle indices to a ByteAddressBuffer? I think many of us are a bit confused about how to use ByteAddressBuffer's compared to StructuredBuffers where you have the data type defined :)

    One more question, where can I find the documentation for the values that should be sent to the arguments buffer when using DrawProceduralIndirect? I've seen some examples of usage, but I'm unable to find the documentation of what the values actually mean.
     
    Egad_McDad likes this.
  31. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    for this, there is a bit of info here that names the arguments: https://docs.unity3d.com/ScriptReference/Graphics.DrawProceduralIndirect.html

    then there is some more description here: https://docs.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-drawinstanced

    note that the final parameter, StartInstanceLocation, does not work on d3d11 and some other platforms.
     
  32. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    I don’t have anything specifically to write triangle indices, but this compares doing the same thing with a structured buffer vs a byte address buffer: https://github.com/walbourn/directx-sdk-samples/blob/master/BasicCompute11/BasicCompute11.hlsl

    It’s basically like a StructuredBuffer<uint>.
    To read and write, call Load and Store with a byte offset (ie 4 bytes per uint)

    There are Load2/3/4 and Store2/3/4 to get/set vector types in a single command (eg uint2,uint3,uint4)

    Because they have no type in the shader, use asfloat or asint to bit-cast to the type you are using.

    I think that’s pretty much it :)
     
    Last edited: Feb 12, 2021
    Egad_McDad likes this.
  33. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    862
    Hi @richardkettlewell, are there any news on GraphicsBuffer as vertex buffer to be used with DrawProcedural? I don't see much in the 2021.1 beta release notes. It the work still in progress, or stalled? It is a long wait.
     
    Egad_McDad likes this.
  34. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Unfortunately I don’t think the graphics team are working on it at the moment
     
  35. DanielZeller

    DanielZeller

    Joined:
    Nov 18, 2014
    Posts:
    18
    Thanks for the replies. That answers my questions :)
     
    richardkettlewell likes this.
  36. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    862
    Thanks for getting back.

    This is becoming increasingly frustrating. When you do any real time GPGPU/Compute geometry work and want to render it, there is no other option other than to write specific renderers and shaders every time. And with the crippling inter-incompatibility of legacy, URP and HDRP the workload just blows up. If only it was possible to set the GPU content of a mesh directly from ComputeBuffers I think we would see a lot more interesting procedural tools being made and shared by the community. I am not sure what good a new concept like GraphicsBuffer does without providing this feature. With the two new render pipelines, Unity has in effect become three separate engines. Really it should be called Trinity at this point. This feature would help glue them together again.

    It is beyond my understanding why this has such a low priority at Unity.
     
    Egad_McDad and Circool like this.
  37. korzen303

    korzen303

    Joined:
    Oct 2, 2012
    Posts:
    223
    @cecarlsen I agree, no idea why Unity makes this so difficult...
     
    Egad_McDad and Circool like this.
  38. korzen303

    korzen303

    Joined:
    Oct 2, 2012
    Posts:
    223
    Hi @richardkettlewell, just wanted to ask when we can expect a straitghtforward way of setting up the GPU content of the mesh directly from Compute/GraphicsBuffers. I am worried whether this is even planned for 2021?

    Besides regular rendering of procedural or simulation content straight from the GPU memory I would like to use it to efficiently construct raytracing acceleration structures for GPU physics simulation.

    Thanks
     
  39. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    This was not in the original plans for 2021. But a few days ago I happened to start working on it, let's see how that goes...
     
  40. korzen303

    korzen303

    Joined:
    Oct 2, 2012
    Posts:
    223
    HI @Aras thats great news! Please let me know if you'd need a helping hand with testing stuff. I am really looking forward to it.
     
  41. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    Btw here's wot I'm thinking C# API wise so far (all additions to existing API classes):
    Code (CSharp):
    1. class Mesh
    2. {
    3.     public GraphicsBuffer GetVertexBuffer(int stream = 0);
    4.     public GraphicsBuffer GetIndexBuffer();
    5.     // By default vertex buffers just have Vertex target, and index
    6.     // buffers just have Index target, but you can request others,
    7.     // e.g. Raw, CopySource etc. The targets are serialized in Mesh data.
    8.     public GraphicsBuffer.Target vertexBufferTarget { get; set; }
    9.     public GraphicsBuffer.Target indexBufferTarget { get; set; }
    10. }
    11. class SkinnedMeshRenderer
    12. {
    13.     public GraphicsBuffer GetVertexBuffer();
    14.     // Vertex buffer of the previous frame (only there when skinned motion
    15.     // vectors are used).
    16.     public GraphicsBuffer GetPreviousVertexBuffer();
    17.     // Request buffers to also be a structured buffer (off by default).
    18.     // By default vertex buffers just have Vertex target, but you can
    19.     // request others, e.g. Raw, CopySource etc.
    20.     public GraphicsBuffer.Target vertexBufferTarget { get; set; }
    21. }
    22. class Graphics
    23. {
    24.     public static void CopyBuffer(GraphicsBuffer src, GraphicsBuffer dst);
    25. }
    26. class GraphicsBuffer
    27. {
    28.     enum Target
    29.     {
    30.         // New additions, needed in order for CopyBuffer to work
    31.         CopySource = (1<<2),
    32.         CopyDestination = (1<<3),
    33.     }
    34. }
    35. class CommandBuffer
    36. {
    37.     public void CopyBuffer(GraphicsBuffer src, GraphicsBuffer dst);
    38. }
    This is just some early WIP thoughts, by no means a final API. Does it make sense?
     
  42. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    862
    This is truly great news @Aras.

    Does this imply that targets are always CPU bound? What is (or will be) GraphicsBuffer.Target exactly?
     
  43. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    It's what already exists for a while... GraphicsBuffer.Target :)
     
  44. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    862
    Doh, should have checked.

    Well, if Mesh will accept Target.Index and Target.Vertex GraphicsBuffers, then that is enough for me to pop the champagne.

    Graphics.DrawProcedural (and it's siblings) takes a Target.Index GraphicsBuffer, but not Target.Vertex. This is equally important to me.

    In terms of API, I am convinced you will come up with something sane, as usual.
     
  45. Ignifex

    Ignifex

    Joined:
    May 6, 2015
    Posts:
    11
    Hi Aras,
    Thanks for picking this up :)
    Looking forward to try this out.
     
  46. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    Last edited: Apr 20, 2021
    Egad_McDad, cecarlsen and Qleenie like this.
  47. DanielZeller

    DanielZeller

    Joined:
    Nov 18, 2014
    Posts:
    18
    This look pretty awesome, excited about this! But in order for it to be fully complete we would need the same as GetVertexBuffer() for the normals -> GetNormalsBuffer(). I imagine this would be specifically relevant when using SkinneMeshRenderers.
     
  48. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    I don't think so. GetVertexBuffer returns the full GPU buffer of vertex data. What it contains depends on the mesh layout, by default most meshes put everything into one buffer (positions, normals, UVs etc.).
     
    Egad_McDad and Qleenie like this.
  49. DanielZeller

    DanielZeller

    Joined:
    Nov 18, 2014
    Posts:
    18
    Aha, all good then! :)
     
  50. ignarmezh

    ignarmezh

    Joined:
    Mar 23, 2017
    Posts:
    56
    Hello!
    Please tell me, for a Built-in project I use a ComputeBuffer to get information about vertices from a vertex shader. But it doesn't work on HDRP.
    Then I tried to use a GraphicsBuffer (with Vertex, Raw and Structured Target), but it also does not help me, after calling GetData() I get an unchanged vertex array, the code is presented below.
    What could be the problem?
    Thanks!

    Code (CSharp):
    1. GraphicsBuffer OutputVertexBuffer;
    2. OutputVertexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Vertex,gameObject.GetComponent<MeshFilter>().sharedMesh.vertexCount,Marshal.SizeOf( typeof( Vector3 ) ));
    3. Vector3[] vertices = new Vector3[gameObject.GetComponent<MeshFilter>().sharedMesh.vertices.Length];
    4. OutputVertexBuffer.SetData(vertices);
    5. Graphics.SetRandomWriteTarget( 1, OutputVertexBuffer, true );
    6. gameObject.GetComponent<Renderer>().sharedMaterial.SetBuffer( "OutputVertexBuffer", OutputVertexBuffer );
    7. yield return new WaitForEndOfFrame();
    8. OutputVertexBuffer.GetData( vertices );