Fixed-Function Vertex Processing

Vertex fetching is controlled via configurable state, as a logically distinct graphics pipeline stage.

Vertex Attributes

Vertex shaders can define input variables, which receive vertex attribute data transferred from one or more VkBuffer(s) by drawing commands. Vertex shader input variables are bound to buffers via an indirect binding where the vertex shader associates a vertex input attribute number with each variable, vertex input attributes are associated to vertex input bindings on a per-pipeline basis, and vertex input bindings are associated with specific buffers on a per-draw basis via the vkCmdBindVertexBuffers command. Vertex input attribute and vertex input binding descriptions also contain format information controlling how data is extracted from buffer memory and converted to the format expected by the vertex shader.

There are VkPhysicalDeviceLimits::maxVertexInputAttributes number of vertex input attributes and VkPhysicalDeviceLimits::maxVertexInputBindings number of vertex input bindings (each referred to by zero-based indices), where there are at least as many vertex input attributes as there are vertex input bindings. Applications can store multiple vertex input attributes interleaved in a single buffer, and use a single vertex input binding to access those attributes.

In GLSL, vertex shaders associate input variables with a vertex input attribute number using the location layout qualifier. The Component layout qualifier associates components of a vertex shader input variable with components of a vertex input attribute.

GLSL Example

// Assign location M to variableName
layout (location=M, component=2) in vec2 variableName;

// Assign locations [N,N+L) to the array elements of variableNameArray
layout (location=N) in vec4 variableNameArray[L];

In SPIR-V, vertex shaders associate input variables with a vertex input attribute number using the Location decoration. The Component decoration associates components of a vertex shader input variable with components of a vertex input attribute. The Location and Component decorations are specified via the OpDecorate instruction.

SPIR-V Example

               ...
          %1 = OpExtInstImport "GLSL.std.450"
               ...
               OpName %9 "variableName"
               OpName %15 "variableNameArray"
               OpDecorate %18 BuiltIn VertexIndex
               OpDecorate %19 BuiltIn InstanceIndex
               OpDecorate %9 Location M
               OpDecorate %9 Component 2
               OpDecorate %15 Location N
               ...
          %2 = OpTypeVoid
          %3 = OpTypeFunction %2
          %6 = OpTypeFloat 32
          %7 = OpTypeVector %6 2
          %8 = OpTypePointer Input %7
          %9 = OpVariable %8 Input
         %10 = OpTypeVector %6 4
         %11 = OpTypeInt 32 0
         %12 = OpConstant %11 L
         %13 = OpTypeArray %10 %12
         %14 = OpTypePointer Input %13
         %15 = OpVariable %14 Input
               ...

Attribute Location and Component Assignment

The Location decoration specifies which vertex input attribute is used to read and interpret the data that a variable will consume.

When a vertex shader input variable declared using a 16- or 32-bit scalar or vector data type is assigned a Location, its value(s) are taken from the components of the input attribute specified with the corresponding VkVertexInputAttributeDescription::location. The components used depend on the type of variable and the Component decoration specified in the variable declaration, as identified in Table 32. Input Attribute Components Accessed By 16-Bit and 32-Bit Input Variables. Any 16-bit or 32-bit scalar or vector input will consume a single Location. For 16-bit and 32-bit data types, missing components are filled in with default values as described below.

If an implementation supports storageInputOutput16, vertex shader input variables can have a width of 16 bits.

Table 32. Input Attribute Components Accessed By 16-Bit and 32-Bit Input Variables
16-bit or 32-bit data typeComponent decorationComponents consumed

scalar

0 or unspecified

(x, o, o, o)

scalar

1

(o, y, o, o)

scalar

2

(o, o, z, o)

scalar

3

(o, o, o, w)

two-component vector

0 or unspecified

(x, y, o, o)

two-component vector

1

(o, y, z, o)

two-component vector

2

(o, o, z, w)

three-component vector

0 or unspecified

(x, y, z, o)

three-component vector

1

(o, y, z, w)

four-component vector

0 or unspecified

(x, y, z, w)

Components indicated by o are available for use by other input variables which are sourced from the same attribute, and if used, are either filled with the corresponding component from the input format (if present), or the default value.

