Vulkan 设计指南

Vulkan 与旧版图形 API 的不同之处在于,驱动程序不会为应用执行特定的优化(例如流水线再利用)。相反,使用 Vulkan 的应用必须自行实现这类优化。否则,这些应用可能会展现出比运行 OpenGL ES 的应用更差的性能。

在应用自行实现这些优化时,它们可能比驱动程序做得更成功,因为它们可以访问指定用例的更多特定信息。因此,使用 Vulkan 的应用经过巧妙的优化后,可能会比使用 OpenGL ES 的应用具有更高的性能。

本页介绍了您的 Android 应用为了通过 Vulkan 实现性能提升可以实现的多项优化。

硬件加速

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

性能关键型应用应避免使用软件模拟的 Vulkan 实现,而应改为使用 OpenGL ES。

渲染时应用屏幕旋转

如果应用的向上方向与设备屏幕的方向不符,合成器将旋转应用的交换链图像,以使这两种方向一致。合成器会在显示图像时执行此旋转操作,而这会导致能耗增加,有时能耗会显著高于不旋转图像的情况。

相比之下,如果一边生成交换链图像一边进行旋转,即便会导致能耗增加,增幅也十分有限。VkSurfaceCapabilitiesKHR::currentTransform 字段会指示合成器向窗口应用的旋转效果。当应用在渲染过程中应用该旋转效果后,应用会使用 VkSwapchainCreateInfoKHR::preTransform 字段报告旋转完成。

最大程度减少每个帧的渲染通道

在大多数移动 GPU 架构中,开始和结束渲染通道是既耗时又耗电的操作。通过将渲染操作控制在尽可能少的渲染通道中,可以提升您的应用性能。

不同的附件加载和附件存储操作会实现不同级别的性能。例如,如果您不需要保留附件的内容,可以使用更快的 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 的系统上大,独立 GPU 拥有自己专属的内存。应用不应假设此属性为必要属性。

按频率将描述符组分组

如果您拥有以不同频率变化的资源绑定,请为每个流水线使用多个描述符组,而不是为每个绘图重新绑定所有资源。例如,您可以为“按场景”绑定使用一组描述符,为“按材料”绑定使用另一组描述符,为“按网格实例”绑定使用第三组描述符。

为最高频率的变更(例如使用每个绘制调用执行的变更)使用立即常数。