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
fxvertex-attrib-components.
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.
In all the following component assignment specifications, if
the vertexAttributeRobustness
feature is enabled,
or
the maintenance9 feature is enabled,
and there is no VkVertexInputAttributeDescription::location
specified for the shader vertex attribute Location being read, the
value (0,0,0,0) or (0,0,0,1) is used for each of the equivalent (x,y,z,w)
components consumed entries as specified below.
| 16-bit or 32-bit data type | Componentdecoration | Components 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 fxvertex-attrib-matrix.
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.
| Data type | Column vector type | Locations consumed | Components 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 fxvertex-attrib-double.
For 64-bit data types, no default attribute values are provided.
Input variables must not use more components than provided by the
attribute.
| Input format | Locations consumed | 64-bit data type | Location decoration | Component decoration | 32-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 fxvertex-attrib-double.
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.
Vertex Attribute Divisor in Instanced Rendering
Vertex Input Address Calculation
The address of each attribute for each vertexIndex and
instanceIndex is calculated as follows:
- Let
attribDescbe the member of VkPipelineVertexInputStateCreateInfo::pVertexAttributeDescriptionswith VkVertexInputAttributeDescription::locationequal to the vertex input attribute number. - Let
bindingDescbe the member of VkPipelineVertexInputStateCreateInfo::pVertexBindingDescriptionswith VkVertexInputAttributeDescription::bindingequal toattribDesc.binding. - Let
vertexIndexbe the index of the vertex within the draw (a value betweenfirstVertexandfirstVertex+vertexCountforvkCmdDraw, or a value taken from the index buffer plusvertexOffsetforvkCmdDrawIndexed), and letinstanceIndexbe the instance number of the draw (a value betweenfirstInstanceandfirstInstance+instanceCount). - Let
offsetbe an array of offsets into the bound vertex buffers specified duringvkCmdBindVertexBuffersorvkCmdBindVertexBuffers2withpOffsets. - Let
divisorbe the member of VkPipelineVertexInputDivisorStateCreateInfo::pVertexBindingDivisorswith VkVertexInputBindingDivisorDescription::bindingequal toattribDesc.binding. If the vertex binding state is dynamically set, instead letdivisorbe the member of thepVertexBindingDescriptionsparameter to the vkCmdSetVertexInputEXT call with VkVertexInputBindingDescription2EXT::bindingequal toattribDesc.binding. - Let
stridebe the member of VkPipelineVertexInputStateCreateInfo::pVertexBindingDescriptions→strideunless there is dynamic state causing the value to be ignored. In this case the value is set from the last value from one of the following- vkCmdSetVertexInputEXT::
pVertexBindingDescriptions→stride - vkCmdBindVertexBuffers2::
pStrides, if notNULL
- vkCmdSetVertexInputEXT::
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 in
the same manner as described for image reads as if a texel
were read from that address.
The numeric type of the attribute’s 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 the sum of attribAddress and the data extracted is outside of the bound
vertex buffer, behavior is as described by
Shader Out-of-Bounds Memory Access.
If
either format is a 64-bit format or the
legacyVertexAttributes feature is
not enabled, and
format is a packed format, attribAddress must be a multiple of the
size in bytes of the size of the format as described in
Packed Formats.
Otherwise,
if either format is a 64-bit format or the
legacyVertexAttributes feature is
not enabled,
attribAddress must be a multiple of the size in bytes of the component
type indicated by format (see Formats).
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.
If the numeric format of format uses sRGB
encoding, and the maintenance10 feature is
enabled, the implementation must convert values from nonlinear to linear as
described in the sRGB EOTF section of the Khronos Data
Format Specification.
If the maintenance10 feature is not
enabled, the implementation should convert values from nonlinear to linear.
Implementations
which do not support maintenance10, and
which do not convert nonlinear to linear for sRGB formats should not expose
VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT for such formats.