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.

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.

In this chapter, there are references to SPIR-V terms such as the 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.

Output variables of a shader stage have undefined: values until the shader writes to them or uses the Initializer operand when declaring the variable.

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 BuiltIn decoration,
  • 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, and Stream
    • one is not decorated with Component and the other is declared with a Component of 0
    • Interpolation decorations
    • RelaxedPrecision if 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 OpTypeArray with an Element Type equivalent to the OpType* declaration of the output, and neither is a structure member; or
    • if the maintenance4 feature is enabled, they are declared as OpTypeVector variables, and the output has a Component Count value higher than that of the input but the same Component Type; or
    • if the output is declared in a mesh shader as an OpTypeArray with an Element Type equivalent to the OpType* 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 an OpTypeArray with an Element Type equivalent to the OpType* 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 both are structures and every member has an interface match.

The word 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 Assignment

This section describes Location assignments for user-defined variables and how many Location slots are consumed by a given user-variable type. As mentioned above, some inputs and outputs have an additional level of arrayness relative to other shader inputs and outputs. This outer array level is removed from the type before considering how many Location slots the type consumes.

The Location value specifies an interface slot comprised of a 32-bit four-component vector conveyed between stages. The Component specifies word components within these vector Location slots. Only types with widths of 16, 32 or 64 are supported in shader interfaces.

Inputs and outputs of the following types consume a single interface Location:

  • 16-bit scalar and vector types, and
  • 32-bit scalar and vector types, and
  • 64-bit scalar and 2-component vector types.

64-bit three- and four-component vectors consume two consecutive Location slots.

If a declared input or output is an array of size n and each element takes m Location slots, it will be assigned m × n consecutive Location slots starting with the specified Location.

If the declared input or output is an n × m 16-, 32- or 64-bit matrix, it will be assigned multiple Location slots starting with the specified Location. The number of Location slots assigned for each matrix will be the same as for an n-element array of m-component vectors.

An OpVariable with a structure type that is not a block must be decorated with a Location.

When an OpVariable with a structure type (either block or non-block) is decorated with a Location, the members in the structure type must not be decorated with a Location. The OpVariable’s members are assigned consecutive Location slots in declaration order, starting from the first member, which is assigned the Location decoration from the OpVariable.

When a block-type OpVariable is declared without a Location decoration, each member in its structure type must be decorated with a Location. Types nested deeper than the top-level members must not have Location decorations.

The Location slots consumed by block and 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.

Any two inputs listed as operands on the same OpEntryPoint must not be assigned the same Location slot and Component word, either explicitly or implicitly. Any two outputs listed as operands on the same OpEntryPoint must not be assigned the same Location slot and Component word, either explicitly or implicitly.

The number of input and output Location slots available for a shader input or output interface is limited, and dependent on the shader stage as described in xref::name::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 xref::name::interfaces-iointerfaces-limits.

Component Assignment

The Component decoration allows the Location to be more finely specified for scalars and vectors, down to the individual Component word within a Location slot that are consumed. The Component word within a Location are 0, 1, 2, and 3. A variable or block member starting at Component N will consume Component words N, N+1, N+2, …​ up through its size. For 16-, and 32-bit types, it is invalid if this sequence of Component words gets larger than 3. A scalar 64-bit type will consume two of these Component words in sequence, and a two-component 64-bit vector type will consume all four Component words available within a Location. A three- or four-component 64-bit vector type must not specify a non-zero Component decoration. A three-component 64-bit vector type will consume all four Component words of the first Location and Component 0 and 1 of the second Location. This leaves Component 2 and 3 available for other component-qualified declarations.

A scalar or two-component 64-bit data type must not specify a Component decoration of 1 or 3. A Component decoration must not be specified for any type that is not a scalar or vector.

A four-component 64-bit data type will consume all four Component words of the first Location and all four Component words of the second Location.

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.

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. Locations are consumed as described in Location Assignment. 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.

vkCmdSetRenderingAttachmentLocationsKHRSet color attachment location mappings for a command buffer
VkRenderingAttachmentLocationInfoKHRStructure specifying attachment locations

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 the invocation does not set a value for them, the input values to those blending or color attachment writes are undefined:.

Components of the output variables are assigned as described in Component Assignment. 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 underlying type (floating-point or integer). 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.

There must be no output variable which has the same Location, Component, and Index as any other, either explicitly declared or implied.

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.

This extension is intended only for use by OpenGL emulation layers, and as such the dithering algorithm applied to the subpass should be equivalent to the vendor’s OpenGL implementation, if any.

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 undefined:.

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, it consumes N consecutive input attachments, starting with the index specified. 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.

