validation layer介绍
validation layer称为验证层。用于校验Vulkan API输入是否有效。
有效输入
有效输入(Valid Usage,简称为VU),在Vulkan Spec中定义为:
为了使应用出现明确定义的行为而必须满足的前提条件。
作为一种显式调用的 API,Vulkan 的主要特点之一是驱动程序不会在检查有效输入上浪费时间。而在 OpenGL 中,驱动程序必须检查输入是否有效,这会增加很多额外开销。Vulkan 中没有等效的 glGetError实现。
vulkan spec在每个函数和结构之后列出了有效性输入。例如,如果检测出VkBindImageMemory
中使用了无效的 vkImage
,那么validation layer会识别出一个VUID,在VkBindImageMemory
下有该VUID的说明。
未定义的行为
当应用程序有无效输入时,结果将是未定义行为。在这种状态下,Vulkan 不保证任何未定义行为的结果。
有效输入 ID (VUID)
VUID是每个有效性输入的唯一 ID。根据VUID将很容易地在spec中找到有效性输入的说明。
举个例子,VUID-vkBindImageMemory-memoryOffset-01046
)只需将 VUID 在spec html中添加锚点 (vkspec.html#VUID-vkBindImageMemory-memoryOffset-01046),就会直接跳转到该 VUID。
Khronos validation layer
由于 Vulkan 不执行任何错误检查,因此在开发调试时,启用验证层来辅助定位无效行为是非常重要的。
获取validation layer
验证层在不断的更新和改进,因此可以下载最新的源代码自己构建。也可以下载平台预编译好的版本:
- Android - 二进制文件在 GitHub 上 发布。NDK 也附带了验证层,参考Android使用说明。
- Linux - Vulkan SDK附带了验证层,参考 Linux使用说明 。
- MacOS - Vulkan SDK 附带了验证层,参考 MacOS使用说明 。
- Windows - Vulkan SDK附带了验证层,参考 Windows使用说明 。
分析验证错误消息
验证层会在发生错误时提供尽可能多的信息。以下示例说明了如何解读验证层信息
示例 1 - 隐式的有效输入校验
下面的信息表明触发了隐式有效输入,VUID 末尾没有数字。
Validation Error: [ VUID-vkBindBufferMemory-memory-parameter ] Object 0: handle =
0x20c8650, type = VK_OBJECT_TYPE_INSTANCE; | MessageID = 0xe9199965 | Invalid
VkDeviceMemory Object 0x60000000006. The Vulkan spec states: memory must be a valid
VkDeviceMemory handle (https://registry.khronos.org/vulkan/specs/1.1-extensions/
html/vkspec.html#VUID-vkBindBufferMemory-memory-parameter)
- VUID 在消息一开始处展现(
VUID-vkBindBufferMemory-memory-parameter
),在消息末尾还有VUID在spec中的链接 The Vulkan spec states
:是从spec引用的VUID。VK_OBJECT_TYPE_INSTANCE
:指的是 VkObjectType。Invalid VkDeviceMemory Object 0x60000000006
:是 Dispatchable Handle,用来定位哪个VkDeviceMemory
句柄导致的错误。
示例 2 - 显式的有效输入校验
下面的错误信息表明VkImage
对象尝试绑定到 2 个不同的对象VkDeviceMemory
对象
Validation Error: [ VUID-vkBindImageMemory-image-01044 ] Object 0: handle =
0x90000000009, name = myTextureMemory, type = VK_OBJECT_TYPE_DEVICE_MEMORY; Object 1:
handle = 0x70000000007, type = VK_OBJECT_TYPE_IMAGE; Object 2: handle = 0x90000000006,
name = myIconMemory, type = VK_OBJECT_TYPE_DEVICE_MEMORY; | MessageID = 0x6f3eac96 |
In vkBindImageMemory(), attempting to bind VkDeviceMemory 0x90000000009[myTextureMemory]
to VkImage 0x70000000007[] which has already been bound to VkDeviceMemory
0x90000000006[myIconMemory]. The Vulkan spec states: image must not already be
backed by a memory object (https://registry.khronos.org/vulkan/specs/1.1-extensions/
html/vkspec.html#VUID-vkBindImageMemory-image-01044)
- 示例 2 与示例 1 大致相同,不同之处在于附加对象名称(
name = myTextureMemory
)。这是通过 VK_EXT_debug_util 扩展(扩展使用示例)来实现的。 - 此错误行为涉及 3 个对象
- 对象0:名称为
myTextureMemory
的VkDeviceMemory
- 对象1:没有名称的
VkImage
- 对象2:名称为
myIconMemory
的VkDeviceMemory
- 对象0:名称为
- 通过显示的名称,很容易看到:在
vkBindImageMemory()
中,内存myTextureMemory
尝试绑定到一个image
,但是该image
已绑定到内存myIconMemory
。
每条错误消息都包含一个固定的日志格式,格式如下:
- 日志状态(如
Error:
、Warning:
等) - VUID
- 涉及的对象数组
- 索引数组
- Dispatch Handle 值
- 可选名称
- 对象类型
- 出现错误的函数或结构
- Layer描述问题的消息
- spec中完整的有效输入说明
- 有效输入的链接