作者:solovyev,文章出处:ARM Mali Graphics,发表时间:2016 年 7 月 6 日 11:01:00
为何使用验证层?
与 OpenGL 不同,Vulkan 驱动程序没有全局上下文,不维护全局状态,也不必验证来自应用程序端的输入。其目的是减少驱动程序的 CPU 占用,并在引擎实现中为应用程序提供更多自由。这种方法是可行的,因为好的应用程序或游戏不应在发行模式中为驱动程序提供错误的输入,这样会使驱动程序通常执行的所有内部检查都是在浪费 CPU 时间。但是,在开发/调试阶段,无效输入检测机制是有用、强大的工具,可大大简化开发人员的工作。作为 Vulkan 驱动程序中的新功能,所有输入验证都已移入一个称为验证层的独立模块中。在调试或准备要发布的图形应用程序时,运行验证层能够很好地保证应用程序没有明显错误。尽管“干净”的验证层不一定能保证应用程序无 Bug,这也是一大进步,有助于为客户提供愉快的体验。验证层是 Khronos 社区的开源项目,欢迎所有人参与或提出问题:https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues
我的应用程序在此设备上运行正常。我可以交付了吗?
不,还不行!Vulkan 规范是由多个供应商确定的,在 Vulkan API 所提供功能的列表中,有些功能可能适用于供应商 A,但与供应商 B 无关。对于无法通过应用程序直接观测的 Vulkan 操作,如布局转换、执行内存屏障等,这尤其重要。应用程序需要正确管理资源,您无法知道给定设备到底会发生什么情况,例如,在图像子资源中执行内存屏障时。实际上,这在很大程度上取决于内存体系结构和 GPU 的具体情况。从这个角度看,资源共享、布局转换、选择可视范围和转让资源所有权等领域的错误可能会在不同体系结构中产生不同结果。这一点很关键,供应商选择的实现选项可能不会造成此设备出现资源管理不当,但应用程序可能无法在其他供应商支持的其他设备上运行。
Mali 上的 Vulkan 驱动程序的常见应用程序问题。
外部资源所有权。
Vulkan 驱动程序将可显示图像等资源视为外部资源,这意味着它没有这些资源的所有权。驱动程序暂时获取对此类外部资源的锁定,以执行特定渲染操作或一系列渲染操作。操作完成后,将资源释放回系统。如果所有权更改为归驱动程序所有,外部资源必须进行映射并在 MMU 表中获取有效条目,以便在 GPU 中正确读取/写入。与资源相关的图形操作一完成,必须将资源释放回系统,所有 MMU 条目都失效。应用程序负责通过在渲染通道创建结构中或在执行管道屏障中提供相关信息来告知驱动程序,给定外部资源所有权将在哪个阶段更改。
示例:当预期驱动程序将使用可显示资源时,布局从 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR 转换为 VK_IMAGE_LAYOUT_GENERAL 或 VK_IMAGE_LAYOUT_COLOR{DEPTH_STENCIL}_ATTACHMENT_OPTIMAL。当附件完成渲染准备显示在显示屏上时,布局需要转换回 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR。
错误使用同步
Vulkan 对象生命周期是 Vulkan 应用程序的另一个重要问题。应用程序必须确保,Vulkan 对象或它们来自的池仅当不再使用时才能销毁或重置。错误管理对象生命周期的结果是无法预测的。最可能出现的问题是 MMU 错误,这会导致渲染问题和设备丢失。验证层可以捕获和报告大多数这种情况,例如,当从命令池中分配的命令缓冲区仍在使用时,应用程序试图重置该命令池;验证层应截获此操作并显示以下报告:
[DS] Code 54: Attempt to reset command pool with command buffer (0xXXXXXXXX)which is in use
另一个示例。当应用程序尝试将命令记录到仍在使用的命令缓冲区时,验证层应截获此操作并显示以下报告:
[MEM] Code 9: Calling vkBeginCommandBuffer() on active CB 0xXXXXXXXX before it has completed.
You must check CB fence before this call.
内存要求冲突。
Vulkan 应用程序负责通过适当调用 vkBindBufferMemory 或 vkBindImageMemory 提供内存后备图像或缓冲区对象。应用程序不能为对象假设适当的内存要求,举例来说,即使是用 VK_IMAGE_TILING_LINEAR 平铺创建的 vkImage 对象也不可以,原因是无法保证内存连续。必须根据 vkGetImageMemoryRequirements 或 vkGetBufferMemoryRequirements 的 size 和 alignment 返回值完成分配。然后,必须根据子资源布局值(如到子资源起始处的偏移量、大小、行/数组/深度值)向子资源上载数据。违反 Vulkan 对象的内存要求通常会导致 GPU 中出现分段错误或 MMU 错误,最终导致 VK_ERROR_DEVICE_LOST。建议运行验证层进行保护,以免出现这类问题。尽管验证层可以检测到内存溢出、交叉对象内存别名、映射/取消映射问题,验证层目前还无法检测绑定内存不足的问题。