Vulkan Environment for SPIR-V
Shaders for Vulkan are defined by the Khronos SPIR-V Specification as well as the Khronos SPIR-V Extended Instructions for GLSL Specification. This appendix defines additional SPIR-V requirements applying to Vulkan shaders.
Versions and Formats
A Vulkan 1.4 implementation must support the 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, and 1.6 versions of SPIR-V and the 1.0 version of the SPIR-V Extended Instructions for GLSL.
A SPIR-V module passed into vkCreateShaderModule is interpreted as a series of 32-bit words in host endianness, with literal strings packed as described in section 2.2 of the SPIR-V Specification. The first few words of the SPIR-V module must be a magic number and a SPIR-V version number, as described in section 2.3 of the SPIR-V Specification.
Capabilities
The table below lists the set of SPIR-V
capabilities that may be supported in Vulkan implementations.
The application must not use any of these capabilities in SPIR-V passed to
vkCreateShaderModule unless one of the following conditions is met for
the VkDevice specified in the device parameter of
vkCreateShaderModule:
-
The corresponding field in the table is blank.
-
Any corresponding Vulkan feature is enabled.
-
Any corresponding Vulkan extension is enabled.
-
Any corresponding Vulkan property is supported.
-
The corresponding core version is supported (as returned by VkPhysicalDeviceProperties::
apiVersion).
The application must not pass a SPIR-V module containing any of the following to vkCreateShaderModule:
-
any
OpCapabilitynot listed above, -
an unsupported capability, or
-
a capability which corresponds to a Vulkan feature or extension which has not been enabled.
SPIR-V Extensions
The following table lists SPIR-V extensions
that implementations may support.
The application must not pass a SPIR-V module to vkCreateShaderModule
that uses the following SPIR-V extensions unless one of the following
conditions is met for the VkDevice specified in the device
parameter of vkCreateShaderModule:
-
Any corresponding Vulkan extension is enabled.
-
The corresponding core version is supported (as returned by VkPhysicalDeviceProperties::
apiVersion).
SPIR-V OpExtensionVulkan extension or core version |
|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Validation Rules Within a Module
A SPIR-V module passed to vkCreateShaderModule must conform to the following rules:
Precision and Operation of SPIR-V Instructions
The following rules apply to half, single, and double-precision floating-point instructions:
-
Positive and negative infinities and positive and negative zeros are generated as dictated by IEEE 754, but subject to the precisions allowed in the table below.
-
Signaling NaNs are not required to be generated and exceptions are never raised. Signaling NaN may be converted to quiet NaNs values by any floating-point instruction.
-
The set of operations
OpPhi,OpSelect,OpFunctionCall,OpReturnValue,OpVectorExtractDynamic,OpVectorInsertDynamic,OpVectorShuffle,OpCompositeConstruct,OpCompositeExtract,OpCompositeInsert,OpTranspose,OpCopyObject,OpCopyLogical,OpCopyMemory,OpGroupNonUniformBroadcast,OpGroupNonUniformBroadcastFirst,OpGroupNonUniformShuffle,OpGroupNonUniformShuffleXor,OpGroupNonUniformShuffleUp,OpGroupNonUniformShuffleDown,OpGroupNonUniformQuadBroadcast,OpGroupNonUniformQuadSwap,OpSubgroupReadInvocationKHR,OpSubgroupFirstInvocationKHR,OpGroupNonUniformRotateKHR,OpCooperativeMatrixLoadKHR,OpCooperativeMatrixStoreKHR,OpCooperativeMatrixLoadNV,OpCooperativeMatrixStoreNV,OpCooperativeMatrixLoadTensorNV,OpCooperativeMatrixStoreTensorNV,OpAtomicLoad,OpAtomicStore,OpAtomicExchange,OpStore, andOpLoadare referred to as bit-preserving operations. -
The floating-point environment used for an instruction can be determined as follows:
-
If the SPIR-V specifies it explicitly using the
FPFastMathdecoration orFPFastMathDefaultExecutionModethen that is used. -
If the environment is not specified in the SPIR-V then it is determined as follows:
-
If the operation is not decorated
NoContractionthen the flagsAllowContract,AllowReassoc,AllowRecip, andAllowTransformare assumed. -
If any of the following conditions are true then the flags
NSZ,NotInf, andNotNaNare assumed:-
The entry point does not use the
ExecutionModeSignedZeroInfNanPreservewith a bit-width corresponding to one of the operands or to the result type. -
The operation is not a bit-preserving operation and is not one of
OpFConvert,OpFNegate,OpFAdd,OpFSub,OpFMul,OpFDiv,OpIsNan,OpIsInf,OpVectorTimesScalar,OpMatrixTimesScalar,OpVectorTimesMatrix,OpMatrixTimesVector,OpMatrixTimesMatrix,OpOuterProduct,OpDot,OpFOrdEqual,OpFUnordEqual,OpFOrdNotEqual,OpFUnordNotEqual,OpFOrdLessThan,OpFUnordLessThan,OpFOrdGreaterThan,OpFUnordGreaterThan,OpFOrdLessThanEqual,OpFUnordLessThanEqual,OpFOrdGreaterThanEqual,OpFUnordGreaterThanEqual,OpGroupNonUniformAllEqual,OpSubgroupAllEqualKHR,OpGroupNonUniformFMin,OpGroupNonUniformFMax,OpAtomicCompareExchange,OpAtomicCompareExchangeWeak,OpDPdx,OpDPdy,OpFwidth,OpDPdxFine,OpDPdyFine,OpFwidthFine,OpDPdxCoarse,OpDPdyCoarse, orOpFwidthCoarse. -
The operation is an
OpLoadfrom theInputStorageClassin the fragment shader stage.
-
-
-
-
All bit-preserving operations and the following instructions must not flush denormalized values:
OpConstant,OpConstantComposite,OpSpecConstant,OpSpecConstantComposite, andOpBitcast. -
Denormalized values are supported.
-
By default, any half, single, or double-precision denormalized value input into a shader or potentially generated by any instruction (except those listed above) or any extended instructions for GLSL in a shader may be flushed to zero.
-
If the entry point is declared with the
DenormFlushToZeroExecutionModethen for the affected instructions the denormalized result must be flushed to zero and the denormalized operands may be flushed to zero. Denormalized values obtained via unpacking an integer into a vector of values with smaller bit width and interpreting those values as floating-point numbers must be flushed to zero. -
The following core SPIR-V instructions must respect the
DenormFlushToZeroExecutionMode:OpSpecConstantOp(with opcodeOpFConvert),OpFConvert,OpFNegate,OpFAdd,OpFSub,OpFMul,OpFDiv,OpFRem,OpFMod,OpVectorTimesScalar,OpMatrixTimesScalar,OpVectorTimesMatrix,OpMatrixTimesVector,OpMatrixTimesMatrix,OpOuterProduct,OpDot,OpGroupNonUniformFMin,OpGroupNonUniformFMax,OpAtomicFAddEXT,OpAtomicFMinEXT,OpAtomicFMaxEXT,OpDPdx,OpDPdy,OpFwidth,OpDPdxFine,OpDPdyFineOpFwidthFine,OpDPdxCoarse,OpDPdyCoarse,OpFwidthCoarse; and the following extended instructions for GLSL:Round,RoundEven,Trunc,FAbs,Floor,Ceil,Fract,Radians,Degrees,Sin,Cos,Tan,Asin,Acos,Atan,Sinh,Cosh,Tanh,Asinh,Acosh,Atanh,Atan2,Pow,Exp,Log,Exp2,Log2,Sqrt,InverseSqrt,Determinant,MatrixInverse,Modf,ModfStruct,FMin,FMax,FClamp,FMix,Step,SmoothStep,Fma,UnpackHalf2x16,Length,Distance,Cross,Normalize,FaceForward,Reflect,Refract,NMin,NMax, andNClamp. -
The following core SPIR-V instructions must respect the
DenormPreserveExecutionMode:OpSpecConstantOp,OpFConvert,OpFNegate,OpFAdd,OpFSub,OpFMul,OpVectorTimesScalar,OpMatrixTimesScalar,OpVectorTimesMatrix,OpMatrixTimesVector,OpMatrixTimesMatrix,OpOuterProduct,OpDot,OpFOrdEqual,OpFUnordEqual,OpFOrdNotEqual,OpFUnordNotEqual,OpFOrdLessThan,OpFUnordLessThan,OpFOrdGreaterThan,OpFUnordGreaterThan,OpFOrdLessThanEqual,OpFUnordLessThanEqual,OpFOrdGreaterThanEqual,OpFUnordGreaterThanEqual,OpSubgroupAllEqualKHR,OpGroupNonUniformAllEqual,OpGroupNonUniformFMin,OpGroupNonUniformFMax,OpAtomicCompareExchange,OpAtomicCompareExchangeWeak,OpAtomicFAddEXT,OpAtomicFMinEXT,OpAtomicFMaxEXT,OpDPdx,OpDPdy,OpFwidth,OpDPdxFine,OpDPdyFineOpFwidthFine,OpDPdxCoarse,OpDPdyCoarse,OpFwidthCoarse; and the following extended instructions for GLSL:FAbs,FSign,Radians,Degrees,FMin,FMax,FClamp,FMix,Fma,PackHalf2x16,PackDouble2x32,UnpackHalf2x16,UnpackDouble2x32,NMin,NMax, andNClamp.
-
The precision of double-precision instructions is at least that of single precision.
The precision of individual operations is defined in Precision of Individual Operations. Subject to the constraints below, however, implementations may reorder or combine operations, resulting in expressions exhibiting different precisions than might be expected from the constituent operations.
Evaluation of Expressions
Implementations may rearrange floating-point operations using any of the
mathematical properties governing the expressions in precise arithmetic,
even where the floating- point operations do not share these properties.
This includes, but is not limited to, associativity and distributivity, and
may involve a different number of rounding steps than would occur if the
operations were not rearranged.
In shaders that use the SignedZeroInfNanPreserve Execution Mode the
values must be preserved if they are generated after any rearrangement but
the Execution Mode does not change which rearrangements are valid.
This rearrangement can be prevented for particular operations by using the
NoContraction decoration.
|
For example, in the absence of the If the |
Precision of Individual Operations
The precision of individual operations is defined either in terms of rounding (correctly rounded), as an error bound in ULP, or as inherited from a formula as follows:
Operations that are described as returning the “correct result” will return the infinitely precise result which, due to the nature of the operation, will not need rounding.
Operations described as “correctly rounded” will return the infinitely
precise result, x, rounded so as to be representable in
floating-point.
If the entry point is declared with the RoundingModeRTE or the
RoundingModeRTZ Execution Mode then this is done according to
IEEE 754 “roundTiesToEven” or “roundTowardZero” rounding
directions, respectively.
Otherwise, they are rounded with
implementation-defined rounding mode.
Operations described as “correctly rounded with implementation-defined rounding mode” will return the infinitely precise result, x, rounded so as to be representable in floating-point. If x is exactly representable then x will be returned. Otherwise, either the floating-point value closest to and no less than x or the value closest to and no greater than x will be returned. Which value is chosen is implementation-defined.
Where an error bound of n ULP (units in the last place) is given, for an operation with infinitely precise result x the value returned must be in the range [x - n × ulp(x), x + n × ulp(x)]. The function ulp(x) is defined as follows:
-
If there exist non-equal, finite floating-point numbers a and b such that a ≤ x ≤ b then ulp(x) is the minimum possible distance between such numbers, \(ulp(x) = \mathrm{min}_{a,b} | b - a |\). If such numbers do not exist then ulp(x) is defined to be the difference between the two non-equal, finite floating-point numbers nearest to x.
Where the range of allowed return values includes any value of magnitude larger than that of the largest representable finite floating-point number, operations may, additionally, return either an infinity of the appropriate sign or the finite number with the largest magnitude of the appropriate sign. If the infinitely precise result of the operation is not mathematically defined then the value returned is undefined.
Where an operation’s precision is described as being inherited from a
formula, the result returned must be at least as accurate as the result of
computing an approximation to x using a formula equivalent to the
given formula applied to the supplied inputs.
Specifically, the formula given may be transformed using the mathematical
associativity, commutativity and distributivity of the operators involved to
yield an equivalent formula.
The SPIR-V precision rules, when applied to each such formula and the given
input values, define a range of permitted values.
If NaN is one of the permitted values then the operation may return
any result, otherwise let the largest permitted value in any of the ranges
be Fmax and the smallest be Fmin.
The operation must return a value in the range [x - E, x + E]
where \(E = \mathrm{max} \left( | x - F_{\mathrm{min}} |, | x -
F_{\mathrm{max}} | \right) \).
If the entry point is declared with the DenormFlushToZero execution
mode, then any intermediate denormal value(s) while evaluating the formula
may be flushed to zero.
Denormal final results must be flushed to zero.
If the entry point is declared with the DenormPreserve Execution Mode,
then denormals must be preserved throughout the formula.
For half- (16 bit) and single- (32 bit) precision instructions, precisions are required to be at least as follows:
| Instruction | Single precision, unless decorated with RelaxedPrecision | Half precision |
|---|---|---|
|
Correct result. |
|
|
Correctly rounded. |
|
|
Correctly rounded. |
|
|
Correctly rounded. |
|
|
Inherited from . |
|
|
Inherited from . |
|
|
Inherited from . |
|
|
Correctly rounded. |
|
|
Inherited from . |
|
|
Correct result. |
|
|
Correct result. |
|
|
Correct result. |
|
|
Correct result. |
|
|
Correct result. |
|
|
Correct result. |
|
|
Correct result. |
|
|
Correct result. |
|
|
Correct result. |
|
|
Correct result. |
|
|
2.5 ULP for |y| = 0 or |y| in the range [2-126, 2126]. |
2.5 ULP for |y| = 0 or |y| in the range [2-14, 214]. |
|
Inherited from x - y × trunc(x/y). |
|
|
Inherited from x - y × floor(x/y). |
|
|
Correctly rounded with implementation defined rounding mode. |
|
conversions between types |
Correctly rounded. |
|
|
Correct result. |
|
|
Return value correct result, value in memory correctly rounded. |
|
|
Correct result. |
|
|
Correctly rounded. |
|
|
Correctly rounded. |
|
|
Correctly rounded. |
|
|
The |
| Instruction | Single precision, unless decorated with RelaxedPrecision | Half precision |
|---|---|---|
|
Inherited from |
|
|
ULP. |
ULP. |
|
3 ULP outside the range . Absolute error < inside the range . |
3 ULP outside the range . Absolute error < inside the range . |
|
Inherited from |
|
|
Inherited from 1.0 / |
|
|
2 ULP. |
|
|
Inherited from , where is a correctly rounded approximation to . |
|
|
Inherited from , where is a correctly rounded approximation to . |
|
|
Absolute error inside the range . |
Absolute error inside the range . |
|
Absolute error inside the range . |
Absolute error inside the range . |
|
Inherited from . |
|
|
Inherited from . |
|
|
Inherited from . |
|
|
4096 ULP |
5 ULP. |
|
Inherited from . |
|
|
Inherited from . |
|
|
Inherited from . |
|
|
Inherited from . |
|
|
Inherited from . |
|
|
Inherited from . |
|
|
Correct result. |
|
|
Correctly rounded. |
|
|
Inherited from . |
|
|
Inherited from . |
|
|
Inherited from |
|
|
Inherited from . |
|
|
Inherited from |
|
|
Inherited from x - 2.0 × |
|
|
Inherited from k < 0.0 ? 0.0 : eta × I - (eta × |
|
|
Correctly rounded. |
|
|
Correctly rounded. |
|
|
Correctly rounded. |
|
|
Correct result. |
|
|
Correct result. |
|
|
Correctly rounded. |
|
|
Correctly rounded. |
|
|
Correctly rounded. |
|
|
Correctly rounded. |
|
|
Correct result. |
|
|
Correct result. |
|
|
Correct result. |
|
|
Inherited from . |
|
|
Correctly rounded. |
|
|
Inherited from , where . |
|
|
Correct result. |
|
|
Correct result. |
|
|
Correct result. |
|
|
Correctly rounded with implementation defined rounding mode. |
|
GLSL.std.450 extended instructions specifically defined in terms of the above instructions inherit the above errors. GLSL.std.450 extended instructions not listed above and not defined in terms of the above have undefined precision.
If the maintenance8 feature is not enabled
and if
either operand to OpSRem and OpSMod instructions is negative the
result is undefined.
|
While the |
OpCooperativeMatrixMulAddNV performs its operations in an
implementation-dependent order and internal precision.
OpCooperativeMatrixMulAddKHR performs its operations in an
implementation-dependent order and internal precision.
OpCooperativeVectorMatrixMulNV and
OpCooperativeVectorMatrixMulAddNV perform their operations in an
implementation-dependent order and internal precision.
When inputType is VK_COMPONENT_TYPE_FLOAT16_KHR and
inputInterpretation is a lower-precision floating-point type (e.g.
VK_COMPONENT_TYPE_FLOAT_E4M3_NV or
VK_COMPONENT_TYPE_FLOAT_E5M2_NV), the input vector should be
converted to the lower-precision type before performing the matrix-vector
multiply, but may keep the full 16 bits of precision.
Signedness of SPIR-V Image Accesses
SPIR-V associates a signedness with all integer image accesses.
This is required in certain parts of the SPIR-V and the Vulkan image access
pipeline to ensure defined results.
The signedness is determined from a combination of the access instruction’s
Image Operands and the underlying image’s Sampled Type
as follows:
-
If the instruction’s
ImageOperandscontains theSignExtendoperand then the access is signed. -
If the instruction’s
ImageOperandscontains theZeroExtendoperand then the access is unsigned. -
Otherwise, the image accesses signedness matches that of the
SampledTypeof theOpTypeImagebeing accessed.
Image Format and Type Matching
When specifying the Image Format of an OpTypeImage, the
converted bit width and type, as shown in the table below, must match the
Sampled Type.
The signedness must match the signedness of any access to the image.
|
Formatted accesses are always converted from a shader readable type to the resource’s format or vice versa via Format Conversion for reads and Texel Output Format Conversion for writes. As such, the bit width and format below do not necessarily match 1:1 with what might be expected for some formats. |
For a given Image Format, the Sampled Type must be the
type described in the Type column of the below table, with its
Literal Width set to that in the Bit Width column.
Every access that is made to the image must have a signedness equal to that
in the Signedness column (where applicable).
| Image Format | Type-Declaration instructions | Bit Width | Signedness |
|---|---|---|---|
|
Any |
Any |
Any |
|
|
32 |
N/A |
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|
32 |
1 |
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
0 |
||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|
64 |
1 |
|
0 |
The SPIR-V Type is defined by an instruction in SPIR-V, declared with the Type-Declaration Instruction, Bit Width, and Signedness from above.
Compatibility Between SPIR-V Image Dimensions and Vulkan ImageView Types
SPIR-V Image Dim values are compatible with VkImageView
viewType values as defined below:
| SPIR-V Image Dim | Compatible Vulkan ImageView viewTypes |
|---|---|
1D |
|
2D |
|
3D |
|
Cube |
|
Compatibility Between SPIR-V Image Formats and Vulkan Formats
SPIR-V Image Format values are compatible with VkFormat
values as defined below:
| SPIR-V Image Format | Compatible Vulkan Format |
|---|---|
|
Any |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ray Query Precision and Operation
The values returned by
OpRayQueryGetIntersectionTriangleVertexPositionsKHR are transformed by
the geometry transform, which is performed at standard
floating-point precision, but without a
specifically defined order of floating-point operations to perform the
matrix multiplication.