Vulkan规范:第二章(2)

来源:互联网 发布:java windows 路径 编辑:程序博客网 时间:2024/06/07 14:42

2.6. 错误

Vulkan是一个分层的API。最底层是Vulkan核心层,就是本规范所定义的。应用程序可以在其上使用附加层来调试、验证或者达到其他的目的。

Vulkan一个核心的原则就是构建并提交命令缓冲区应该是非常高效的。所以,错误检查和状态验证在核心层应该尽量小, 尽管可以使用这些层来开启更严格的验证。

核心层假设应用程序正确的使用API。除了按照本规范所写的内容,应用程序中核心层错误的使用API将导致未知的结果,可能包括程序终止。 然而,Vulkan实现必须保证应用程序错误的使用并不影响操作系统的完整性、Vulkan实现或者其他Vulkan客户端应用程序,也不允许一个应用程序去 访问另外一个程序的数据。应用程序可以通过启用特征,限制和格式中描述的robustBufferAccess特征来要求更健壮的保证。

Validation of correct API usage is left to validation layers. Applications should be developed with validation layers enabled, to help catch and eliminate errors. Once validated, released applications should not enable validation layers by default.

2.6.1. 正确使用(Valid Usage)

正确使用定义了一系列的条件,它们必须被遵守,来让应用程序达到预想的运行时行为。 这些条件只依赖于Vulkan状态,这些参数或者对象的使用被条件所限制。

一些正确使用条件依赖于运行时限制条件或者可用的特性。 可能通过对这些限制和特征的Vulkan的最小支持值或者其他已知的值来验证这些条件 。

正确使用条件并不覆盖正确行为的条件(包含返回错误码)。

正确使用条件应该应用到命令或者数据结构上,关于条件完整的信息在程序运行的使用是已知的。 This is such that a validation layer or linter can be written directly against these statements at the point they are specified.

注意

This does lead to some non-obvious places for valid usage statements. For instance, the valid values for a structure might depend on a separate value in the calling command. In this case, the structure itself will not reference this valid usage as it is impossible to determine validity from the structure that it is invalid - instead this valid usage would be attached to the calling command.

Another example is draw state - the state setters are independent, and can cause a legitimately invalid state configuration between draw calls; so the valid usage statements are attached to the place where all state needs to be valid - at the draw command.

Valid usage conditions are described in a block labelled “Valid Usage” following each command or structure they apply to.

2.6.2. 隐式的正确使用(Implicit Valid Usage)

一些正确使用条件应用到API的所有的命令和数据结构上,除非显式的指明一个特定命令或者结构。 这些条件被认为是 隐式的 ,在每个命令或者数据结构可能带有标签为 "`Valid Usage (Implicit)`"的块中进行描述。 隐式正确使用条件在下面详细的讲解。

对象handle的正确使用(Valid Usage for Object Handles)

一个命令的输入参数必须是一个有效的对象handle,除非有明确指明。 有效的handle符合以下条件:

  • 它是被之前的一次成功的API调用产生的。这个函数在spec里有列举。

  • 它没有被之前的API所删除或者释放。这些函数在spec里有列举。

  • 被该对象使用的任何对象,是创建或者执行的一部分,必须是有效的。

当 在本规范中称谓时 ,被保留的值VK_NULL_HANDLE 和 NULL 可以用来分别替代有效的 不可分派handle和 可分派handle, 任何成功创建对象的命令不能返回这些值。 把这些值传入 vkDestroy* or vkFree* 命令是合法的,命令将静默的忽略这些值。

指针的正确使用(Valid Usage for Pointers)

任何是指针的参数必须是有效的指针。一个有效的指针包含的值必须指向命令期待的类型的数据, 所有通过指针访问的基础类型(例如数组的所有元素或者数据结构的成员)满足CPU要求的对齐大小。

枚举类型的正确使用(Valid Usage for Enumerated Types)

任何枚举类型的参数必须是该枚举类型有效的枚举值。一个有效的枚举值必须满足:

  • 该枚举值在枚举类型中有定义。

  • 枚举值不是枚举类型中特许的值,比如带有诸如 _BEGIN_RANGE, _END_RANGE_RANGE_SIZE 或 _MAX_ENUM 等前缀的值。

标志位的正确使用(Valid Usage for Flags)

VkFlags 可以用来表示 标志掩码 的枚举:

typedef uint32_t VkFlags;

这些标志位被传入许多命令,表示各种选项,但是 VkFlags 在API中并没有被使用。 相反, Vk*Flags 是 VkFlags的别名,和Vk*FlagBits 中的各个枚举值一一对应。 这些别名在规范的 附录 Flag Types 部分中描述。

Any Vk*Flags member or parameter used in the API must be a valid combination of bit flags. A valid combination is either zero or the bitwise OR of valid bit flags. A bit flag is valid if:

  • The bit flag is defined as part of the Vk*FlagBits type, where the bits type is obtained by taking the flag type and replacing the trailing Flags with FlagBits. For example, a flag value of type VkColorComponentFlags mustcontain only bit flags defined by VkColorComponentFlagBits.

  • The flag is allowed in the context in which it is being used. For example, in some cases, certain bit flags or combinations of bit flags are mutually exclusive.

数据结构的正确使用

任何包含 sType 作为参数的数据结构必须包含一个sType 值,对应着 VkStructureType 数据结构的值。 作为常见规则,这个名字就是把数据结构的前缀Vk 去掉的部分,把首字母大写前添加 _,把整个生成的字符串转化为大写,并在最前添加VK_STRUCTURE_TYPE_ 前缀。 例如, VkImageCreateInfo 类型的数据结构必须有一个sType 类型的值 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO

VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO 和 VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO 被保留给内部的loader 使用,在规范中并没有对应的Vulkan数据结构。

受支持的 structure types 列表在附录中定义。

数据结构指针链的正确使用(Valid Usage for Structure Pointer Chains)

包含 void* pNext成员 的任何参数必须是`NULL`或者指向一个有效的由拓展定义的数据结构的指针,包含sType 和 pNext类型的成员,如Vulkan Documentation and Extensions 文档中"`Extension Interactions`" 一节所描述。 如果拓展被Vulkan实现所支持,它必须被开启。 Vulkan实现的任何组成部分(loader,任何启用的layer和 驱动)必须跳过,无需处理任何带有未被受支持的拓展定义的sType类型 链式数据结构。

拓展的数据结构并没有在基础的Vulkan规范文档中描述,但是在 和这些拓展协作的layered规范中,或者单独的vendor提供的文档中描述。

嵌套数据结构的正确使用(Valid Usage for Nested Structures)

上述条件可以递归的应用到作为命令参数的数据结构上,要么是命令的直接参数,要么它们自己是别的数据结构的成员。

Specifics on valid usage of each command are covered in their individual sections.

2.6.3. 返回值Return Codes

因为Vulkan核心API并未被设计来捕捉错误的使用,一些场景下依然需要返回错误码。 Vulkan的命令通过状态码返回他们的状态,这些状态码分为两类:

  • Successful completion codes are returned when a command needs to communicate success or status information. All successful completion codes are non-negative values.

  • Run time error codes are returned when a command needs to communicate a failure that could only be detected at run time. All run time error codes are negative values.

Vulkan中所有的返回码都在VkResult 中定义。可选的值有:

typedef enum VkResult {    VK_SUCCESS = 0,    VK_NOT_READY = 1,    VK_TIMEOUT = 2,    VK_EVENT_SET = 3,    VK_EVENT_RESET = 4,    VK_INCOMPLETE = 5,    VK_ERROR_OUT_OF_HOST_MEMORY = -1,    VK_ERROR_OUT_OF_DEVICE_MEMORY = -2,    VK_ERROR_INITIALIZATION_FAILED = -3,    VK_ERROR_DEVICE_LOST = -4,    VK_ERROR_MEMORY_MAP_FAILED = -5,    VK_ERROR_LAYER_NOT_PRESENT = -6,    VK_ERROR_EXTENSION_NOT_PRESENT = -7,    VK_ERROR_FEATURE_NOT_PRESENT = -8,    VK_ERROR_INCOMPATIBLE_DRIVER = -9,    VK_ERROR_TOO_MANY_OBJECTS = -10,    VK_ERROR_FORMAT_NOT_SUPPORTED = -11,    VK_ERROR_FRAGMENTED_POOL = -12,} VkResult;
Success Codes
  • VK_SUCCESS 命令正确执行完成

  • VK_NOT_READY fence 或者 query 还没有完成

  • VK_TIMEOUT A wait operation has not completed in the specified time

  • VK_EVENT_SET 一个event被激发了

  • VK_EVENT_RESET An event is unsignaled

  • VK_INCOMPLETE A return array was too small for the result