vkCmdSetRenderingInputAttachmentIndicesKHRSet input attachment index mappings for a command buffer
VkRenderingInputAttachmentIndexInfoKHRStructure specifying input attachment indices

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 undefined:. 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 tracked 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 used between stages must match between the stages using it. Specifically:

  • 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.
  • 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.

Any shader with an incoming ray payload, incoming callable data, or hit attribute must only declare one variable of that type.

Shader Resource Interface

When a shader stage accesses buffer or image resources, as described in the Resource Descriptors section, the shader resource variables must be matched with the pipeline layout that is provided at pipeline creation time.

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 two sub-interfaces: 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 Block decoration, and
  • laid out explicitly using the Offset, ArrayStride, and MatrixStride decorations as specified in Offset and Stride Assignment.

There must be no more than one push constant block statically used per shader entry point.

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).

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, Uniform or UniformConstant (including the variables in the fragment input attachment interface) that are statically used by the shader entry points for the pipeline.

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 the shaderStorageImageWriteWithoutFormat feature is enabled and the shader module declares the StorageImageWriteWithoutFormat capability.
  • For OpImageWrite, if the image format supports VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT and the shader module declares the StorageImageWriteWithoutFormat capability.
  • For OpImageRead or OpImageSparseRead, if the image format is listed in the storage without format list and if the shaderStorageImageReadWithoutFormat feature is enabled and the shader module declares the StorageImageReadWithoutFormat capability.
  • For OpImageRead or OpImageSparseRead, if the image format supports VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT and the shader module declares the StorageImageReadWithoutFormat capability.
  • For OpImageRead, if Dim is SubpassData (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 Block or BufferBlock decoration, and
  • laid out explicitly using the Offset, ArrayStride, and MatrixStride decorations 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 Block decoration, and
  • laid out explicitly using the Offset, ArrayStride, and MatrixStride decorations 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).

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 descriptorcan have a type of OpTypeImage, OpTypeSampler (Sampled=1), or OpTypeSampledImage.

Arrays of any of these types can be indexed with constant integral expressions. The following features must be enabled and capabilities must be declared in order to index such arrays with dynamically uniform or non-uniform indices:

  • Storage images (except storage texel buffers and input attachments):
    • Dynamically uniform: shaderStorageImageArrayDynamicIndexing and StorageImageArrayDynamicIndexing
    • Non-uniform: shaderStorageImageArrayNonUniformIndexing and StorageImageArrayNonUniformIndexing
  • Storage texel buffers:
    • Dynamically uniform: shaderStorageTexelBufferArrayDynamicIndexing and StorageTexelBufferArrayDynamicIndexing
    • Non-uniform: shaderStorageTexelBufferArrayNonUniformIndexing and StorageTexelBufferArrayNonUniformIndexing
  • Input attachments:
    • Dynamically uniform: shaderInputAttachmentArrayDynamicIndexing and InputAttachmentArrayDynamicIndexing
    • Non-uniform: shaderInputAttachmentArrayNonUniformIndexing and InputAttachmentArrayNonUniformIndexing
  • Sampled images (except uniform texel buffers), samplers and combined image samplers:
    • Dynamically uniform: shaderSampledImageArrayDynamicIndexing and SampledImageArrayDynamicIndexing
    • Non-uniform: shaderSampledImageArrayNonUniformIndexing and SampledImageArrayNonUniformIndexing
  • Uniform texel buffers:
    • Dynamically uniform: shaderUniformTexelBufferArrayDynamicIndexing and UniformTexelBufferArrayDynamicIndexing
    • Non-uniform: shaderUniformTexelBufferArrayNonUniformIndexing and UniformTexelBufferArrayNonUniformIndexing
  • Uniform buffers:
    • Dynamically uniform: shaderUniformBufferArrayDynamicIndexing and UniformBufferArrayDynamicIndexing
    • Non-uniform: shaderUniformBufferArrayNonUniformIndexing and UniformBufferArrayNonUniformIndexing
  • Storage buffers:
    • Dynamically uniform: shaderStorageBufferArrayDynamicIndexing and StorageBufferArrayDynamicIndexing
    • Non-uniform: shaderStorageBufferArrayNonUniformIndexing and StorageBufferArrayNonUniformIndexing
  • 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.

If an instruction loads from or stores to a resource (including atomics and image instructions) and the resource descriptor being accessed is not dynamically uniform, then the corresponding non-uniform indexing feature must be enabled and the capability must be declared. If an instruction loads from or stores to a resource (including atomics and image instructions) and the resource descriptor being accessed is loaded from an array element with a non-constant index, then the corresponding dynamic or non-uniform indexing feature must be enabled and the capability must be declared.

If the combined image sampler enables sampler Y′CBCR conversion or samples a subsampled image, it must be indexed only by constant integral expressions when aggregated into arrays in shader code, irrespective of the shaderSampledImageArrayDynamicIndexing feature.

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.

