How to get patch id in domain shader.

Started by
7 comments, last by Jason Z 7 years, 9 months ago

Greetings,

In my domain shader I want to sample a structured buffer with current patch id. I specified SV_PrimitiveID as input parameter but the value is 0 for all patches. And to be honest I don't see how the pipeline can provide a patch id if I draw each patch with separate draw call (DrawIndexedInstanced()). But the documentation says I can use it for patch id.

Advertisement

SV_PrimitiveID always starts at 0 for every draw call, and then increases for every primitive processed as part of that draw call. So if you only every draw 1 primitive per draw, then it's always going to be 0. If you need some sort of global ID, then you'll need to provide an offset in a constant buffer.

Also, drawing each path in its own DrawCall sounds incredibly inefficient. You need to provide at least 256 vertices per draw call to fully utilize the vertex shader.

Also, drawing each path in its own DrawCall sounds incredibly inefficient. You need to provide at least 256 vertices per draw call to fully utilize the vertex shader.

I thought it was 64 vertices to fully utilize the vertex shader and 256 to not become command processor limited.

edit - for amd.

-potential energy is easily made kinetic-

Thank you @MJP. That make sense. And actually documentation says that though I had to read it several times to understand.

@Matias is it still true if I have a pass-through vertex shader?

And maybe you can help me with my scenario. I have a big buffer with all control points. A have several index buffers for patches. Some patches should be drawn multiple times with different transformation. So if I want to draw everything in one call I have to duplicate indices. Right now I'm drawing each patch in it's own draw call and for patches that need to be drawn multiple times I'm using instancing. Here's a problem - for each new instance SV_PrimitiveID resets to 0. SV_InstanceID is not available in hull/domain shader and I have to pass it from vertex shader unnecessary duplicating data. Looks like instancing not works very well with tessellation.

Also, drawing each path in its own DrawCall sounds incredibly inefficient. You need to provide at least 256 vertices per draw call to fully utilize the vertex shader.

I thought it was 64 vertices to fully utilize the vertex shader and 256 to not become command processor limited.

edit - for amd.

AMD's wavefront size is of 64, that's true, but there are some inefficiencies and overhead details, such as needing 3 vertices to make a triangle (e.g. 64 triangles x 3 = 192 vertices assuming no tri shares any vertex). Real world testing shows on average you get near optimum throughput at >= 256 vertices per draw.
Edit. See http://www.g-truc.net/post-0666.html

@Matias is it still true if I have a pass-through vertex shader?

Yep.

Thank you @MJP. That make sense. And actually documentation says that though I had to read it several times to understand.

@Matias is it still true if I have a pass-through vertex shader?

And maybe you can help me with my scenario. I have a big buffer with all control points. A have several index buffers for patches. Some patches should be drawn multiple times with different transformation. So if I want to draw everything in one call I have to duplicate indices. Right now I'm drawing each patch in it's own draw call and for patches that need to be drawn multiple times I'm using instancing. Here's a problem - for each new instance SV_PrimitiveID resets to 0. SV_InstanceID is not available in hull/domain shader and I have to pass it from vertex shader unnecessary duplicating data. Looks like instancing not works very well with tessellation.

Have you considered putting your control point data into a resource that can be read by a shader (i.e. constant buffer or a structured buffer)? That would allow you to have a very small vertex format (like a single integer offset) and you can just update your vertex buffer to indicate which set of control points you want each instance to use, and then utilize one of the basic draw calls instead of real instancing. That should keep your primitive ID sequential, while still offering the reuse of most of your data without bloating.

Also, maybe I missed it, but what are you using the primitive ID for? Is a unique value within the domain/hull shader needed?

Hi Jason, it's a good solution, thank you. But if I understood you correctly, your approach is basically the same as drawing with indices. If I would have a set of points as one constant/structured buffer, I have to pass the id of a point as a vertex data, right? So, drawing the same patch multiple times will require to duplicate vertices.

And I need a unique sequential patch id for coloring entire patch. So in domain shader a could sample structured buffer of colors.

That's right, but each vertex would only contain a single index into your structured buffer. So even if you had to repeat a vertex, it would be relatively low cost. If you have a way to generate the desired indices when given a sequential value, you could always use an empty vertex type and just generate the vertices on the fly in the vertex shader. That would be super low cost, and you can easily expand the vertex data as needed throughout the pipeline (i.e. in the VS, DS, and HS).

This topic is closed to new replies.

Advertisement