Error codes
  • VK_ERROR_OUT_OF_HOST_MEMORY A host memory allocation has failed.

  • VK_ERROR_OUT_OF_DEVICE_MEMORY A device memory allocation has failed.

  • VK_ERROR_INITIALIZATION_FAILED Initialization of an object could not be completed for implementation-specific reasons.

  • VK_ERROR_DEVICE_LOST The logical or physical device has been lost. See Lost Device

  • VK_ERROR_MEMORY_MAP_FAILED Mapping of a memory object has failed.

  • VK_ERROR_LAYER_NOT_PRESENT A requested layer is not present or could not be loaded.

  • VK_ERROR_EXTENSION_NOT_PRESENT A requested extension is not supported.

  • VK_ERROR_FEATURE_NOT_PRESENT A requested feature is not supported.

  • VK_ERROR_INCOMPATIBLE_DRIVER The requested version of Vulkan is not supported by the driver or is otherwise incompatible for implementation-specific reasons.

  • VK_ERROR_TOO_MANY_OBJECTS Too many objects of the type have already been created.

  • VK_ERROR_FORMAT_NOT_SUPPORTED A requested format is not supported on this device.

  • VK_ERROR_FRAGMENTED_POOL A requested pool allocation has failed due to fragmentation of the pool’s memory.

If a command returns a run time error, it will leave any result pointers unmodified, unless other behavior is explicitly defined in the specification.

Out of memory errors do not damage any currently existing Vulkan objects. Objects that have already been successfully created can still be used by the application.

性能严苛的命令一般没有返回码。若在这些命令中出现错误,Vulkan实现会把错误报告推迟到一个特定的点。 对于那些录入到命令缓冲区(vkCmd*)的命令,错误是通过 vkEndCommandBuffer 报告出来的。

2.7. 数值表示与计算(Numeric Representation and Computation)

Vulkan实现一般以浮点数进行计算,必须满足下面定义的"`Floating-Point Computation`" 的浮点数范围和精度。 Implementations normally perform computations in floating-point, and must meet the range and precision requirements defined under “Floating-Point Computation” below.

These requirements only apply to computations performed in Vulkan operations outside of shader execution, such as texture image specification and sampling, and per-fragment operations. Range and precision requirements during shader execution differ and are specified by the Precision and Operation of SPIR-V Instructions section.

In some cases, the representation and/or precision of operations is implicitly limited by the specified format of vertex or texel data consumed by Vulkan. Specific floating-point formats are described later in this section.

2.7.1. 浮点计算

大多数浮点运算是通过SPIR-V着色器模块执行的。在着色器内存计算的属性受到限制,在 Precision and Operation of SPIR-V Instructions一节中有描述。

一些浮点计算是在着色器外部进行的,比如视口和深度范围计算。 对于这些计算,我们不指定浮点数是如何表示的,或者对它们的操作是如何完成的,但在本节剩余部分给出如何表示及精度的最小要求。

editing-note

(Jon, Bug 14966) This is a rat’s nest of complexity, both in terms of describing/enumerating places such computation may take place (other than “not shader code”) and in how implementations may do it. We have consciously deferred the resolution of this issue to post-1.0, and in the meantime, the following language inherited from the OpenGL Specification is inserted as a placeholder. Hopefully it can be tightened up considerably.

We require simply that numbers' floating-point parts contain enough bits and that their exponent fields are large enough so that individual results of floating-point operations are accurate to about 1 part in 105. The maximum representable magnitude for all floating-point values must be at least 232.

x × 0 = 0 × x = 0 for any non-infinite and non-NaN x.

1 × x = x × 1 = x.

x + 0 = 0 + x = x.

00 = 1.

Occasionally, further requirements will be specified. Most single-precision floating-point formats meet these requirements.

The special values Inf and -Inf encode values with magnitudes too large to be represented; the special value NaN encodes “Not A Number” values resulting from undefined arithmetic operations such as 0 / 0. Implementations may support Infand NaN in their floating-point computations.