When a vertex shader input variable declared using a 32-bit floating-point matrix type is assigned a Location i, its values are taken from consecutive input attributes starting with the corresponding VkVertexInputAttributeDescription::location. Such matrices are treated as an array of column vectors with values taken from the input attributes identified in Table 33. Input Attributes Accessed by 32-Bit Input Matrix Variables. The VkVertexInputAttributeDescription::format must be specified with a VkFormat that corresponds to the appropriate type of column vector. The Component decoration must not be used with matrix types.

Table 33. Input Attributes Accessed by 32-Bit Input Matrix Variables
Data typeColumn vector typeLocations consumedComponents consumed

mat2

two-component vector

i, i+1

(x, y, o, o), (x, y, o, o)

mat2x3

three-component vector

i, i+1

(x, y, z, o), (x, y, z, o)

mat2x4

four-component vector

i, i+1

(x, y, z, w), (x, y, z, w)

mat3x2

two-component vector

i, i+1, i+2

(x, y, o, o), (x, y, o, o), (x, y, o, o)

mat3

three-component vector

i, i+1, i+2

(x, y, z, o), (x, y, z, o), (x, y, z, o)

mat3x4

four-component vector

i, i+1, i+2

(x, y, z, w), (x, y, z, w), (x, y, z, w)

mat4x2

two-component vector

i, i+1, i+2, i+3

(x, y, o, o), (x, y, o, o), (x, y, o, o), (x, y, o, o)

mat4x3

three-component vector

i, i+1, i+2, i+3

(x, y, z, o), (x, y, z, o), (x, y, z, o), (x, y, z, o)

mat4

four-component vector

i, i+1, i+2, i+3

(x, y, z, w), (x, y, z, w), (x, y, z, w), (x, y, z, w)

Components indicated by o are available for use by other input variables which are sourced from the same attribute, and if used, are either filled with the corresponding component from the input (if present), or the default value.

When a vertex shader input variable declared using a scalar or vector 64-bit data type is assigned a Location i, its values are taken from consecutive input attributes starting with the corresponding VkVertexInputAttributeDescription::location. The Location slots and Component words used depend on the type of variable and the Component decoration specified in the variable declaration, as identified in Table 34. Input Attribute Locations and Components Accessed by 64-Bit Input Variables. For 64-bit data types, no default attribute values are provided. Input variables must not use more components than provided by the attribute.

Table 34. Input Attribute Locations and Components Accessed by 64-Bit Input Variables
Input formatLocations consumed64-bit data typeLocation decorationComponent decoration32-bit components consumed

R64

i

scalar

i

0 or unspecified

(x, y, -, -)

R64G64

i

scalar

i

0 or unspecified

(x, y, o, o)

scalar

i

2

(o, o, z, w)

two-component vector

i

0 or unspecified

(x, y, z, w)

R64G64B64

i, i+1

scalar

i

0 or unspecified

(x, y, o, o), (o, o, -, -)

scalar

i

2

(o, o, z, w), (o, o, -, -)

scalar

i+1

0 or unspecified

(o, o, o, o), (x, y, -, -)

two-component vector

i

0 or unspecified

(x, y, z, w), (o, o, -, -)

three-component vector

i

unspecified

(x, y, z, w), (x, y, -, -)

R64G64B64A64

i, i+1

scalar

i

0 or unspecified

(x, y, o, o), (o, o, o, o)

scalar

i

2

(o, o, z, w), (o, o, o, o)

scalar

i+1

0 or unspecified

(o, o, o, o), (x, y, o, o)

scalar

i+1

2

(o, o, o, o), (o, o, z, w)

two-component vector

i

0 or unspecified

(x, y, z, w), (o, o, o, o)

two-component vector

i+1

0 or unspecified

(o, o, o, o), (x, y, z, w)

three-component vector

i

unspecified

(x, y, z, w), (x, y, o, o)

four-component vector

i

unspecified

(x, y, z, w), (x, y, z, w)

Components indicated by o are available for use by other input variables which are sourced from the same attribute. Components indicated by - are not available for input variables as there are no default values provided for 64-bit data types, and there is no data provided by the input format.

When a vertex shader input variable declared using a 64-bit floating-point matrix type is assigned a Location i, its values are taken from consecutive input attribute locations. Such matrices are treated as an array of column vectors with values taken from the input attributes as shown in Table 34. Input Attribute Locations and Components Accessed by 64-Bit Input Variables. Each column vector starts at the Location immediately following the last Location of the previous column vector. The number of attributes and components assigned to each matrix is determined by the matrix dimensions and ranges from two to eight locations.

