SPIR-V 的 Vulkan 环境
Vulkan 的着色器由Khronos SPIR-V 规范以及GLSL 的 Khronos SPIR-V 扩展指令规范定义。本附录定义了适用于 Vulkan 着色器的其他 SPIR-V 要求。
版本和格式
Vulkan 1.4 实现必须支持 SPIR-V 的 1.0、1.1、1.2、1.3、1.4、1.5 和 1.6 版本,以及 GLSL 的 SPIR-V 扩展指令的 1.0 版本。
传入 vkCreateShaderModule 的 SPIR-V 模块被解释为主机字节序中的一系列 32 位字,其中文字字符串按照 SPIR-V 规范第 2.2 节中的描述进行打包。SPIR-V 模块的前几个字必须是幻数和 SPIR-V 版本号,如 SPIR-V 规范的第 2.3 节中所述。
功能
下表列出了 Vulkan 实现中可能支持的 SPIR-V 功能集。除非满足以下针对 vkCreateShaderModule 的 device 参数中指定的 VkDevice 的条件之一,否则应用程序不得在传递给 vkCreateShaderModule 的 SPIR-V 中使用这些功能中的任何一个。
-
表中相应的字段为空。
-
任何相应的 Vulkan 特性已启用。
-
任何相应的 Vulkan 扩展已启用。
-
支持任何相应的 Vulkan 属性。
-
支持相应的核心版本(由 VkPhysicalDeviceProperties::
apiVersion返回)。
应用程序**必须**不将包含以下任何内容的 SPIR-V 模块传递给vkCreateShaderModule
-
任何上面未列出的
OpCapability, -
不支持的功能,或
-
与未启用的 Vulkan 功能或扩展相对应的功能。
SPIR-V 扩展
下表列出了实现**可能**支持的 SPIR-V 扩展。应用程序**必须**不将使用以下 SPIR-V 扩展的 SPIR-V 模块传递给vkCreateShaderModule,除非满足以下条件之一:VkDevice 在vkCreateShaderModule的 device 参数中指定
-
任何相应的 Vulkan 扩展已启用。
-
支持相应的核心版本(由 VkPhysicalDeviceProperties::
apiVersion返回)。
模块内的验证规则
传递给vkCreateShaderModule的 SPIR-V 模块**必须**符合以下规则
SPIR-V 指令的精度和操作
以下规则适用于半精度、单精度和双精度浮点指令。
-
不要求生成信号 NaN,并且永远不会引发异常。任何浮点指令可能将信号 NaN 转换为静默 NaN 值。
-
操作集合
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和OpLoad被称为位保留操作。 -
用于指令的浮点环境可以按如下方式确定:
-
如果 SPIR-V 使用
FPFastMath修饰符或FPFastMathDefaultExecutionMode显式指定,则使用该指定的环境。 -
如果未在 SPIR-V 中指定环境,则按如下方式确定:
-
如果操作未修饰
NoContraction,则假定标志AllowContract、AllowReassoc、AllowRecip和AllowTransform。 -
如果满足以下任何条件,则假定标志
NSZ、NotInf和NotNaN。-
入口点不使用
ExecutionModeSignedZeroInfNanPreserve,其位宽对应于其中一个操作数或结果类型。 -
该操作不是位保留操作,也不是
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或OpFwidthCoarse之一。 -
该操作是从片段着色器阶段的
InputStorageClass执行的OpLoad。
-
-
-
-
所有位保留操作和以下指令必须不刷新非规格化值:
OpConstant、OpConstantComposite、OpSpecConstant、OpSpecConstantComposite和OpBitcast。 -
支持非规格化值。
-
默认情况下,输入到着色器中或可能由着色器中任何指令(上述列表中的指令除外)或任何 GLSL 扩展指令生成的任何半精度、单精度或双精度非规格化值可能被刷新为零。
-
如果入口点声明了
DenormFlushToZeroExecutionMode,则对于受影响的指令,非规格化结果必须被刷新为零,并且非规格化操作数可能被刷新为零。通过将整数解包为具有较小位宽的值向量并将这些值解释为浮点数而获得的非规格化值必须被刷新为零。 -
以下核心 SPIR-V 指令必须遵守
DenormFlushToZeroExecutionMode:OpSpecConstantOp(操作码为OpFConvert)、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;以及以下 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和NClamp。 -
以下核心 SPIR-V 指令必须遵守
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;以及以下 GLSL 扩展指令:FAbs、FSign、Radians、Degrees、FMin、FMax、FClamp、FMix、Fma、PackHalf2x16、PackDouble2x32、UnpackHalf2x16、UnpackDouble2x32、NMin、NMax和NClamp。
-
双精度指令的精度至少与单精度指令的精度相同。
各个操作的精度在各个操作的精度中定义。然而,在满足以下约束的情况下,实现**可以**重新排序或组合操作,从而导致表达式的精度与构成操作的预期精度不同。
表达式的求值
实现**可以**使用精确算术中支配表达式的任何数学属性来重新排列浮点运算,即使浮点运算不共享这些属性。这包括但不限于结合律和分配律,并且**可能**涉及与未重新排列操作时发生的不同的舍入步骤数量。在使用 SignedZeroInfNanPreserve Execution Mode 的着色器中,如果在任何重新排列之后生成值,则**必须**保留这些值,但 Execution Mode 不会改变哪些重新排列是有效的。可以使用 NoContraction 修饰来阻止特定操作的这种重新排列。
|
例如,在没有 如果应用了 |
各个操作的精度
各个操作的精度根据舍入(正确舍入)、ULP中的误差范围或从公式继承来定义,如下所示
描述为返回“正确结果”的操作将返回无限精确的结果,由于操作的性质,该结果不需要舍入。
描述为“正确舍入”的操作将返回无限精确的结果,x,并进行舍入以使其可以在浮点中表示。如果入口点声明为使用 RoundingModeRTE 或 RoundingModeRTZ Execution Mode,则分别根据 IEEE 754 “roundTiesToEven” 或 “roundTowardZero” 舍入方向进行舍入。否则,它们将使用 实现定义的舍入模式进行舍入。
描述为“使用实现定义的舍入模式进行正确舍入”的操作将返回无限精确的结果,x,并进行舍入以使其可以在浮点中表示。如果 x 可以精确表示,则将返回 x。否则,将返回最接近且不小于 x 的浮点值或最接近且不大于 x 的值。选择哪个值由实现定义。
如果给定的误差范围为 n ULP(最后一位的单位),对于具有无限精确结果 x 的操作,返回的值**必须**在范围 [x - n × ulp(x), x + n × ulp(x)] 内。函数 ulp(x) 定义如下
-
如果存在不相等的有限浮点数 a 和 b,使得 a ≤ x ≤ b,则 ulp(x) 是这些数字之间的最小可能距离,\(ulp(x) = \mathrm{min}_{a,b} | b - a |\)。如果不存在这样的数字,则 ulp(x) 定义为最接近 x 的两个不相等的有限浮点数之间的差。
如果允许的返回值范围包括任何大于最大可表示的有限浮点数的量级的值,则操作**可能**还会返回具有适当符号的无穷大或具有适当符号的最大量级的有限数字。如果操作的无限精确结果在数学上未定义,则返回的值是**未定义的**。
如果操作的精度被描述为从公式继承,则返回的结果**必须**至少与使用等效于给定公式应用于提供的输入的公式计算 x 的近似值的结果一样准确。具体而言,可以使用所涉及运算符的数学结合律、交换律和分配律转换给定的公式,以产生等效的公式。当应用于每个此类公式和给定输入值时,SPIR-V 精度规则定义了允许值的范围。如果 NaN 是允许值之一,则操作可能返回任何结果,否则,让任何范围内的最大允许值为 Fmax,最小值为 Fmin。该操作**必须**返回范围 [x - E, x + E] 内的值,其中 \(E = \mathrm{max} \left( | x - F_{\mathrm{min}} |, | x - F_{\mathrm{max}} | \right) \)。如果入口点声明为使用 DenormFlushToZero 执行模式,则在评估公式时,任何中间次正规值都**可能**被刷新为零。次正规最终结果**必须**被刷新为零。如果入口点声明为使用 DenormPreserve Execution Mode,则次正规值**必须**在整个公式中保留。
对于半精度(16 位)和单精度(32 位)指令,精度**必须**至少如下所示
| 指令 | 单精度,除非使用 RelaxedPrecision 修饰 | 半精度 |
|---|---|---|
|
正确结果。 |
|
|
正确舍入。 |
|
|
正确舍入。 |
|
|
正确舍入。 |
|
|
继承自 。 |
|
|
继承自 。 |
|
|
Inherited from . |
|
|
正确舍入。 |
|
|
继承自 。 |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
当 |y| = 0 或 |y| 在 [2-126, 2126] 范围内时,为 2.5 ULP。 |
当 |y| = 0 或 |y| 在 [2-14, 214] 范围内时,为 2.5 ULP。 |
|
继承自 x - y × trunc(x/y)。 |
|
|
继承自 x - y × floor(x/y)。 |
|
|
使用实现定义的舍入模式正确舍入。 |
|
类型之间的转换 |
正确舍入。 |
|
|
正确结果。 |
|
|
返回值正确,内存中的值已正确舍入。 |
|
|
正确结果。 |
|
|
正确舍入。 |
|
|
正确舍入。 |
|
|
正确舍入。 |
|
|
|
| 指令 | 单精度,除非使用 RelaxedPrecision 修饰 | 半精度 |
|---|---|---|
|
继承自 |
|
|
ULP。 |
ULP。 |
|
超出范围 范围 3 ULP。 绝对误差 < 在 范围。 |
超出范围 3 ULP 。绝对误差 < 在范围 内。 |
|
继承自 |
|
|
继承自 1.0 / |
|
|
2 ULP。 |
|
|
Inherited from , where is a correctly rounded approximation to . |
|
|
Inherited from , where is a correctly rounded approximation to . |
|
|
绝对误差 在范围 内。 |
绝对误差 在范围 内。 |
|
绝对误差 在范围 内。 |
绝对误差 在范围 内。 |
|
继承自 。 |
|
|
Inherited from . |
|
|
Inherited from . |
|
|
4096 ULP |
5 ULP。 |
|
Inherited from . |
|
|
Inherited from . |
|
|
继承自 . |
|
|
Inherited from . |
|
|
Inherited from . |
|
|
继承自 。 |
|
|
正确结果。 |
|
|
正确舍入。 |
|
|
继承自 。 |
|
|
继承自 。 |
|
|
继承自 |
|
|
Inherited from . |
|
|
继承自 |
|
|
继承自 x - 2.0 × |
|
|
继承自 k < 0.0 ? 0.0 : eta × I - (eta × |
|
|
正确舍入。 |
|
|
正确舍入。 |
|
|
正确舍入。 |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
正确舍入。 |
|
|
正确舍入。 |
|
|
正确舍入。 |
|
|
正确舍入。 |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
继承自 。 |
|
|
正确舍入。 |
|
|
Inherited from , where . |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
正确结果。 |
|
|
使用实现定义的舍入模式正确舍入。 |
|
GLSL.std.450 扩展指令,特别是根据上述指令定义的,会继承上述错误。未列出且不是根据上述定义的 GLSL.std.450 扩展指令具有未定义的精度。
如果未启用 maintenance8 功能,并且 OpSRem 和 OpSMod 指令的任何一个操作数为负数,则结果为未定义。
|
虽然 Vulkan 环境支持 |
OpCooperativeMatrixMulAddNV 以依赖于实现的方式和内部精度执行其操作。
OpCooperativeMatrixMulAddKHR 以依赖于实现的方式和内部精度执行其操作。
SPIR-V 图像访问的符号性
SPIR-V 将符号性与所有整数图像访问相关联。这是 SPIR-V 和 Vulkan 图像访问管道的某些部分所必需的,以确保定义的结果。符号性由访问指令的 Image Operands 和底层图像的 Sampled Type 的组合确定,如下所示
-
如果指令的
ImageOperands包含SignExtend操作数,则访问为带符号的。 -
如果指令的
ImageOperands包含ZeroExtend操作数,则访问为无符号的。 -
否则,图像访问的符号性与正在访问的
OpTypeImage的SampledType的符号性匹配。
图像格式和类型匹配
当指定 OpTypeImage 的 Image Format 时,如下表所示,转换后的位宽和类型必须与 Sampled Type 匹配。符号性必须与对图像的任何访问的符号性匹配。
对于给定的 Image Format,Sampled Type 必须是下表类型列中描述的类型,其 Literal Width 设置为位宽列中的值。对图像进行的每次访问必须具有与符号性列中相同的符号性(如果适用)。
| 图像格式 | 类型声明指令 | 位宽 | 符号性 |
|---|---|---|---|
|
任意 |
任意 |
任意 |
|
|
32 |
32 |
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|
32 |
1 |
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
0 |
||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|
64 |
1 |
|
0 |
SPIR-V 类型由 SPIR-V 中的指令定义,该指令使用上面的类型声明指令、位宽和符号性声明。
SPIR-V 图像维度和 Vulkan ImageView 类型之间的兼容性
SPIR-V Image Dim 值与 VkImageView viewType 值兼容,如下定义
| SPIR-V 图像 Dim | 兼容的 Vulkan ImageView viewTypes |
|---|---|
1D |
|
2D |
|
3D |
|
立方体 |
|
SPIR-V 图像格式和 Vulkan 格式之间的兼容性
SPIR-V Image Format 值与 VkFormat 值兼容,如下定义
| SPIR-V 图像格式 | 兼容的 Vulkan 格式 |
|---|---|
|
任意 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
射线查询精度和操作
OpRayQueryGetIntersectionTriangleVertexPositionsKHR 返回的值通过几何变换进行转换,几何变换以标准浮点精度执行,但没有明确定义的浮点运算顺序来执行矩阵乘法。