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

Question Is it possible to "stream" vertices from a compute shader into a vertex shader?

Discussion in 'Shaders' started by najati, Jun 11, 2023.

  1. najati

    najati

    Joined:
    Oct 23, 2017
    Posts:
    40
    Hi all, I'm trying to understand typical uses for compute shaders. By way of a simplified example, my use case is generating a large number of relatively simple meshes, all simple variations of a few template shapes. I had hoped to be able to send effectively a list of position+template+variations to the GPU and have the GPU generate the geometry for the instances, and then render them with a given material.

    I've done a decent chunk of reading/tutorialing about compute shaders and understand what seems to be the most common use case of generating a mesh into a buffer and then rendering it with one of the Graphics.Render* methods. I'm wondering if that's possible without the interim buffers.

    I've never used a geometry shader and understand that they had their limitations, but there seems to be a common claim that there's no use for them with computer shaders being so available. One main thing they seemed to provide over compute shaders was the ability to generate geometry and render it directly, without storing it all in one big buffer.

    I can't find anything that suggests the same is possible with a compute shader. Is it, and I'm just missing it?

    If not, are there typical approaches to working around what seems like a limitation to compute shaders for this use?

    Cheers
     
  2. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    Typically, if you're generating geometry on the GPU (at least on SM4.5+ platforms*), you will generate it as a ComputeBuffer with vertices, and then use something like DrawProcedural or DrawProceduralIndirect, where the vertex shader. If the meshes have many repeated vertices, you might want to create index buffers and bind those, but that can be slower for simple meshes and is always going to be more complex.

    You're right. GS still need to output verts to a buffer, but that buffer is a small on-chip one that is re-used, so no need to manually allocate anything. Since it's one draw call, it's easier to manage the shaders and wrapper code that invokes them. We'd all love it if geometry shaders were good, since the spec and API is very developer-friendly.

    The problems with geometry shaders are largely implementation issues. Read that link for some of the gory details From what I understand (I Am Not A Driver Programmer, so this could be all wrong), there were a few technical hurdles with the spec. But these could probably be fixed for the common case with enough engineering effort (just like GPUs do for a lot of other stuff -- for example, the spec says late-Z, but GPUs hacked in early-Z because in 99% of shaders early-Z is just fine).

    However, there was never much incentive for GPU manufacturers to improve geometry shaders or make them actually fast. Developers didn't adopt or use them. Apple killed them on the new iPhones. The most common use case for them was tessellation, which GPU manufacturers eventually made a fast path for. Mesh/amplification shaders are a newer alternative that have a much more narrow spec that's easier to implement. NVIDIA, AMD, Intel, Quallcomm, et al basically just gave up on them.

    I'm sure you could make a whole documentary on "Who killed the Geometry Shader?" and have arguments over whether the spec itself was terrible from the start, or merely "kinda bad" while business decisions did the rest of the job. Either way, GS were bad in 2006 and they're still bad in 2023.

    tl;dr: Yes, geometry shaders will do what you want. But they're slow, not supported on all platforms, and are unlikely to be well supported on new platforms.

    The typical flow is to generate the verts into a buffer using a compute shader, and then use DrawProcedural or DrawProceduralIndirect to put them on screen. This is fast and effective. Just takes a bit more code.
     
    najati likes this.
  3. aras-p

    aras-p

    Unity Legend

    Joined:
    Feb 17, 2022
    Posts:
    67
    najati likes this.
  4. najati

    najati

    Joined:
    Oct 23, 2017
    Posts:
    40
    Thanks all! Glad I ended up on the right path, if perhaps by accident. Thanks for confirming.

    Another question that probably doesn't warrant its own thread that I can't find a succinct answer to: Does DrawProceduralIndirect respect the order of geometry as it's drawing? I'm worried this might be a hardware-dependent answer, but my hope is that it does! I thought I saw something somewhere that said that triangles within a mesh are drawn in the order that they appear in the geometry, but I can't refind that.

    Cheers
     
  5. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    At least in DirectX, the spec guarantees that triangles will be sorted and drawn in the order they are submitted, which should apply both to indexed and non-indexed/procedural. So, yes, at least on PC it'll be in order.
     
    najati likes this.
  6. aras-p

    aras-p

    Unity Legend

    Joined:
    Feb 17, 2022
    Posts:
    67
    All the graphics APIs guarantee this.
     
    najati and Unifikation like this.
  7. najati

    najati

    Joined:
    Oct 23, 2017
    Posts:
    40
    Hi, thanks all, this information has been extremely useful!