Vulkan 设计指南

Vulkan 不同于早期的图形 API,其驱动程序不会为应用执行某些优化,例如管线重用。相反,使用 Vulkan 的应用必须自行实现这些优化。如果未实现,其性能可能会比运行 OpenGL ES 的应用更差。

当应用自行实现这些优化时,由于可以访问特定用例的更详细信息,它们比驱动程序更有可能成功实现优化。因此,熟练优化使用 Vulkan 的应用可以带来比使用 OpenGL ES 更好的性能。

本页介绍了几种您的 Android 应用可以实施的优化措施,以从 Vulkan 获得性能提升。

硬件加速

大多数设备通过硬件加速支持 Vulkan 1.1,而一小部分设备通过软件模拟支持。应用可以使用 vkGetPhysicalDeviceProperties 检测基于软件的 Vulkan 设备,并检查返回结构的 deviceType 字段。SwiftShader 和其他基于 CPU 的实现具有值 VK_PHYSICAL_DEVICE_TYPE_CPU。应用可以通过检查此同一结构的 vendorIDdeviceID 字段中是否存在 SwiftShader 特定的值来专门检查 SwiftShader。

对性能要求严苛的应用应避免使用软件模拟的 Vulkan 实现,而应回退到 OpenGL ES。

在渲染时应用显示旋转

当应用向上方向与设备显示屏方向不匹配时,合成器会旋转应用的交换链图片,使其匹配。它在显示图片时执行此旋转操作,这会导致比不旋转时更高的功耗(有时会显著更高)。

相比之下,在生成交换链图片时旋转,只会产生很少(甚至没有)额外的功耗。VkSurfaceCapabilitiesKHR::currentTransform 字段指示合成器对窗口应用的旋转。应用在渲染时应用该旋转后,会使用 VkSwapchainCreateInfoKHR::preTransform 字段报告旋转已完成。

最小化每帧的渲染通道

在大多数移动 GPU 架构上,开始和结束一个渲染通道是一项开销很大的操作。您的应用可以通过将渲染操作组织到尽可能少的渲染通道中来提高性能。

不同的 attachment-load 和 attachment-store 操作提供不同级别的性能。例如,如果您不需要保留附件的内容,您可以使用速度更快的 VK_ATTACHMENT_LOAD_OP_CLEARVK_ATTACHMENT_LOAD_OP_DONT_CARE,而不是 VK_ATTACHMENT_LOAD_OP_LOAD。同样,如果您不需要将附件的最终值写入内存以便将来使用,您可以使用 VK_ATTACHMENT_STORE_OP_DONT_CARE,获得比 VK_ATTACHMENT_STORE_OP_STORE 好得多的性能。

此外,在大多数渲染通道中,您的应用不需要加载或存储深度/模板附件。在这种情况下,您可以在创建附件图片时使用 VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT 标志,避免为附件分配物理内存。此位提供的优势与 OpenGL ES 中的 glFramebufferDiscard 相同。

选择合适的内存类型

分配设备内存时,应用必须选择内存类型。内存类型决定了应用如何使用内存,并描述了内存的缓存和一致性属性。不同的设备提供不同的内存类型;不同的内存类型表现出不同的性能特征。

应用可以使用简单的算法为特定用途选择最佳内存类型。此算法选择 VkPhysicalDeviceMemoryProperties::memoryTypes 数组中满足两个条件的第一个内存类型:内存类型必须允许用于缓冲区或图片,并且必须具备应用所需的最低属性。

移动系统通常没有独立的 CPU 和 GPU 物理内存堆。在此类系统上,VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT 的重要性不如在具有独立 GPU 及其专用内存的系统上重要。应用不应假定此属性是必需的。

按使用频率对描述符集进行分组

如果您的资源绑定以不同频率发生变化,每个管线使用多个描述符集,而不是为每次绘制重新绑定所有资源。例如,您可以有一个用于场景绑定的描述符集,另一个用于材质绑定的描述符集,以及第三个用于网格实例绑定的描述符集。

对于最高频率的变化,例如每次绘制调用时执行的变化,使用立即常量。