DescriptorSet decoration values must be between zero and maxBoundDescriptorSets minus one, inclusive. Binding decoration values can be any 32-bit unsigned integer value, as described in Descriptor Set Layout. 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 array must be a single-dimensional array and 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.

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.

The 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.

However, if a variable assigned to a given DescriptorSet and Binding is statically used by the entry point for a shader stage, 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.

There are no limits on the number of shader variables that can have overlapping set and binding values in a shader; but which resources are statically used has an impact. If any shader variable identifying a resource is statically used in a shader, then the underlying descriptor bound at the declared set and binding must support the declared type in the shader when the shader executes.

If multiple shader variables are declared with the same set and binding values, and with the same underlying descriptor type, they can all be statically used within the same shader. However, accesses are not automatically synchronized, and 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.

Offset and Stride Assignment

Certain objects must be explicitly laid out using the Offset, ArrayStride, and MatrixStride, as described in SPIR-V explicit layout validation rules. All such layouts also must conform to the following requirements.

The numeric order of 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 on the device.

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.

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 struct in the StorageBuffer storage class, StorageBuffer8BitAccess or UniformAndStorageBuffer8BitAccess must 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 Offset decorations 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 Offset decorations 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 struct is contained in pointer types of multiple storage classes, it must satisfy the requirements for every storage class used to reference it.

  1. If the scalarBlockLayout feature is enabled on the device and the storage class is Uniform, StorageBuffer, PhysicalStorageBuffer, ShaderRecordBufferKHR, or PushConstant then every member must be aligned according to its scalar alignment.
  2. If the workgroupMemoryExplicitLayoutScalarBlockLayout feature is enabled on the device and the storage class is Workgroup then every member must be aligned according to its scalar alignment.
  3. All vectors must be aligned according to their scalar alignment.
  4. If the uniformBufferStandardLayout feature is not enabled on the device, then any member of an OpTypeStruct with a storage class of Uniform and a decoration of Block must be aligned according to its extended alignment.
  5. Every other member must be aligned according to its base alignment.

Even if scalar alignment is supported, it is generally more performant to use the base alignment.

The memory layout must obey the following rules:

  • The Offset decoration of any member must be a multiple of its alignment.
  • Any ArrayStride or MatrixStride decoration 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, or PushConstant, and the scalarBlockLayout feature is not enabled on the device.
  • The storage class is Workgroup, and either the struct member is not part of a Block or the workgroupMemoryExplicitLayoutScalarBlockLayout feature is not enabled on the device.
  • 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 Offset decoration 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.

The std430 layout in GLSL satisfies these rules for types using the base alignment. The std140 layout satisfies the rules for types using the extended alignment.

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.