Any representable floating-point value is legal as input to a Vulkan command that requires floating-point data. The result of providing a value that is not a floating-point number to such a command is unspecified, but must not lead to Vulkan interruption or termination. In IEEE 754 arithmetic, for example, providing a negative zero or a denormalized number to an Vulkan command must yield deterministic results, while providing a NaN or Inf yields unspecified results.

2.7.2. 16-Bit Floating-Point Numbers

16-bit floating point numbers are defined in the “16-bit floating point numbers” section of the Khronos Data Format Specification.

Any representable 16-bit floating-point value is legal as input to a Vulkan command that accepts 16-bit floating-point data. The result of providing a value that is not a floating-point number (such as Inf or NaN) to such a command is unspecified, but must not lead to Vulkan interruption or termination. Providing a denormalized number or negative zero to Vulkan must yield deterministic results.

2.7.3. Unsigned 11-Bit Floating-Point Numbers

Unsigned 11-bit floating point numbers are defined in the “Unsigned 11-bit floating point numbers” section of the Khronos Data Format Specification.

When a floating-point value is converted to an unsigned 11-bit floating-point representation, finite values are rounded to the closest representable finite value.

While less accurate, implementations are allowed to always round in the direction of zero. This means negative values are converted to zero. Likewise, finite positive values greater than 65024 (the maximum finite representable unsigned 11-bit floating-point value) are converted to 65024. Additionally: negative infinity is converted to zero; positive infinity is converted to positive infinity; and both positive and negative NaN are converted to positive NaN.

Any representable unsigned 11-bit floating-point value is legal as input to a Vulkan command that accepts 11-bit floating-point data. The result of providing a value that is not a floating-point number (such as Inf or NaN) to such a command is unspecified, but must not lead to Vulkan interruption or termination. Providing a denormalized number to Vulkan mustyield deterministic results.

2.7.4. Unsigned 10-Bit Floating-Point Numbers

Unsigned 10-bit floating point numbers are defined in the “Unsigned 10-bit floating point numbers” section of the Khronos Data Format Specification.

When a floating-point value is converted to an unsigned 10-bit floating-point representation, finite values are rounded to the closest representable finite value.

While less accurate, implementations are allowed to always round in the direction of zero. This means negative values are converted to zero. Likewise, finite positive values greater than 64512 (the maximum finite representable unsigned 10-bit floating-point value) are converted to 64512. Additionally: negative infinity is converted to zero; positive infinity is converted to positive infinity; and both positive and negative NaN are converted to positive NaN.

Any representable unsigned 10-bit floating-point value is legal as input to a Vulkan command that accepts 10-bit floating-point data. The result of providing a value that is not a floating-point number (such as Inf or NaN) to such a command is unspecified, but must not lead to Vulkan interruption or termination. Providing a denormalized number to Vulkan mustyield deterministic results.

2.7.5. General Requirements

Some calculations require division. In such cases (including implied divisions performed by vector normalization), division by zero produces an unspecified result but must not lead to Vulkan interruption or termination.

2.8. 浮点数据转换

When generic vertex attributes and pixel color or depth components are represented as integers, they are often (but not always) considered to be normalized. Normalized integer values are treated specially when being converted to and from floating-point values, and are usually referred to as normalized fixed-point.

In the remainder of this section, b denotes the bit width of the fixed-point integer representation. When the integer is one of the types defined by the API, b is the bit width of that type. When the integer comes from an image containing color or depth component texels, b is the number of bits allocated to that component in its specified image format.

The signed and unsigned fixed-point representations are assumed to be b-bit binary two’s-complement integers and binary unsigned integers, respectively.

2.8.1. Conversion from Normalized Fixed-Point to Floating-Point

Unsigned normalized fixed-point integers represent numbers in the range [0,1]. The conversion from an unsigned normalized fixed-point value c to the corresponding floating-point value f is defined as

\[f = { c \over { 2^b - 1 } }\]

Signed normalized fixed-point integers represent numbers in the range [-1,1]. The conversion from a signed normalized fixed-point value c to the corresponding floating-point value f is performed using

\[f = \max\left( {c \over {2^{b-1} - 1}}, -1.0 \right)\]

Only the range [-2b-1 + 1, 2b-1 - 1] is used to represent signed fixed-point values in the range [-1,1]. For example, if b = 8, then the integer value -127 corresponds to -1.0 and the value 127 corresponds to 1.0. Note that while zero is exactly expressible in this representation, one value (-128 in the example) is outside the representable range, and must be clamped before use. This equation is used everywhere that signed normalized fixed-point values are converted to floating-point.

