Vulkan 设计指南

Vulkan 与旧版图形 API 的不同之处在于,驱动程序不会为应用执行特定的优化,例如管道重用。 相反,使用 Vulkan 的应用必须自行实现此类优化。 如果不实现,这些应用可能会展现出比运行 OpenGL ES 的应用更差的性能。

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

本页面介绍您的 Android 应用可以实现的多个优化,以便从 Vulkan 获得性能提升。

渲染时应用屏幕旋转

当应用的向上方向与设备显示画面的方向不匹配时,编译器将旋转应用的交换链图像,使其匹配。 编译器在显示图像时执行此旋转,这会导致能耗增加。相比于不旋转图像,—有时能耗增幅显著—。

相反,边生成交换链图像边旋转,即便会导致能耗增加,增幅也十分有限。 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 拥有自己专用的内存。 应用不应假设此属性为必要属性。

按频率将描述符组分组

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

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