与之前的图形 API 不同,Vulkan 中驱动程序不会为应用执行某些优化,例如管道重用。使用 Vulkan 的应用必须自行实现此类优化。如果它们没有这样做,它们的性能可能会比运行 OpenGL ES 的应用更差。
当应用自行实现这些优化时,它们比驱动程序更有可能成功,因为它们可以访问给定用例的更具体信息。因此,巧妙地优化使用 Vulkan 的应用可以比使用 OpenGL ES 的应用获得更好的性能。
此页面介绍了您的 Android 应用可以实现的几种优化,以从 Vulkan 获得性能提升。
硬件加速
大多数设备通过硬件加速支持 Vulkan 1.1,而一小部分设备通过软件模拟支持它。应用可以使用vkGetPhysicalDeviceProperties
检测基于软件的 Vulkan 设备,并检查返回结构的deviceType
字段。SwiftShader和其他基于 CPU 的实现的值为VK_PHYSICAL_DEVICE_TYPE_CPU
。应用可以通过检查此同一结构的vendorID
和deviceID
字段中 SwiftShader 特定的值来专门检查 SwiftShader。
性能关键型应用应避免使用软件模拟的 Vulkan 实现,而应改用 OpenGL ES。
在渲染过程中应用显示旋转
当应用的向上方向与设备显示器的方向不匹配时,合成器会旋转应用的交换链图像以使其匹配。它在显示图像时执行此旋转,这会导致比不旋转它们时更高的功耗——有时会高得多。
相比之下,在生成交换链图像时旋转它们几乎不会产生额外的功耗。 VkSurfaceCapabilitiesKHR::currentTransform
字段指示合成器应用于窗口的旋转。应用在渲染过程中应用该旋转后,应用使用VkSwapchainCreateInfoKHR::preTransform
字段报告旋转已完成。
最小化每帧的渲染通道
在大多数移动 GPU 架构上,开始和结束渲染通道是一项代价高昂的操作。您的应用可以通过将渲染操作组织成尽可能少的渲染通道来提高性能。
不同的附件加载和附件存储操作提供不同的性能级别。例如,如果您不需要保留附件的内容,您可以使用速度快得多的VK_ATTACHMENT_LOAD_OP_CLEAR
或VK_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 及其专用内存的系统上那样重要。应用不应假设此属性是必需的。
按频率分组描述符集
如果您的资源绑定以不同的频率更改,请对每个管道使用多个描述符集,而不是为每次绘制重新绑定所有资源。例如,您可以为每个场景绑定设置一组描述符,为每个材质绑定设置另一组描述符,以及为每个网格实例绑定设置第三组描述符。
对于最高频率的更改(例如每次绘制调用执行的更改),请使用立即常量。