2.8.2. Conversion from Floating-Point to Normalized Fixed-Point

The conversion from a floating-point value f to the corresponding unsigned normalized fixed-point value c is defined by first clamping f to the range [0,1], then computing

c = convertFloatToUint(f × (2b - 1), b)

where convertFloatToUint}(r,b) returns one of the two unsigned binary integer values with exactly b bits which are closest to the floating-point value r. Implementations should round to nearest. If r is equal to an integer, then that integer value must be returned. In particular, if f is equal to 0.0 or 1.0, then c must be assigned 0 or 2b - 1, respectively.

The conversion from a floating-point value f to the corresponding signed normalized fixed-point value c is performed by clamping f to the range [-1,1], then computing

c = convertFloatToInt(f × (2b-1 - 1), b)

where convertFloatToInt(r,b) returns one of the two signed two’s-complement binary integer values with exactly b bits which are closest to the floating-point value r. Implementations should round to nearest. If r is equal to an integer, then that integer value must be returned. In particular, if f is equal to -1.0, 0.0, or 1.0, then c must be assigned -(2b-1 - 1), 0, or 2b-1 - 1, respectively.

This equation is used everywhere that floating-point values are converted to signed normalized fixed-point.

2.9. API版本数字和语义

Vulkan版本号在API中数个地方被用到。在每一处使用点, API 主版本号次版本号 和 补丁版本号 都被塞入到如下的一个32位整型数字内:

  • 主版本号是10-bit 整型,被塞入到31-22 bit的位置。

  • 次版本号是10-bit 整型,被塞入到21-12 bit的位置。

  • 补丁版本号是12-bit 整型,被塞入到11-0 bit的位置。

Vulkan的任何版本号区别意味着API在一定程度上已经改变了,版本号的每一部分意味着更改的范围不同。

补丁版本号的区别意味着此规范文档或者头文件很小一部分被修改了,通常为了修复bug,或者现有功能有性能性能问题。 这个号码变更不应该影响 兼容性 或两个版本之间的 向后兼容 ,亦或者是为了向API添加接口。

次版本号的变更意味着新增了一系列的新功能。这通常宝货向头文件中增加新街口,或者包括行为变更、bug修复。 在次版本中可能淘汰一些功能,但并不会移除。 当引入了一个新的此版本后,补丁版本号被重置为0,每一个次版本都维护自己的补丁版本。 次版本的变更不应该影响后向兼容,但是会影响全兼容性。

主版本的变更意味着API的重大变化,可能包括新功能和头文件接口,行为变更,已淘汰特性的移除, 修改或者公开替换任何特性,极有可能破坏兼容性。 主版本变更通常导致已有的应用程序需进行明显的修改才能正常工作。

操纵版本号数字的C语言宏在附录 Version Number Macros 中定义。

2.10. 常见对象类型

这里列举了在很多不同的数据结构和命令参数中使用的Vulkan对象。这些类型包括 offsetsextents, 和 rectangles

2.10.1. Offsets

Offset 用来描述图像或者帧缓冲区的某个像素的位置,在二维图像中是(x,y),在三维图像中是(x,y,z)。

下列数据结构定义了二维Offset:

typedef struct VkOffset2D {    int32_t    x;    int32_t    y;} VkOffset2D;

下列数据结构定义了三维Offset:

typedef struct VkOffset3D {    int32_t    x;    int32_t    y;    int32_t    z;} VkOffset3D;

2.10.2. Extents

Extends被用来描述图像或者帧缓冲区内矩形区域的大小,对于二维图像是(width,height),对于三维图像是(width,height,depth)。

下列数据结构定义了二维extent:

typedef struct VkExtent2D {    uint32_t    width;    uint32_t    height;} VkExtent2D;

下列数据结构定义了三维extent:

typedef struct VkExtent3D {    uint32_t    width;    uint32_t    height;    uint32_t    depth;} VkExtent3D;

2.10.3. Rectangles

Rectangles被用来描述图像或者帧缓冲区内某个矩形区域内的像素。 Rectangles 包含一个offset和一个 extend,二者是同一个维度。

下列数据结构定义了二维rectangles:

typedef struct VkRect2D {    VkOffset2D    offset;    VkExtent2D    extent;} VkRect2D;