Consider a pipeline with a vertex shader, geometry shader and pixel shader. The vertex shader runs per-vertex, and once one primitive's worth of vertices have been processed, the geometry shader runs. The geometry shader runs per-primitive and outputs vertices of a potentially different primitive type.

Now add a hull and domain shader to the mix. Say the input assembler primitive type is a patch with n control points. The vertex shader runs n times per patch, then the hull shader runs another n times per patch, processing a total of m control points. The tessellator feeds the domain shader each tessellated vertex, and the domain shader outputs the processed vertex. From here, we head to the geometry shader.

Recall that the tessellator can produce lines or triangles. This determines the incoming primitive type to our geometry shader. For the sake of this example, assume the tessellator is configured to output a triangular topology. Say we're emitting points from the geometry shader. This means the signature to the geometry shader looks something like this:

void GS(triangle DOMAIN_SHADER_OUTPUT input[3], inout PointStream<GEOMETRY_SHADER_OUTPUT> stream);

Had the tessellator been configured to deal with isolines, then we would be using

`line DOMAIN_SHADER_OUTPUT input[2]`

instead.So, there you have it. The geometry shader integrates seamlessly into the tessellation model. Recall that the domain shader runs per tessellated vertex, and so we have little control over each individual triangle in that stage. A geometry shader can be used to break a patch up into individual primitives, which can be independently transformed, culled, duplicated, etc. Not to mention that geometry shaders can be instanced now... that's for a future post. :)

What happens if we configure the input assembler to use a patch primitive type, but do not bind hull and domain shaders to the pipeline? Remember that the geometry shader operates on primitives, and that the new patch types are primitives... therefore, the geometry shader can operate on patch primitives!

Here are some example geometry shader signatures.

Input primitive type of point:

`void GS(point VERTEX_SHADER_OUTPUT pt[1], ...);`

Input primitive type of line:

`void GS(line VERTEX_SHADER_OUTPUT pt[2], ...);`

Input primitive type of triangle:

`void GS(triangle VERTEX_SHADER_OUTPUT pt[3], ...);`

Input primitive type of a 25-point patch:

`void GS(InputPatch<VERTEX_SHADER_OUTPUT, 25> pt, ...);`

Excited yet? You should be! What this essentially means is that you can make up your own primitive types (with anywhere from 1 point to 32 points) that the geometry shader can operate on. Wish you had a quad primitive type? Use a 4-point patch with a geometry shader and emit two triangles!

Very interesting. I didn't know you could use the patch primitive in the geometry shader.

ReplyDeleteAn important thing to note is that you cannot get adjacency information in the geometry shader if you are using the tessellator.

This is a good point, I forgot to mention this in my post.

ReplyDeleteThis comment has been removed by the author.

ReplyDelete