Vulkan 程序中实现调试

Vulkan 程序中实现调试,当我们通过验证层启用了调试功能之后,与之相关的调试功能核心代码实现都可以在用户类VulkanLayerAndExtension中找到(VulkanLED.h/.cpp)。本文我们会学习使用其中的代码来实现Vulkan的调试过程。

Vulkan的调试功能并不属于默认核心功能的一部分。因此,我们需要首先添加必需的扩展和层,从而启用调试功能,并且通过回调来获取报告。

  • 扩展:在实例级上添加VK_EXT_DEBUG_REPORT_EXTENSION_NAME扩展。这样我们就可以在应用程序中使用Vulkan调试相关的API了,具体如下:

Vulkan 程序中实现调试

  • :在实例级定义下列层类型,从而启用相应的调试功能:

Vulkan 程序中实现调试

除了启用上述层之外,LunarG SDK还提供了一个特殊的层,即VK_LAYER_LUNARG_standard_validation。它按照正确的顺序依次启用一些基础的验证功能。同时,这个内置的元数据层还会按照最佳顺序加载一组标准的验证层。如果读者对于层的概念还不是非常了解,那么直接使用这个功能也是一种不错的选择。

  • VK_LAYER_GOOGLE_threading
  • VK_LAYER_LUNARG_parameter_validation
  • VK_LAYER_LUNARG_object_tracker
  • VK_LAYER_LUNARG_image
  • VK_LAYER_LUNARG_core_validation
  • VK_LAYER_LUNARG_swapchain
  • VK_LAYER_GOOGLE_unique_objects

执行启用操作

这些层的信息会被传递给API函数vkCreateinstance()来执行启用操作:
Vulkan 程序中实现调试

验证层的种类与供应商以及SDK版本都是有直接关系的。因此,我们建议首先检查当前底层系统所支持的层的类型,然后再调用vkCreateinstance()函数和传入参数。这样应用程序就可以确保自身的可移植性,当它在其他的底层驱动上运行时也不会出现问题。

用户自定义的工具函数areLayersSupported()可以用来判断给定的层名称是否是当前系统所支持的。应用程序会自动识别出无法支持的层,将它们从列表中去除,然后再传递给系统去执行:
Vulkan 程序中实现调试

Vulkan 程序中实现调试

调试报告是通过API函数vkCreateDebugReportCallbackEXT创建的。这个函数并不属于Vulkan核心指令的一部分,因此没有办法通过加载器直接静态加载。如果读者直接通过如下习惯的方式去访问它,可能会收到一个“未定义符号”的错误提示:

vkCreateDebugReportCallbackEXT(instance, NULL, NULL. NULL);

所有这些调试相关的API都需要先通过vkGetInstanceProcAddr()进行查询并动态链接。获取后的函数被存储到一个对应的函数指针当中,即PFN vkCreateDebugReport-CallbackEXT。函数VulkanLayerAndExtension::createDebugReportCallback()负责获取创建和销毁调试报告的API函数,如下面的代码所示:
Vulkan 程序中实现调试
Vulkan 程序中实现调试

函数vkGetInstanceProcAddr()负责动态获取实例级别扩展,这些扩展没有办法静态链接到系统中,因此只能通过这种方法动态链接。以下给出了这个函数的声明:
Vulkan 程序中实现调试

API的参数说明如表所示:
Vulkan 程序中实现调试

创建调试报告对象

我们通过函数指针dbgCreateDebugReportCallback()创建了一个调试报告对象,并且将它的句柄保存到debugReportCallback当中。这个函数的第二个参数需要输入一个结构体VkDebugReportCallbackCreateInfoEXT。这个结构体定义了调试的具体行为模式,例如调试信息的内容:错误、常规警告、信息、性能相关的警告、调试信息,等等。另外,它还引用了一个用户自定义的函数(debugFunction)。这样我们就可以在系统获取了数据之后直接将它们过滤并打印输出。以下给出了调试报告结构体的具体语法:
Vulkan 程序中实现调试

这个函数的具体参数说明如表所示:
Vulkan 程序中实现调试

结构体VkDebugReportFlagBitsEXT可以定义一个按位整合的标识变量,它的值里可以包括如下标识,如表所示:
Vulkan 程序中实现调试

函数createDebugReportCallback实现了调试报告的创建过程。首先,它建立了一个VulkanLayerAndExtension结构体,并且设置了必要的参数。这里主要包括两个步骤:一,设置一个用户定义的回调函数(pfnCallback)用来打印系统中返回的调试信息(参见下面的部分);二,根据程序开发者的需要,设置调试标识量(flags):
Vulkan 程序中实现调试

Vulkan 程序中实现调试

打印调试信息

这里定义的debugFunction()函数负责将收到的调试信息通过一种用户友好的方式打印输出。它的输入参数包括调试信息的类型,以及显示的内容:
Vulkan 程序中实现调试

debugFunction()回调函数的各个参数的意义如表所示:
Vulkan 程序中实现调试

回调函数debugFunction的返回值为Boolean。如果返回true,那么继续执行指令链后续的验证,无论当前是否已经检查到错误。

但是如果返回值是false,那么验证层将在遇到错误时中止执行。我们建议程序中一旦遇到了错误,就立即中止后续的执行。

错误的发生意味着产生了一些预期之外的结果。因此系统在此状况下继续运行可能会导致一些不可预测的结果,或者更多的错误(而后续的大量错误提示有可能难以被用户所理解)。对于后一种情况来说,让系统执行立即中止可以帮助开发者更有效率地检查和修复当前的问题。而对于前一种情况来说,一旦系统突然抛出了一系列的错误,开发者可能会因此感到迷惑,难以入手。

为了确保vkCreateInstance执行的时候就已经开启了调试功能,我们将dbgReport-Createinfo设置给VkInstanceCreateInfo结构体的参数pNext:
Vulkan 程序中实现调试

销毁调试回调对象

最后,如果我们已经完成了调试操作,需要销毁调试回调对象:
Vulkan 程序中实现调试

生成调试报告

下图给出了调试报告的输出画面。读者的输出内容可能和图中并不相同,这可能是因为不同的GPU供应商和SDK供应商。此外,有关错误和警告报告的解释内容,也是和SDK自身直接相关的。不过从更高的层面上来说,它们都是基于同样的标准,也就是说,只要你开启了对应的调试标识量,你就会看到相应的调试报告信息,包括警告、信息、调试帮助文字,等等。
Vulkan 程序中实现调试

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!