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.
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. Generally, when non-shader stages are between shader stages, the user-defined variables, and most built-in variables, form an interface between the shader stages.
The variables forming the input or 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.
Output
variables of a shader stage have undefined values until the
shader writes to them or uses the Initializer
operand when declaring
the variable.
Shader built-in variables meeting the following requirements define the built-in interface block. They must
BuiltIn
decoration,
Built-ins only participate in interface matching if they are declared in
such a block.
They must not have any Location
or Component
decorations.
There must be no more than one built-in interface block per shader per interface.
The remaining variables listed by OpEntryPoint
with the Input
or
Output
storage class form the user-defined variable interface.
These variables must be identified with a Location
decoration and can
also be identified with a Component
decoration.
A user-defined output variable is considered to match an input variable in
the subsequent stage if the two variables are declared with the same
Location
and Component
decoration and match in type and
decoration, except that interpolation decorations are not required to match.
For the purposes of interface matching, variables declared without a
Component
decoration are considered to have a Component
decoration
of zero.
Variables or block members declared as structures are considered to match in type if and only if the structure members match in type, decoration, number, and declaration order. Variables or block members declared as arrays are considered to match in type only if both declarations specify the same element type and size.
Tessellation control shader per-vertex output variables and blocks, and tessellation control, tessellation evaluation, and geometry shader per-vertex input variables and blocks are required to be declared as arrays, with each element representing input or output values for a single vertex of a multi-vertex primitive. For the purposes of interface matching, the outermost array dimension of such variables and blocks is ignored.
At an interface between two non-fragment shader stages, the built-in interface block must match exactly, as described above. At an interface involving the fragment shader inputs, the presence or absence of any built-in output does not affect the interface matching.
At an interface between two shader stages, the user-defined variable interface must match exactly, as described above.
Any input value to a shader stage is well-defined as long as the preceding stages writes to a matching output, as described above.
Additionally, scalar and vector inputs are well-defined if there is a corresponding output satisfying all of the following conditions:
In this case, the components of the input will be taken from the first components of the output, and any extra components of the output will be ignored.
This section describes how many locations are consumed by a given type. As mentioned above, geometry shader inputs, tessellation control shader inputs and outputs, and tessellation evaluation inputs all 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 locations the type consumes.
The Location
value specifies an interface slot comprised of a 32-bit
four-component vector conveyed between stages.
The Component
specifies
components within these vector
locations.
Only types with widths of 32 or 64 are supported in shader interfaces.
Inputs and outputs of the following types consume a single interface location:
64-bit three- and four-component vectors consume two consecutive locations.
If a declared input or output is an array of size n and each element takes m locations, it will be assigned m × n consecutive locations starting with the location specified.
If the declared input or output is an n × m 32- or 64-bit matrix, it will be assigned multiple locations starting with the location specified. The number of locations assigned for each matrix will be the same as for an n-element array of m-component vectors.
The layout of a structure type used as an Input
or Output
depends
on whether it is also a Block
(i.e. has a Block
decoration).
If it is a not a Block
, then the structure type must have a
Location
decoration.
Its members are assigned consecutive locations in their declaration order,
with the first member assigned to the location specified for the structure
type.
The members, and their nested types, must not themselves have Location
decorations.
If the structure type is a Block
but without a Location
, then each
of its members must have a Location
decoration.
If it is a Block
with a Location
decoration, then its members are
assigned consecutive locations in declaration order, starting from the first
member which is initially assigned the location specified for the
Block
.
Any member with its own Location
decoration is assigned that location.
Each remaining member is assigned the location after the immediately
preceding member in declaration order.
The locations 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, either explicitly or implicitly.
Any two outputs listed as operands on the same OpEntryPoint
must not
be assigned the same location, either explicitly or implicitly.
The number of input and output locations available for a shader input or output interface are limited, and dependent on the shader stage as described in Table 14.1, “Shader Input and Output Locations”.
Table 14.1. Shader Input and Output Locations
Shader Interface | Locations Available |
---|---|
vertex input |
|
vertex output |
|
tessellation control input |
|
tessellation control output |
|
tessellation evaluation input |
|
tessellation evaluation output |
|
geometry input |
|
geometry output |
|
fragment input |
|
fragment output |
|
The Component
decoration allows the Location
to be more finely
specified for scalars and vectors, down to the individual components within
a location that are consumed.
The components within a location are 0, 1, 2, and 3.
A variable or block member starting at component N will consume components
N, N+1, N+2, …
up through its size.
For single precision types, it is invalid if this sequence of components
gets larger than 3.
A scalar 64-bit type will consume two of these components in sequence, and a
two-component 64-bit vector type will consume all four components available
within a location.
A three- or four-component 64-bit vector type must not specify a
Component
decoration.
A three-component 64-bit vector type will consume all four components of the
first location and components 0 and 1 of the second location.
This leaves components 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.