When a vertex shader input variable declared using an array type is assigned a location, its values are taken from consecutive input attributes starting with the corresponding VkVertexInputAttributeDescription::location. The number of attributes and components assigned to each element are determined according to the data type of the array elements and Component decoration (if any) specified in the declaration of the array, as described above. Each element of the array, in order, is assigned to consecutive locations, but all at the same specified component within each location.

Only input variables declared with the data types and component decorations as specified above are supported. Two variables are allowed to share the same Location slot only if their Component words do not overlap. If multiple variables share the same Location slot, they must all have the same SPIR-V floating-point component type or all have the same width scalar type components.

Vertex Input Description

Applications specify vertex input attribute and vertex input binding descriptions as part of graphics pipeline creation by setting the VkGraphicsPipelineCreateInfo::pVertexInputState pointer to a VkPipelineVertexInputStateCreateInfo structure. Alternatively, if the graphics pipeline is created with the VK_DYNAMIC_STATE_VERTEX_INPUT_EXT dynamic state enabled, then the vertex input attribute and vertex input binding descriptions are specified dynamically with vkCmdSetVertexInputEXT, and the VkGraphicsPipelineCreateInfo::pVertexInputState pointer is ignored.

VkPipelineVertexInputStateCreateInfoStructure specifying parameters of a newly created pipeline vertex input state
VkPipelineVertexInputStateCreateFlagsReserved for future use
VkVertexInputBindingDescriptionStructure specifying vertex input binding description
VkVertexInputRateSpecify rate at which vertex attributes are pulled from buffers
VkVertexInputAttributeDescriptionStructure specifying vertex input attribute description
vkCmdSetVertexInputEXTSet the vertex input state dynamically for a command buffer
VkVertexInputBindingDescription2EXTStructure specifying the extended vertex input binding description
VkVertexInputAttributeDescription2EXTStructure specifying the extended vertex input attribute description
vkCmdBindVertexBuffersBind vertex buffers to a command buffer
vkCmdBindVertexBuffers2Bind vertex buffers to a command buffer and dynamically set strides

Vertex Attribute Divisor in Instanced Rendering

VkPipelineVertexInputDivisorStateCreateInfoKHRStructure specifying vertex attributes assignment during instanced rendering
VkVertexInputBindingDivisorDescriptionKHRStructure specifying a divisor used in instanced rendering

Vertex Input Address Calculation

The address of each attribute for each vertexIndex and instanceIndex is calculated as follows:

bufferBindingAddress = buffer[binding].baseAddress + offset[binding];

if (bindingDesc.inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
    effectiveVertexOffset = vertexIndex * stride;
else
    if (divisor == 0)
        effectiveVertexOffset = firstInstance * stride;
    else
        effectiveVertexOffset = (firstInstance + ((instanceIndex - firstInstance) / divisor)) * stride;

attribAddress = bufferBindingAddress + effectiveVertexOffset + attribDesc.offset;

Vertex Input Extraction

For each attribute, raw data is extracted starting at attribAddress and is converted from the VkVertexInputAttributeDescription’s format to either floating-point, unsigned integer, or signed integer based on the numeric type of format. The numeric type of format must match the numeric type of the input variable in the shader. The input variable in the shader must be declared as a 64-bit data type if and only if format is a 64-bit data type. If either format is a 64-bit format or legacyVertexAttributes is not enabled, and format is a packed format, attribAddress must be a multiple of the size in bytes of the whole attribute data type as described in Packed Formats. Otherwise, if either format is a 64-bit format or legacyVertexAttributes is not enabled, attribAddress must be a multiple of the size in bytes of the component type indicated by format (see Formats). For attributes that are not 64-bit data types, each component is converted to the format of the input variable based on its type and size (as defined in the Format Definition section for each VkFormat), using the appropriate equations in 16-Bit Floating-Point Numbers, Unsigned 11-Bit Floating-Point Numbers, Unsigned 10-Bit Floating-Point Numbers, Fixed-Point Data Conversion, and Shared Exponent to RGB. Signed integer components smaller than 32 bits are sign-extended. Attributes that are not 64-bit data types are expanded to four components in the same way as described in conversion to RGBA. The number of components in the vertex shader input variable need not exactly match the number of components in the format. If the vertex shader has fewer components, the extra components are discarded.