BaryCoordKHRBarycentric coordinates of a fragment
BaryCoordNoPerspAMDBarycentric coordinates of a fragment center in screen-space
BaryCoordNoPerspKHRBarycentric coordinates of a fragment in screen-space
BaryCoordNoPerspCentroidAMDBarycentric coordinates of a fragment centroid in screen-space
BaryCoordNoPerspSampleAMDBarycentric coordinates of a sample center in screen-space
BaryCoordPullModelAMDInverse barycentric coordinates of a fragment center
BaryCoordSmoothAMDBarycentric coordinates of a fragment center
BaryCoordSmoothCentroidAMDBarycentric coordinates of a fragment centroid
BaryCoordSmoothSampleAMDBarycentric coordinates of a sample center
BaseInstanceFirst instance being rendered
BaseVertexFirst vertex being rendered
ClipDistanceApplication-specified clip distances
ClipDistancePerViewNVApplication-specified clip distances per view
ClusterIDHUAWEIcluster culling shader output variable
ClusterShadingRateHUAWEIcluster culling shader output variable
CullDistanceApplication-specified cull distances
CullDistancePerViewNVApplication-specified cull distances per view
CullPrimitiveEXTApplication-specified culling state per primitive
CullMaskKHROpTrace specified ray cull mask
CurrentRayTimeNVTime value of a ray intersection
DeviceIndexIndex of the device executing the shader
DrawIndexIndex of the current draw
FirstIndexHUAWEIcluster culling shader output variable
FragCoordScreen-space coordinate of the fragment center
FragDepthApplication-specified depth for depth testing
FirstInstanceHUAWEIcluster culling shader output variable
FirstVertexHUAWEIcluster culling shader output variable
FragInvocationCountEXTNumber of fragment shader invocations for a fragment
FragSizeEXTSize of the screen-space area covered by the fragment
FragStencilRefEXTApplication-specified stencil reference value used in stencil tests
FragmentSizeNVSize of the screen-space area covered by the fragment
FrontFacingFront face determination of a fragment
FullyCoveredEXTIndication of whether a fragment is fully covered
GlobalInvocationIdGlobal invocation ID
HelperInvocationIndication of whether a fragment shader is a helper invocation
HitKindKHRKind of hit that triggered an any-hit or closest hit ray shader
HitTNVT value of a ray intersection
HitTriangleVertexPositionsKHRVertices of an intersected triangle
IncomingRayFlagsKHRFlags used to trace a ray
IndexCountHUAWEIcluster culling shader output variable
InstanceCountHUAWEIcluster culling shader output variable
InstanceCustomIndexKHRCustom index associated with an intersected instance
InstanceIdId associated with an intersected instance
InvocationIdInvocation ID in a geometry or tessellation control shader
InvocationsPerPixelNVNumber of fragment shader invocations for the current pixel
InstanceIndexIndex of an instance
LaunchIdKHRLaunch Id for ray shaders
LaunchSizeKHRLaunch dimensions for ray shaders
LayerLayer index for layered rendering
LayerPerViewNVLayer index per view for layered rendering
LocalInvocationIdLocal invocation ID
LocalInvocationIndexLinear local invocation index
MeshViewCountNVNumber of views processed by a mesh or task shader
MeshViewIndicesNVIndices of views processed by a mesh or task shader
NumWorkgroupsNumber of workgroups in a dispatch
ObjectRayDirectionKHRRay direction in object space
ObjectRayOriginKHRRay origin in object space
ObjectToWorldKHRTransformation matrix from object to world space
PatchVerticesNumber of vertices in an input patch
PointCoordFragment coordinates in screen-space within a point primitive
PointSizeSize of a point primitive
PositionVertex position
PositionPerViewNVVertex position per view
PrimitiveCountNVNumber of primitives output by a mesh shader
PrimitiveIdPrimitive ID
PrimitiveIndicesNVIndices of primitives in a mesh shader
PrimitivePointIndicesEXTIndices of point primitives in a mesh shader
PrimitiveLineIndicesEXTIndices of line primitives in a mesh shader
PrimitiveTriangleIndicesEXTIndices of triangle primitives in a mesh shader
PrimitiveShadingRateKHRPrimitive contribution to fragment shading rate
RayGeometryIndexKHRGeometry index in a ray shader
RayTmaxKHRMaximum T value of a ray
RayTminKHRMinimum T value of a ray
SampleIdSample ID within a fragment
SampleMaskCoverage mask for a fragment shader invocation
SamplePositionPosition of a shaded sample
ShadingRateKHRShading rate of a fragment
SMCountNVNumber of SMs on the device
SMIDNVSM ID on which a shader invocation is running
SubgroupEqMaskMask of shader invocations in a subgroup with the same subgroup local invocation ID
SubgroupGeMaskMask of shader invocations in a subgroup with the same or higher subgroup local invocation ID
SubgroupGtMaskMask of shader invocations in a subgroup with a higher subgroup local invocation ID
SubgroupLeMaskMask of shader invocations in a subgroup with the same or lower subgroup local invocation ID
SubgroupLtMaskMask of shader invocations in a subgroup with a lower subgroup local invocation ID
SubgroupLocalInvocationIdID of the invocation within a subgroup
SubgroupSizeSize of a subgroup
TaskCountNVNumber of mesh shader workgroups that will be generated
TessCoordBarycentric coordinate of a tessellated vertex within a patch
TessLevelOuterOuter tessellation levels
TessLevelInnerInner tessellation levels
VertexCountHUAWEIcluster culling shader output variable
VertexIndexVertex index of a shader invocation
VertexOffsetHUAWEIcluster culling shader output variable
ViewIndexView index of a shader invocation
ViewportIndexViewport index used
ViewportMaskNVMask of the viewports used
ViewportMaskPerViewNVMask of viewports broadcast to per view
WarpsPerSMNVNumber of warps per SM
WarpIDNVWarp ID within an SM of a shader invocation
WorkgroupIdWorkgroup ID of a shader
WorkgroupSizeSize of a workgroup
WorldRayDirectionKHRRay direction in world space
WorldRayOriginKHRRay origin in world space
WorldToObjectKHRTransformation matrix from world to object space
CoreCountARMNumber of cores on the device
CoreMaxIDARMMax core ID that can be observed on the device running the invovation reading CoreMaxIDARM
CoreIDARMCore ID on which a shader invocation is running
WarpMaxIDARMMax ID for a warp on the core running a shader invovation
WarpIDARMWarp ID within a core of a shader invocation
CoalescedInputCountAMDXNumber of inputs coalesced for a coalescing node in a work graph
ShaderIndexAMDXIndex assigned to the shader within the workgraph