I'm confused about the difference between the shader input element classifications in D3D12 and Vulkan. For example, in Vulkan I could have the following declarations:

struct vertex
    glm::vec3 pos;
    glm::vec3 col;

VkVertexInputBindingDescription input_binding_description
    .binding = 0,
    .stride = sizeof(vertex),

std::array<VkVertexInputAttributeDescription, 2> input_attribute_descriptions {
        .location = 0,
        .format = VK_FORMAT_R32G32B32_SFLOAT,
        .offset = offsetof(vertex, pos)
        .location = 1,
        .format = VK_FORMAT_R32G32B32_SFLOAT,
        .offset = offsetof(vertex, col)

Here the input rate is specified per vertex and not per attribute. On the other hand, in D3D12, we would have

struct Vertex
    XMFLOAT3 pos;
    XMFLOAT3 col;

std::array<D3D12_INPUT_ELEMENT_DESC, 2> input_element_descs =
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
    { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12,

And as you can see, the input rate is specified per attribute. Why is that? Is there a difference between the meaning of the input classification in D3d12 and Vulkan that I'm missing? I'm not familiar with D3D12, but at first glance, it doesn't make sense to me to have different input classifications for the attributes of a vertex.

  • \$\begingroup\$ I know input rate "per vertex" and "per primitive", but can't imagine "per attribute". How does that work ? But i only have a very superficial idea of vulkan from a little dabbling and none of d3d12 ... \$\endgroup\$
    – user144188
    Commented Dec 9, 2020 at 11:36

1 Answer 1


That's because in case of the D3D12 API, there is no separation between "binding slots" and their corresponding declarations.

In Vulkan, you first specify the input bindings (eg. binding = 0 -> vertex data, binding = 1 -> instance data) and then specify the corresponding layout (attribute descriptors) per bindings.

binding = 0 -> vertex data, rate = per vertex
    attributes: [ position(location=0), texcoord(location=1), ... ]

binding = 1 -> instance data, rate = per instance
    attributes: [ ... ]

In contrast, with the D3D API you don't have this separation and you must define the whole input state in a single array. So if you have more than one "binding slots", you still have a single array describing all of the elements from all of the slots.

elements: [
    position(binding=0, semantic=POSITION0, rate=vertex)
    texcoord(binding=0, semantic=TEXCOORD0, rate=vertex)
    something(binding=1, semantic=TEXCOORD1, rate=instance)

This D3D12_INPUT_ELEMENT_DESC array is then used in the D3D12_INPUT_LAYOUT_DESC to describe all of the elements for a vertex shader.

See D3D12_INPUT_ELEMENT_DESC and D3D12_INPUT_LAYOUT_DESC and this guide.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .