Search code examples
directx-11hlslprimitive

SV_PrimitiveID and primitives in direct3D 11


I saw SV_PrimitiveID semantic in documentation which says it creates an ID for each primitive which are unique in every draw call.

I have seen this semantic in Geometry shader and I'm confused with the term primitive. I have vertex buffer with vertices of a cube and a sphere, does SV_PrimitiveID index cube vertices 0 and sphere 1 or for every triangle in vertex buffer it gives a number(imagining GS inputs triangle list). I also don't know if the first situation was true how does it distinguish between cube and sphere when they are both in one vertex buffer.


Solution

  • What the SV_PrimitiveID means is determined by the D3D11_PRIMITIVE_TOPOLOGY (set by ID3D11DeviceContext::IASetPrimitiveTopology). Every draw call every primitive is assigned a number in order that the primitives are drawn.

    For example:

    // buffers that will be copied to the gpu
    struct Vertex { float X, Y, Z; } VertexData[6] =
    {
        { 0, 0, 0 },
        { 1, 0, 0 },
        { 1, 1, 0 },
    
        { 1, 1, 0 },
        { 0, 1, 0 },
        { 0, 0, 0 },
    };
    
    struct Triangle { int A, B, C; } IndexData[2] =
    {
        { 0, 1, 2 },// SV_PrimitiveID == 0
        { 2, 4, 0 },// SV_PrimitiveID == 1
    };
    
    struct Instance { float X, Y, Z; } InstanceData[2] =
    {
        { 0, 0, 0 },// SV_InstanceID == 0
        { 0, 0, 1 },// SV_InstanceID == 1
    };
    
    ...
        pDeviceConstext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
        pDeviceConstext->Draw(6, 0);// would result in two triangles numbered (value of SV_PrimitiveID) 0 and 1
        pDeviceConstext->DrawIndexed(2 * 3, 0, 0);// same thing
        pDeviceConstext->DrawInstanced(6, 2, 0, 0);// now 4 triangles, 2 for the 0th instance and 2 for the 1st; SV_PrimitiveID restarts from zero for every instance!
    ...
    
    

    I don't know for sure the interaction between geometry shaders and SV_PrimitiveID, but DirectX is well-documented. Here are some links:

    https://learn.microsoft.com/en-us/windows/win32/direct3d11/geometry-shader-stage https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-geometry-shader

    Personally I find useful to visually display any information that I might find confusing. For example setting something like this as the pixel shader:

    float4 main(uint pid : SV_PrimitiveId) : SV_Target
    {
        static const uint N = 16;
        float3 color = float3(((pid / uint3(1, N, N * N)) % N) / (float)N);
        return float4(color, 1);
    }