Shader Interfaces
When a pipeline is created, the set of shaders specified in the
corresponding VkPipelineCreateInfo structure are implicitly linked at
a number of different interfaces.
- Shader Input and Output Interface
- Vertex Input Interface
- Fragment Output Interface
- Fragment Tile Image Interface
- Fragment Input Attachment Interface
- Ray Tracing Pipeline Interface
- Shader Resource Interface
- Geometry Shader Passthrough
This chapter describes valid uses for a set of SPIR-V decorations.
Any other use of one of these decorations is invalid, with the exception
that, when using SPIR-V versions 1.4 and earlier: Block,
BufferBlock, Offset, ArrayStride, and MatrixStride can
also decorate types and type members used by variables in the Private
and Function storage classes.
MeshNV execution model.
These terms will appear even in a build of the specification which does not
support any extensions.
This is as intended, since these terms appear in the unified SPIR-V
specification without such qualifiers.Shader Input and Output Interfaces
When multiple stages are present in a pipeline, the outputs of one stage form an interface with the inputs of the next stage. When such an interface involves a shader, shader outputs are matched against the inputs of the next stage, and shader inputs are matched against the outputs of the previous stage.
All the variables forming the shader input and output interfaces are
listed as operands to the OpEntryPoint instruction and are declared
with the Input or Output storage classes, respectively, in the
SPIR-V module.
These generally form the interfaces between consecutive shader stages,
regardless of any non-shader stages between the consecutive shader stages.
There are two classes of variables that can be matched between shader stages, built-in variables and user-defined variables. Each class has a different set of matching criteria.
For compute shaders, the input interface is formed by the built-in interface. The output interface is empty.
Built-In Interface Block
Shader built-in variables meeting the following requirements define the built-in interface block. They must
- be explicitly declared (there are no implicit built-ins),
- be identified with a
BuiltIndecoration, - form object types as described in the Built-in Variables section, and
- be declared in a block whose top-level members are the built-ins.
There must be no more than one built-in interface block per shader per
interface
, except for the mesh output interface where there must be at most one
built-in interface block decorated with the PerPrimitiveEXT decoration
and at most one built-in interface block without this decoration
.
Built-ins must not have any Location or Component decorations.
User-Defined Variable Interface
The non-built-in variables listed by OpEntryPoint with the Input
or Output storage class form the user-defined variable interface.
These must have numeric type or, recursively,
composite types of such types.
If an implementation supports storageInputOutput16, components can have a width of 16 bits.
These variables must be identified with a Location decoration and can
also be identified with a Component decoration.
Interface Matching
An output variable, block, or structure member in a given shader stage has an interface match with an input variable, block, or structure member in a subsequent shader stage if they both adhere to the following conditions:
- They have equivalent decorations, other than:
XfbBuffer,XfbStride,Offset, andStream- one is not decorated with
Componentand the other is declared with aComponentof0 - Interpolation decorations
RelaxedPrecisionif one is an input variable and the other an output variable
- Their types match as follows:
- if the input is declared in a tessellation control or geometry shader
as an
OpTypeArraywith anElementTypeequivalent to theOpType*declaration of the output, and neither is a structure member; or - if the
maintenance4feature is enabled, they are declared asOpTypeVectorvariables, and the output has aComponentCountvalue higher than that of the input but the sameComponentType; or - if the output is declared in a mesh shader as an
OpTypeArraywith anElementTypeequivalent to theOpType*declaration of the input, and neither is a structure member; or - if the input is decorated with
PerVertexKHR, and is declared in a fragment shader as anOpTypeArraywith anElementTypeequivalent to theOpType*declaration of the output, and neither the input nor the output is a structure member; or - if in any other case they are declared with an equivalent
OpType*declaration.
- if the input is declared in a tessellation control or geometry shader
as an
- If both are structures and every member has an interface match.
structure above refers to both variables that have an
OpTypeStruct type and interface blocks (which are also declared as
OpTypeStruct).If the pipeline is compiled as separate graphics pipeline libraries and the
graphicsPipelineLibraryIndependentInterpolationDecoration limit is
not supported, matches are not found if the
interpolation decorations differ
between the last pre-rasterization shader stage and the fragment shader stage.
All input variables and blocks must have an interface match in the preceding shader stage, except for built-in variables in fragment shaders. Shaders can declare and write to output variables that are not declared or read by the subsequent stage.
Matching rules for passthrough geometry shaders are slightly different and are described in the Passthrough Interface Matching section.
The value of an input variable is undefined if the preceding stage does not write to a matching output variable, as described above.
Location and Component Assignment
User-defined variables in interfaces
between shader stages in the graphics pipeline consume a unique set of
Location and Component values.
Available space for user-defined interface variables is partitioned into a
number of 32-bit four-component vectors, each identified by a Location
value.
Each individual 32-bit component of a vector is then further identified by a
Component value.
16-bit scalar or vector values consume one Component slot per 16-bit
component and must be specified within a single Location.
32-bit scalar or vector values consume one Component slot per 32-bit
component and must be specified within a single Location.
64-bit scalar or vector values consume two consecutive Component slots
per 64-bit component from up to two consecutive Location slots.
For any shader interface variable where one level of the array is disregarded for type matching, the outer array
level is also disregarded when assigning Location slots.
An array of size n with elements consuming l Location slots
each will consume l × n Location slots.
Each element of the array will consume Component slots in each
Location slot identically to a declaration using the element type.
Matrices of size n × m are assigned locations identically to
arrays of size n of vectors of length 4 (consuming all Component
slots) with an identical element type.
When a variable with a structure type is decorated with a Location, the
members in the structure type must not be decorated with a Location.
The variable’s members are assigned consecutive locations in declaration
order, starting from the first member, which is assigned the location
decoration from the variable.
The Location slots consumed by structure members are determined by
applying the rules above in a depth-first traversal of the instantiated
members as though the structure or block member were declared as an input or
output variable of the same type.
A variable with a structure type that is not decorated with Block must
be decorated with a Location.
When a variable with a structure type decorated with Block is declared
without a Location decoration, each member in the structure must be
decorated with a Location.
Types nested deeper than the top-level members must not have Location
decorations.
Multiple variable declarations in the same storage class must not have
overlapping Component slots within the same Location.
The number of input and output locations available for a shader input or
output interface depend on the shader stage as described in
interfaces-iointerfaces-limits.
All variables in both the built-in interface
block and the user-defined variable
interface count against these limits.
Each effective Location must have a value less than the number of
Location slots available for the given interface, as specified in the
Locations Available column in interfaces-iointerfaces-limits.
| Shader Interface | Locations Available |
|---|---|
| vertex input | maxVertexInputAttributes |
| vertex output | maxVertexOutputComponents/ 4 |
| tessellation control input | maxTessellationControlPerVertexInputComponents/ 4 |
| tessellation control output | maxTessellationControlPerVertexOutputComponents/ 4 |
| tessellation evaluation input | maxTessellationEvaluationInputComponents/ 4 |
| tessellation evaluation output | maxTessellationEvaluationOutputComponents/ 4 |
| geometry input | maxGeometryInputComponents/ 4 |
| geometry output | maxGeometryOutputComponents/ 4 |
| fragment input | maxFragmentInputComponents/ 4 |
| fragment output | maxFragmentOutputAttachments |
| mesh output | maxMeshOutputComponents/ 4 |
| cluster culling output | maxOutputClusterCount |
Vertex Input Interface
When the vertex stage is present in a pipeline, the vertex shader input
variables form an interface with the vertex input attributes.
The vertex shader input variables are matched by the Location and
Component decorations to the vertex input attributes specified in the
pVertexInputState member of the VkGraphicsPipelineCreateInfo
structure.
The vertex shader input variables listed by OpEntryPoint with the
Input storage class form the vertex input interface.
These variables must be identified with a Location decoration and can
also be identified with a Component decoration.
For the purposes of interface matching: variables declared without a
Component decoration are considered to have a Component decoration
of zero.
The number of available vertex input Location slots is given by the
maxVertexInputAttributes member of the VkPhysicalDeviceLimits
structure.
See Attribute Location and Component Assignment for details.
All vertex shader inputs declared as above must have a corresponding attribute and binding in the pipeline.
Components and locations are consumed as defined for
Location and Component Assignment.
Multiple user-defined input variable
declarations must not have overlapping Component slots within the same
Location.
Fragment Output Interface
When the fragment stage is present in a pipeline, the fragment shader
outputs form an interface with the output attachments defined by a
render pass instance.
The fragment shader output variables are matched by the Location and
Component decorations to specified color attachments.
The fragment shader output variables listed by OpEntryPoint with the
Output storage class form the fragment output interface.
These variables must be identified with a Location decoration.
They can also be identified with a Component decoration and/or an
Index decoration.
For the purposes of interface matching: variables declared without a
Component decoration are considered to have a Component decoration
of zero, and variables declared without an Index decoration are
considered to have an Index decoration of zero.
A fragment shader output variable identified with a Location decoration
of i is associated with
the color attachment indicated by
VkRenderingInfo::pColorAttachments[i].
When using render pass objects, it is associated with
the color attachment indicated by
VkSubpassDescription::pColorAttachments[i].
Values are written to those attachments after passing through the blending
unit as described in Blending, if enabled.
The number of available fragment output Location slots is given by the
maxFragmentOutputAttachments member of the
VkPhysicalDeviceLimits structure.
If the
dynamicRenderingLocalRead
feature is supported, fragment output locations can be remapped when using
dynamic rendering.
When an active fragment shader invocation finishes, the values of all
fragment shader outputs are copied out and used as blend inputs or color
attachments writes.
If there is no color attachment indicated by Location, the values that
would have been written to the color attachments are discarded.
Output Component words identified as 0, 1, 2, and 3 will be directed to
the R, G, B, and A inputs to the blending unit, respectively, or to the
output attachment if blending is disabled.
If two variables are placed within the same Location, they must have
the same numeric type.
Component words which do not correspond to any fragment shader output
will also result in undefined values for blending or color attachment
writes.
Fragment outputs identified with an Index of zero are directed to the
first input of the blending unit associated with the corresponding
Location.
Outputs identified with an Index of one are directed to the second
input of the corresponding blending unit.
Components and locations are consumed as defined for
Location and Component Assignment.
Output variable declarations must not consume any of the same
Component slots within the same Location and with the same
Index value as any other output variable declaration.
Output values written by a fragment shader must be declared with either
OpTypeFloat or OpTypeInt, and a Width of 32.
If storageInputOutput16 is supported, output values written by a
fragment shader can be also declared with either OpTypeFloat or
OpTypeInt and a Width of 16.
Composites of these types are also permitted.
If the color attachment has a signed or unsigned normalized fixed-point
format, color values are assumed to be floating-point and are converted to
fixed-point as described in Conversion From Floating-Point to Normalized Fixed-Point; If the color
attachment has an integer format, color values are assumed to be integers
and converted to the bit-depth of the target.
Any value that cannot be represented in the attachment’s format is
undefined.
For any other attachment format no conversion is performed.
If the type of the values written by the fragment shader do not match the
format of the corresponding color attachment, the resulting values are
undefined for those components.
Legacy Dithering
The application can enable dithering to be applied to the color output of a
subpass, by using the
VK_SUBPASS_DESCRIPTION_ENABLE_LEGACY_DITHERING_BIT_EXT flag.
For use in a dynamic render pass, the
VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT flag must be used.
In that case, the pipelines used must have been created with
VK_PIPELINE_CREATE_2_ENABLE_LEGACY_DITHERING_BIT_EXT.
When dithering is enabled, the implementation may modify the output color value c by one ULP. This modification must only depend on the framebuffer coordinates (xf,yf) of the sample, as well as on the value of c.
The exact details of the dithering algorithm are unspecified, including the algorithm itself, the formats dithering is applied to, and the stage in which it is applied.
Fragment Tile Image Interface
When a fragment stage is present in a pipeline, the fragment shader tile
image variables decorated with Location form an interface with the
color attachments defined by the render pass instance.
The fragment shader tile image variables are matched by Location
decorations to the color attachments specified in the
pColorAttachments array of the VkRenderingInfoKHR structure
describing the render pass instance the fragment shader is executed in.
The fragment shader variables listed by OpEntryPoint with the
TileImageEXT storage class and a decoration of Location form the
fragment tile image interface.
These variables must be declared with a type of OpTypeImage, and a
Dim operand of TileImageDataEXT.
The Component decoration is not supported for these variables.
Reading from a tile image variable with a Location decoration of i
reads from the color attachment identified by the element of
VkRenderingInfoKHR::pColorAttachments with a location
equal to i.
If the tile image variable is declared as an array of size N, it consumes N
consecutive tile image locations, starting with the index specified.
There must not be more than one tile image variable with the same
Location whether explicitly declared or implied by an array
declaration.
The number of available tile image locations is the same as the number of
available fragment output locations as given by the
maxFragmentOutputAttachments member of the
VkPhysicalDeviceLimits structure.
The basic data type (floating-point, integer, unsigned integer) of the tile image variable must match the basic format of the corresponding color attachment, or the values read from the tile image variables are poison.
Tile Attachment Interface
The image variables declared with TileAttachmentQCOM storage class form
the tile attachment interface.
These tile attachment variables correspond to a per-tile view of the color, depth, or input attachment of the current subpass or render pass instance.
Such variables must only be declared and accessed in compute and fragment shaders invoked within a render pass instance that enables tile shading. Access of such variables in a fragment shader, additionally requires that the tileShadingFragmentStage feature must be enabled.
Tile attachment variables must not include a Component decoration.
Tile attachment variables must not be consumed by OpImageQuery*
instructions.
Tile attachment variables can be declared as either single-sampled with
MS operand of 0, or as multi-sampled with MS operand of 1.
The image subresources of the tile attachment image must not be in
VK_IMAGE_LAYOUT_UNDEFINED
or VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT
layout in order to access its data in a shader.
Tile attachment variables statically accessed by a fragment or compute
shader must be backed by a descriptor that is equivalent to the
VkImageView in the VkFramebuffer
or the VkRenderingAttachmentInfo
except for subresourceRange.aspectMask.
The aspectMask must be equal to the aspect accessed by the shader.
Tile attachment variables are further subdivided into storage tile attachment, sampled tile attachment, and input tile attachment variables.
- Sampled tile attachment variables must be declared with a
Sampledoperand of1, must be backed by a descriptor of typeVK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM,VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM, orVK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, and can be used withOpImageFetch,OpImageSparseFetch, or used to construct anOpTypeSampledImagethat is subsequently consumed byOpImageSample*,OpImageSparseSample*,OpImageSampleWeightedQCOM,OpImageBoxFilterQCOM,OpImageBlockMatch*QCOM,OpImage*Gather, orOpImageSparse*Gather. Sampled tile attachment variables are managed by the Descriptor Set Interface as sampled images. - Storage tile attachment variables must be declared with a
Sampledoperand of2, must be backed by a descriptor of typeVK_DESCRIPTOR_TYPE_STORAGE_IMAGE, and can be used withOpImageRead,OpImageSparseRead, andOpImageWriteinstructions. Storage tile attachment variables can be consumed byOpImageTexelPointerfor compatibility with atomic operations. Sampled tile attachment variables are managed by the Descriptor Set Interface as storage images. - Input tile attachment variables must be declared with a
Sampledoperand of2, must be backed by a descriptor of typeVK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, and can be used withOpImageReadinstructions. Input tile attachment variables are managed by the Descriptor Set Interface as input attachment images.
Tile attachment access using OpImageWrite instructions must be used
only in the compute stage.
Tile attachment access using OpImageWrite instructions must not be
used on a variable whose underlying descriptor references the same
VkImageView bound as a depth or stencil attachment.
The basic data type (floating-point, integer, unsigned integer) of the tile attachment variable must match the basic format of the corresponding input, depth, or color attachment, otherwise the result of loads/stores for tile attachment variables is poison. If the render pass attachment contains both depth and stencil aspects, the basic data type of the tile attachment variable determines if depth or stencil aspect is accessed by the shader.
Fragment Input Attachment Interface
When a fragment stage is present in a pipeline, the fragment shader subpass
inputs form an interface with the input attachments of the current subpass.
The fragment shader subpass input variables are matched by
InputAttachmentIndex decorations to the input attachments specified in
the pInputAttachments array of the VkSubpassDescription
structure describing the subpass that the fragment shader is executed in.
The fragment shader subpass input variables with the UniformConstant
storage class and a decoration of InputAttachmentIndex that are
statically used by OpEntryPoint form the fragment input attachment
interface.
These variables must be declared with a type of OpTypeImage, a
Dim operand of SubpassData, an Arrayed operand of 0, and a
Sampled operand of 2.
The MS operand of the OpTypeImage must be 0 if the samples
field of the corresponding VkAttachmentDescription is
VK_SAMPLE_COUNT_1_BIT and
multisampled-render-to-single-sampled
is not enabled, and
1 otherwise.
A subpass input variable identified with an InputAttachmentIndex
decoration of i reads from the input attachment indicated by
pInputAttachments[i] member of VkSubpassDescription.
If the subpass input variable is declared as an array of size N,
or a runtime-sized array,
it consumes consecutive input attachments, starting with the index
specified.
For runtime-sized arrays, the number of input attachment indices consumed is
equal to VkDescriptorSetLayoutBinding::descriptorCount.
There must not be more than one input variable with the same
InputAttachmentIndex whether explicitly declared or implied by an array
declaration per image aspect.
A multi-aspect image (e.g. a depth/stencil format) can use the same input
variable.
The number of available input attachment indices is given by the
maxPerStageDescriptorInputAttachments member of the
VkPhysicalDeviceLimits structure.
When using dynamic rendering with the dynamicRenderingLocalRead feature enabled, a subpass input variable
with a InputAttachmentIndex decoration of i can be mapped to a color,
depth, or stencil attachment.
Variables identified with the InputAttachmentIndex must only be used
by a fragment stage.
The numeric format of the subpass input must
match the format of the corresponding input attachment, or the values of
subpass loads from these variables are poison.
If the framebuffer attachment contains both depth and stencil aspects, the
numeric format of the subpass input determines if depth or stencil aspect is
accessed by the shader.
See Input Attachment for more details.
Fragment Input Attachment Compatibility
An input attachment that is statically accessed by a fragment shader must
be backed by a descriptor that is equivalent to the VkImageView in the
VkFramebuffer, except for subresourceRange.aspectMask.
The aspectMask must be equal to the aspect accessed by the shader.
Ray Tracing Pipeline Interface
Ray tracing pipelines may have more stages than other pipelines with multiple instances of each stage and more dynamic interactions between the stages, but still have interface structures that obey the same general rules as interfaces between shader stages in other pipelines. The three types of inter-stage interface variables for ray tracing pipelines are:
- Ray payloads containing data preserved for the entire lifetime of the ray.
- Hit attributes containing data about a specific hit for the duration of its processing.
- Callable data for passing data into and out of a callable shader.
Ray payloads and callable data are used in explicit shader call instructions, so they have an incoming variant to distinguish the parameter passed to the invocation from any other payloads or data being used by subsequent shader call instructions.
An interface structure between stages must match between the stages using it. Specifically:
- If an intersection shader is present, the hit attribute structure read in an any-hit or closest hit shader must be the same structure as the hit attribute structure written in the corresponding intersection shader in the same hit group.
- If an intersection shader is not present, the hit attribute structure read in an any-hit or closest hit shader must be a vector of 2 32-bit floating-point values that accepts the barycentric coordinates for triangle hits.
- The incoming callable data for a callable shader must be the same structure as the callable data referenced by the execute callable instruction in the calling shader.
- The ray payload for a shader invoked by a ray tracing command must be the same structure for all shader stages using the payload for that ray, and must be declared in the shader even if it is not referenced.
Any shader with an incoming ray payload, incoming callable data, or hit attribute must only declare one variable of that type.
| Shader Stage | Ray Payload | Incoming Ray Payload | Hit Attribute | Callable Data | Incoming Callable Data |
|---|---|---|---|---|---|
| Ray Generation | r/w | r/w | |||
| Intersection | r/w | ||||
| Any-Hit | r/w | r | |||
| Closest Hit | r/w | r/w | r | r/w | |
| Miss | r/w | r/w | r/w | ||
| Callable | r/w | r/w |
Shader Resource Interface
When a shader stage accesses buffer,
tensor,
or image resources through a descriptor, as described in the
Resource Descriptors section, the shader resource variables
must be matched with the pipeline layout
that is provided at
shader or
pipeline creation time.
If a pipeline is created with
VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT,
or a shader is created with VK_SHADER_CREATE_DESCRIPTOR_HEAP_BIT_EXT,
then no layout information needs to be provided.
The set of shader variables that form the shader resource interface for a
stage are the variables statically used by that stage’s OpEntryPoint
with a storage class of Uniform, UniformConstant,
StorageBuffer,
or PushConstant.
For the fragment shader, this includes the fragment input attachment interface.
The shader resource interface consists of multiple sub-interfaces: the descriptor heap interface, the push constant interface, and the descriptor set interface.
Push Constant Interface
The shader variables defined with a storage class of PushConstant that
are statically used by the shader entry points for the pipeline define the
push constant interface.
They must be:
- typed as
OpTypeStruct, - identified with a
Blockdecoration, and - laid out explicitly using the
Offset,ArrayStride, andMatrixStridedecorations as specified in Offset and Stride Assignment.
There must be no more than one push constant block statically used per shader entry point.
When using
descriptor buffers or
descriptor sets, each statically used member of a push constant block must
be placed at an Offset such that the entire member is entirely
contained within the VkPushConstantRange for each OpEntryPoint
that uses it, and the stageFlags for that range must specify the
appropriate VkShaderStageFlagBits for that stage.
The Offset decoration for any member of a push constant block must not
cause the space required for that member to extend outside the range
[0, maxPushConstantsSize).
When using descriptor heaps, each statically used member of a push constant
block must be placed at an Offset such that the entire member is
entirely contained within the range specified by vkCmdPushDataEXT in
the command buffer.
The Offset decoration for any member of a push constant block must not
cause the space required for that member to extend outside the range
[0, maxPushDataSize).
Push constant variables or blocks can be decorated with
BankNV and
MemberOffsetNV
decorations to control their placement within push constant banks.
The BankNV decoration specifies which hardware bank the push constant
data should be placed in or accessed from, while MemberOffsetNV
provides additional offset control within the specified bank.
When these decorations are used, the push constant data placement is
determined by both the API-specified ranges and the shader-specified bank
and offset decorations, allowing for more flexible push constant management
on implementations where multiple banks are available.
Any member of a push constant block that is declared as an array must only be accessed with dynamically uniform indices.
Descriptor Set Interface
The descriptor set interface is comprised of the shader variables with the
storage class of
StorageBuffer,
TileAttachmentQCOM,
Uniform or UniformConstant (including the variables in the
fragment input attachment interface) that are
statically used by the shader entry points for the pipeline.
When using descriptor heaps, this interface is not used directly to access heaps, but may be accessed by specifying Shader Bindings to map to the descriptor heaps.
These variables must have DescriptorSet and Binding decorations
specified, which are assigned and matched with the
VkDescriptorSetLayout objects in the pipeline layout as described in
DescriptorSet and Binding Assignment.
The Image Format of an OpTypeImage declaration must not be
Unknown, for variables which are used for OpImageRead,
OpImageSparseRead, or OpImageWrite operations, except under the
following conditions:
- For
OpImageWrite, if the image format is listed in the storage without format list and if theshaderStorageImageWriteWithoutFormatfeature is enabled and the shader module declares theStorageImageWriteWithoutFormatcapability. - For
OpImageWrite, if the image format supportsVK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BITand the shader module declares theStorageImageWriteWithoutFormatcapability. - For
OpImageReadorOpImageSparseRead, if the image format is listed in the storage without format list and if theshaderStorageImageReadWithoutFormatfeature is enabled and the shader module declares theStorageImageReadWithoutFormatcapability. - For
OpImageReadorOpImageSparseRead, if the image format supportsVK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BITand the shader module declares theStorageImageReadWithoutFormatcapability. - For
OpImageRead, ifDimisSubpassData(indicating a read from an input attachment).
The Image Format of an OpTypeImage declaration must not be
Unknown, for variables which are used for OpAtomic* operations.
Variables identified with the Uniform storage class are used to access
transparent buffer backed resources.
Such variables must be:
- typed as
OpTypeStruct, or an array of this type, - identified with a
BlockorBufferBlockdecoration, and - laid out explicitly using the
Offset,ArrayStride, andMatrixStridedecorations as specified in Offset and Stride Assignment.
Variables identified with the StorageBuffer storage class are used to
access transparent buffer backed resources.
Such variables must be:
- typed as
OpTypeStruct, or an array of this type, - identified with a
Blockdecoration, and - laid out explicitly using the
Offset,ArrayStride, andMatrixStridedecorations as specified in Offset and Stride Assignment.
The Offset decoration for any member of a Block-decorated variable
in the Uniform storage class must not cause the space required for
that variable to extend outside the range [0,
maxUniformBufferRange).
The Offset decoration for any member of a Block-decorated variable
in the StorageBuffer storage class must not cause the space required
for that variable to extend outside the range [0,
maxStorageBufferRange).
Variables identified with the Uniform storage class can also be used
to access transparent descriptor set backed resources when the variable is
assigned to a descriptor set layout binding with a descriptorType of
VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK.
In this case the variable must be typed as OpTypeStruct and cannot be
aggregated into arrays of that type.
Further, the Offset decoration for any member of such a variable must
not cause the space required for that variable to extend outside the range
[0,maxInlineUniformBlockSize).
Storage tile attachment and sampled tile attachment variables declared as described in the tile attachment interface are also managed by this interface. The requirements in this section for storage image variables also applies to storage tile attachment variables. The requirements in this section for sampled image variables also applies to sampled tile attachment variables. The requirements in this section for input attachment variables also applies to input tile attachment variables.
Variables identified with a storage class of UniformConstant and a
decoration of InputAttachmentIndex must be declared as described in
Fragment Input Attachment Interface.
SPIR-V variables decorated with a descriptor set and binding that identify a
combined image sampler descriptor can
have a type of OpTypeImage, OpTypeSampler (Sampled=1), or
OpTypeSampledImage.
OpTypeSampledImage can be mapped to a
separate image and sampler for compatibility.When accessing a resource through such a variable, the resource must be selected via compile time constant expressions unless features are enabled to allow dynamically uniform or non-uniform expressions, as described below:
- Storage images (except storage texel buffers and input attachments):
- Dynamically uniform:
shaderStorageImageArrayDynamicIndexingandStorageImageArrayDynamicIndexing - Non-uniform:
shaderStorageImageArrayNonUniformIndexingandStorageImageArrayNonUniformIndexing
- Dynamically uniform:
- Storage texel buffers:
- Dynamically uniform:
shaderStorageTexelBufferArrayDynamicIndexingandStorageTexelBufferArrayDynamicIndexing - Non-uniform:
shaderStorageTexelBufferArrayNonUniformIndexingandStorageTexelBufferArrayNonUniformIndexing
- Dynamically uniform:
- Input attachments:
- Dynamically uniform:
shaderInputAttachmentArrayDynamicIndexingandInputAttachmentArrayDynamicIndexing - Non-uniform:
shaderInputAttachmentArrayNonUniformIndexingandInputAttachmentArrayNonUniformIndexing
- Dynamically uniform:
- Sampled images (except uniform texel buffers), samplers and combined
image samplers:
- Dynamically uniform:
shaderSampledImageArrayDynamicIndexingandSampledImageArrayDynamicIndexing - Non-uniform:
shaderSampledImageArrayNonUniformIndexingandSampledImageArrayNonUniformIndexing
- Dynamically uniform:
- Uniform texel buffers:
- Dynamically uniform:
shaderUniformTexelBufferArrayDynamicIndexingandUniformTexelBufferArrayDynamicIndexing - Non-uniform:
shaderUniformTexelBufferArrayNonUniformIndexingandUniformTexelBufferArrayNonUniformIndexing
- Dynamically uniform:
- Uniform buffers:
- Dynamically uniform:
shaderUniformBufferArrayDynamicIndexingandUniformBufferArrayDynamicIndexing - Non-uniform:
shaderUniformBufferArrayNonUniformIndexingandUniformBufferArrayNonUniformIndexing
- Dynamically uniform:
- Storage buffers:
- Dynamically uniform:
shaderStorageBufferArrayDynamicIndexingandStorageBufferArrayDynamicIndexing - Non-uniform:
shaderStorageBufferArrayNonUniformIndexingandStorageBufferArrayNonUniformIndexing
- Dynamically uniform:
- Acceleration structures:
- Dynamically uniform: Always supported.
- Non-uniform: Always supported.
- weight image:
- Dynamically uniform: Always supported.
- Non-uniform: Never supported.
- Block matching image:
- Dynamically uniform: Always supported.
- Non-uniform: Never supported.
- Storage tensors:
- Dynamically uniform:
shaderStorageTensorArrayDynamicIndexingandStorageTensorArrayDynamicIndexingARM - Non-uniform:
shaderStorageTensorArrayNonUniformIndexingandStorageTensorArrayNonUniformIndexingARM
- Dynamically uniform:
A combined image sampler in an array that enables sampler Y′CBCR conversion or samples a subsampled imagemust only be indexed by constant integral expressions.
| Resource type | Descriptor Type |
|---|---|
| sampler | VK_DESCRIPTOR_TYPE_SAMPLERorVK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER |
| sampled image | VK_DESCRIPTOR_TYPE_SAMPLED_IMAGEorVK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER |
| storage image | VK_DESCRIPTOR_TYPE_STORAGE_IMAGE |
| combined image sampler | VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLERor bothVK_DESCRIPTOR_TYPE_SAMPLED_IMAGEandVK_DESCRIPTOR_TYPE_SAMPLERwhen using heaps |
| uniform texel buffer | VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER |
| storage texel buffer | VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER |
| uniform buffer | VK_DESCRIPTOR_TYPE_UNIFORM_BUFFERorVK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC |
| storage buffer | VK_DESCRIPTOR_TYPE_STORAGE_BUFFERorVK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC |
| input attachment | VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT |
| inline uniform block | VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK |
| acceleration structure | VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHRorVK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV |
| weight image | VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM |
| block matching image | VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM |
| storage tensor | VK_DESCRIPTOR_TYPE_TENSOR_ARM |
| Resource type | Storage Class | Type1 | Decoration(s)2 |
|---|---|---|---|
sampler |
|
| |
sampled image |
|
| |
storage image |
|
| |
combined image sampler |
|
| |
uniform texel buffer |
|
| |
storage texel buffer |
|
| |
uniform buffer |
|
|
|
storage buffer |
|
|
|
|
| ||
input attachment |
|
|
|
inline uniform block |
|
|
|
acceleration structure |
|
| |
sample weight image |
|
|
|
block matching image |
|
|
|
storage tensor |
|
|
Descriptor Heap Interface
The descriptor heap interface is a vastly simplified interface for accessing resources through pointers to heaps of different types, without many of the restrictions that apply to the descriptor set interface.
Two built-in pointers are available to shaders:
- SamplerHeapEXT for samplers
- Descriptor Heaps > Using Heaps for resources
These built-ins must be declared as pointers in the UniformConstant
Storage Class.
These built-ins must not be used to access data outside of the heap bound
to them.
These built-ins can be accessed non-uniformly, with no further decoration
required, and with no dependency on other features or properties.
The UniformId decoration can be applied to the result of accesses to
indicate that the data will be accessed uniformly to a given scope, as a
hint to improve performance on some implementations.
Resources retrieved from each heap must have been created with descriptors that match the variable being declared, as follows:
| Descriptor Type | Heap | SPIR-V Type |
|---|---|---|
VK_DESCRIPTOR_TYPE_SAMPLER | SamplerHeapEXT | OpTypeSampler |
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE | ResourceHeapEXT | OpTypeImage |
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE | ResourceHeapEXT | OpTypeImage |
VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM | ResourceHeapEXT | OpTypeImage |
VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM | ResourceHeapEXT | OpTypeImage |
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT | ResourceHeapEXT | OpTypeImage |
VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER | ResourceHeapEXT | OpTypeImage |
VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER | ResourceHeapEXT | OpTypeImage |
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER | ResourceHeapEXT | OpTypeBufferEXTwith theUniform``Storage``Class |
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER | ResourceHeapEXT | OpTypeBufferEXTwith theStorageBuffer``Storage``Class |
VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR | ResourceHeapEXT | OpTypeAccelerationStructureKHR |
VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV | ResourceHeapEXT | OpTypeAccelerationStructureNV |
VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV | ResourceHeapEXT | OpTypeAccelerationStructureKHR |
VK_DESCRIPTOR_TYPE_TENSOR_ARM | ResourceHeapEXT | OpTypeTensorARM |
While the built-in heap pointers can be declared and dereferenced as pointing to any type, applications must not access data types valid for one heap from any other heap.
When one of the types above is read from a heap in the shader, it will read a number of bytes equal to value advertised for the VkDescriptorType as returned by vkGetPhysicalDeviceDescriptorSizeEXT.
For image types, there are further restrictions on the operands used for the type, according to the descriptor type:
| Descriptor Type | Dim | Arrayed | MS | Sampled |
|---|---|---|---|---|
| VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE | * | * | 0 | 1 |
| VK_DESCRIPTOR_TYPE_STORAGE_IMAGE | * | * | 0 or 1 | 2 |
| VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT | SubpassData | 0 | 0 or 1 | 2 |
| VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER | Buffer | 0 | 0 | 2 |
| VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER | Buffer | 0 | 0 | 2 |
| VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM | 2D | 1 | 0 | 1 |
| VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM | 2D | 0 | 0 | 1 |
For storage images and input attachments, MS is 0 if the image has one
sample per pixel, or 1 otherwise.
For sampled and storage images, the Dim and Arrayed qualifiers
depend on the VkImageViewType specified when writing the descriptor:
| Image View Type | Dim | Arrayed |
|---|---|---|
| VK_IMAGE_VIEW_TYPE_1D | 1D | 0 |
| VK_IMAGE_VIEW_TYPE_2D | 2D | 0 |
| VK_IMAGE_VIEW_TYPE_3D | 3D | 0 |
| VK_IMAGE_VIEW_TYPE_CUBE | Cube | 0 |
| VK_IMAGE_VIEW_TYPE_1D_ARRAY | 1D | 1 |
| VK_IMAGE_VIEW_TYPE_2D_ARRAY | 2D | 1 |
| VK_IMAGE_VIEW_TYPE_CUBE_ARRAY | Cube | 1 |
The type and format of the image resource must also match between the API and SPIR-V.
Descriptors accessed via the ResourceHeapEXT built-in must be
explicitly laid out.
There is no further limit to the number of resources that can be accessed by a shader through a heap pointer beyond the size of the bound range for each heap.
DescriptorSet and Binding Assignment
A variable decorated with a DescriptorSet decoration of s and a
Binding decoration of b indicates that this variable is
associated with the VkDescriptorSetLayoutBinding that has a
binding equal to b in pSetLayouts[s] that was specified
in VkPipelineLayoutCreateInfo.
If using descriptor heaps, such a variable will instead be associated with a
shader binding.
If not using descriptor heaps,
DescriptorSet decoration values must be between zero and
maxBoundDescriptorSets minus one, inclusive.
If a pipeline is created with
VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT,
or a shader is created with VK_SHADER_CREATE_DESCRIPTOR_HEAP_BIT_EXT,
DescriptorSet decorations can be any 32-bit unsigned integer value.
Binding decoration values can be any 32-bit unsigned integer value.
Each descriptor set has its own binding name space.
If the Binding decoration is used with an array, the entire array is
assigned that binding value.
The decorated array must have an Element Type corresponding to a
descriptor type, and the size of the array must be no larger than the
number of descriptors in the binding.
If the array is runtime-sized, then array elements greater than or equal to
the size of that binding in the bound descriptor set must not be used.
If the array is runtime-sized, the runtimeDescriptorArray feature must be enabled and the
RuntimeDescriptorArray capability must be declared.
The index of each element of the array is referred to as the arrayElement.
For the purposes of interface matching and descriptor set
operations, if a resource variable is not an
array, it is treated as if it has an arrayElement of zero.
Binding, when using
descriptor heap mappings, each element will be
assigned a consecutive offset according to the stride for that type.
Applications should take care to set subsequent bindings with this in mind
to avoid unintentional overlap.There is a limit on the number of resources of each type that can be
accessed by a pipeline stage as shown in
Shader Resource Limits.
The Resources Per Stage column gives the limit on the number each type
of resource that can be statically used for an entry point in any given
stage in a pipeline.
The Resource Types column lists which resource types are counted against
the limit.
Some resource types count against multiple limits.
The VK_DESCRIPTOR_TYPE_MUTABLE_EXT descriptor type counts as one
individual resource and one for every unique resource limit per descriptor
set type that is present in the associated binding’s
VkMutableDescriptorTypeListEXT.
If multiple descriptor types in VkMutableDescriptorTypeListEXT map to
the same resource limit, only one descriptor is consumed for purposes of
computing resource limits.
These limits only apply to resources accessed with DescriptorSet and
Binding values.
A pipeline layout may include descriptor sets and bindings which are not
referenced by any variables statically used by the entry points for the
shader stages in the binding’s stageFlags.
Similarly, descriptor heap bindings may
include mappings that are unused by the shader.
However, if a variable assigned to a given DescriptorSet and
Binding is statically used by the entry point for a shader stage, the
heap bindings must specify a mapping for it
when using heaps, or the
pipeline layout must contain a descriptor set layout binding in that
descriptor set layout and for that binding number, and that binding’s
stageFlags must include the appropriate VkShaderStageFlagBits
for that stage.
The variable must be of a valid resource type determined by its SPIR-V type
and storage class, as defined in
Shader Resource and
Storage Class Correspondence.
The descriptor set layout binding must be of a corresponding descriptor
type, as defined in Shader Resource
and Descriptor Type Correspondence.
Aliased
decorations should be used to avoid data hazards (see
section
2.18.2 Aliasing in the SPIR-V specification).If multiple shader variables with the same set and binding values are
declared in a single shader, but with different declared types, where any of
those are not supported by the relevant bound descriptor, that shader can
only be executed if the variables with the unsupported type are not
statically used.A noteworthy example of using multiple statically-used shader variables
sharing the same descriptor set and binding values is a descriptor of type
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER that has multiple
corresponding shader variables in the UniformConstant storage class,
where some could be OpTypeImage (Sampled=1), some could be
OpTypeSampler, and some could be OpTypeSampledImage.| Resources per Stage | Resource Types |
|---|---|
| sampler |
combined image sampler | |
| sampled image |
combined image sampler | |
uniform texel buffer | |
sample weight image | |
block matching image | |
| storage image |
storage texel buffer | |
| uniform buffer |
uniform buffer dynamic | |
| storage buffer |
storage buffer dynamic | |
| input attachment1 |
| inline uniform block |
| acceleration structure |
Offset and Stride Assignment
When a SPIR-V object is declared using an explicit layout, it must be laid out according to the following additional requirements.
Offset decorations does not need to follow member
declaration order.Alignment Requirements
There are different alignment requirements depending on the specific resources and on the features enabled.
Matrix types are defined in terms of arrays as follows:
- A column-major matrix with C columns and R rows is equivalent to a C element array of vectors with R components.
- A row-major matrix with C columns and R rows is equivalent to an R element array of vectors with C components.
The scalar alignment of the type of an OpTypeStruct member is defined
recursively as follows:
- A scalar of size N has a scalar alignment of N.
- A vector type has a scalar alignment equal to that of its component type.
- An array type has a scalar alignment equal to that of its element type.
- A structure has a scalar alignment equal to the largest scalar alignment of any of its members.
- A matrix type inherits scalar alignment from the equivalent array declaration.
OpTypeImagehas a scalar alignment equal to the value ofimageDescriptorAlignmentOpTypeBufferEXThas a scalar alignment equal to the value ofbufferDescriptorAlignmentOpTypeSamplerhas a scalar alignment equal to the value ofsamplerDescriptorAlignmentOpTypeTensorARMhas a scalar alignment equal to the value oftensorDescriptorAlignment
The aligned size of a OpTypeImage, OpTypeBufferEXT, or
OpTypeSampler can be queried from within SPIR-V using
OpConstantSizeOfEXT, which can be used with the OffsetIdEXT or
ArrayStrideIdEXT decorations to lay out types in a descriptor heap.
OpConstantSizeOfEXT returns the following for values for each type:
| Type | Size |
|---|---|
OpTypeSampler | samplerDescriptorSizealigned tosamplerDescriptorAlignment |
OpTypeImage | imageDescriptorSizealigned toimageDescriptorAlignment |
OpTypeBufferEXT | bufferDescriptorSizealigned tobufferDescriptorAlignment |
OpTypeAccelerationStructureKHR | bufferDescriptorSizealigned tobufferDescriptorAlignment |
The base alignment of the type of an OpTypeStruct member is defined
recursively as follows:
- A scalar has a base alignment equal to its scalar alignment.
- A two-component vector has a base alignment equal to twice its scalar alignment.
- A three- or four-component vector has a base alignment equal to four times its scalar alignment.
- An array has a base alignment equal to the base alignment of its element type.
- A structure has a base alignment equal to the largest base alignment of
any of its members.
An empty structure has a base alignment equal to the size of the
smallest scalar type permitted by the capabilities declared in the
SPIR-V module.
(e.g., for a 1 byte aligned empty structure in the
StorageBufferstorage class,StorageBuffer8BitAccessorUniformAndStorageBuffer8BitAccessmust be declared in the SPIR-V module.) - A matrix type inherits base alignment from the equivalent array declaration.
The extended alignment of the type of an OpTypeStruct member is
similarly defined as follows:
- A scalar or vector type has an extended alignment equal to its base alignment.
- An array or structure type has an extended alignment equal to the largest extended alignment of any of its members, rounded up to a multiple of 16.
- A matrix type inherits extended alignment from the equivalent array declaration.
A member is defined to improperly straddle if either of the following are true:
- It is a vector with total size less than or equal to 16 bytes, and has
Offsetdecorations placing its first byte at F and its last byte at L, where floor(F / 16) != floor(L / 16). - It is a vector with total size greater than 16 bytes and has its
Offsetdecorations placing its first byte at a non-integer multiple of 16.
Standard Buffer Layout
Every member of an OpTypeStruct that is required to be explicitly laid
out must be aligned according to the first matching rule as follows.
If the structure is contained in pointer types of multiple storage classes,
it must satisfy the requirements for every storage class used to reference
it.
- If the
scalarBlockLayoutfeature is enabled and the storage class isUniform,StorageBuffer,PhysicalStorageBuffer,ShaderRecordBufferKHR, orPushConstant, or the storage class isUniformConstantand the type is decorated with eitherSamplerHeapEXTorResourceHeapEXT, then every member must be aligned according to its scalar alignment. - If the
workgroupMemoryExplicitLayoutScalarBlockLayoutfeature is enabled and the storage class isWorkgroupthen every member must be aligned according to its scalar alignment. - All vectors must be aligned according to their scalar alignment.
- If the
uniformBufferStandardLayoutfeature is not enabled, then any member of anOpTypeStructwith a storage class ofUniformand a decoration ofBlockmust be aligned according to its extended alignment. - Every other member must be aligned according to its base alignment.
The memory layout must obey the following rules:
- The
OffsetorOffsetIdEXTdecoration of any member must be a multiple of its alignment. - Any
ArrayStride, orArrayStrideIdEXT, orMatrixStridedecoration must be a multiple of the alignment of the array or matrix as defined above.
If one of the conditions below applies
- The storage class is
Uniform,StorageBuffer,PhysicalStorageBuffer,ShaderRecordBufferKHR, orPushConstant, and thescalarBlockLayoutfeature is not enabled. - The storage class is
Workgroup, and either the structure member is not part of aBlockor theworkgroupMemoryExplicitLayoutScalarBlockLayoutfeature is not enabled. - The storage class is any other storage class.
the memory layout must also obey the following rules:
- Vectors must not improperly straddle, as defined above.
- The
Offsetdecoration of a member must not place it between the end of a structure, an array, or a matrix and the next multiple of the alignment of that structure, array, or matrix.
Built-In Variables
Built-in variables are accessed in shaders by declaring a variable decorated
with a BuiltIn SPIR-V decoration.
The meaning of each BuiltIn decoration is as follows.
In the remainder of this section, the name of a built-in is used
interchangeably with a term equivalent to a variable decorated with that
particular built-in.
Built-ins that represent integer values can be declared as either signed or
unsigned 32-bit integers.
As mentioned above, some inputs and outputs have an additional level of arrayness relative to other shader inputs and outputs. This level of arrayness is not included in the type descriptions below, but must be included when declaring the built-in.
Any two variables declared in the Input storage class listed as
operands on the same OpEntryPoint must not have the same BuiltIn
decoration.
Any two variables declared in the Output storage class listed as
operands on the same OpEntryPoint must not have the same BuiltIn
decoration.
Built-in values for descriptor heaps are listed in the descriptor heap chapter:
Types used to access these built-ins must be laid out explicitly using the
Offset, OffsetIdEXT, ArrayStride, ArrayStrideIdEXT, and
MatrixStride decorations as specified in Offset and Stride Assignment.