在 Vulkan 应用程序中启用 AFBC

此示例的源代码可以在 Khronos Vulkan 示例 github 存储库中找到。

概述

AFBC (Arm 帧缓冲区压缩) 是 Arm Mali GPU 中发现的一种实时无损压缩算法,旨在应对不断增长的更高分辨率图形需求。此格式应用于要写入 GPU 的帧缓冲区。这项技术可以提供高达 50% 的带宽减少。

该示例旨在演示通过切换 AFBC 的开关可以节省的带宽,并显示外部带宽的实时图表。在这种情况下,我们将重点关注交换链图像。

Vulkan API 允许开发人员控制 VkSwapchainKHR 的创建和格式化方式。我们希望确保以正确的方式创建和格式化它,以便我们从中查询的后续 VkImage 可以适当地应用 AFBC。

请务必注意,从设备角度来看,要在 Vulkan 上启用 AFBC,您至少需要 r16p0 驱动程序版本和 Mali G-51 或更高版本。要查找您的 GPU 和驱动程序版本,请打开 调试窗口 或按照此文章中的步骤操作。

已在以下设备上测试:Samsung Galaxy S10、Huawei P30

启用 AFBC

AFBC 在功能上对应用程序是透明的,并且会在每个 VkImage 的基础上自动应用 (前提是您的设备和图像的各种属性通过了多项检查)。

驱动程序将检查应用程序的状态以及 VkImage 的属性,以确定是否启用 AFBC 或只是继续而不启用它。本节将详细介绍这些要求。

VkImage 要求

  • VkSampleCountFlagBits 必须为 VK_SAMPLE_COUNT_1_BIT

  • VkImageType 必须为 VK_IMAGE_TYPE_2D

  • VkImageTiling 必须为 VK_IMAGE_TILING_OPTIMAL

  • VkFormat 支持列表

除此之外,您的 VkImage 还需要遵守以下标志

  • VkImageUsageFlags 不得包含

    • VK_IMAGE_USAGE_STORAGE_BIT

    • VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT

    • (仅适用于驱动程序版本为 r16p0 的某些设备) VK_IMAGE_USAGE_TRANSFER_DST_BIT

  • VkImageCreateFlags 不得包含

    • VK_IMAGE_CREATE_ALIAS_BIT

    • VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT

AFBC 示例

该示例向用户展示了 Sponza,顶部有一个显示带宽的图表,底部有一个配置窗口。有一个来回振荡的摄像机,用于禁用任何针对相同帧的 GPU 优化。

配置本身很简单。有一个复选框 (标记为 “启用 AFBC”),当其值更改时将重新加载交换链。

Sponza AFBC off

这里,示例处于默认状态:AFBC 关闭。屏幕顶部有一个图表,显示外部写入带宽(从 L2_EXT_WRITE_BEATS 测量)。

它目前在交换链图像的 VkImageUsageFlags 中设置了 VK_IMAGE_USAGE_STORAGE_BIT 标志,导致驱动程序跳过对交换链图像应用 AFBC。

当我们启用复选框时,示例将重新加载具有正确用法标志的交换链,以使驱动程序启用 AFBC。

Sponza AFBC on

这是与之前相同的场景,只是现在启用了 AFBC。未设置 VK_IMAGE_USAGE_STORAGE_BIT 标志,并且交换链正在正确创建。

带宽已从 788.0 MiB/s 降至 528.6 MiB/s,这大约减少了 33%。

您还可以在 Streamline 中确认这些数字。以下是一些屏幕截图

Streamline AFBC Off Streamline AFBC On

格式支持

从 Mali-G77 开始的 GPU 支持每像素高达 32 位的格式,无论颜色通道排列或 sRBG 如何。

支持 AFBC 的早期版本仅支持格式的子集

格式

VK_FORMAT_R4G4B4A4_UNORM_PACK16

VK_FORMAT_B4G4R4A4_UNORM_PACK16

VK_FORMAT_R5G6B5_UNORM_PACK16

VK_FORMAT_R5G5B5A1_UNORM_PACK16

VK_FORMAT_B5G5R5A1_UNORM_PACK16

VK_FORMAT_A1R5G5B5_UNORM_PACK16

VK_FORMAT_B8G8R8_UNORM

VK_FORMAT_B8G8R8A8_UNORM

VK_FORMAT_B8G8R8A8_SRGB

VK_FORMAT_A8B8G8R8_UNORM

VK_FORMAT_A8B8G8R8_SRGB

VK_FORMAT_A8R8G8B8_SRGB

VK_FORMAT_B10G10R10A2_UNORM

VK_FORMAT_R4G4B4A4_UNORM

VK_FORMAT_R5G6B5_UNORM

VK_FORMAT_R5G5B5A1_UNORM

VK_FORMAT_R8_UNORM

VK_FORMAT_R8G8_UNORM

VK_FORMAT_R8G8B8_UNORM

VK_FORMAT_R8G8B8A8_UNORM

VK_FORMAT_R8G8B8A8_SRGB

VK_FORMAT_A8R8G8B8_UNORM

VK_FORMAT_R10G10B10A2_UNORM

VK_FORMAT_D24_UNORM_S8_UINT

VK_FORMAT_D16_UNORM

VK_FORMAT_D32_SFLOAT

延伸阅读

最佳实践总结

执行

  • 确保按照 AFBC 的要求正确创建交换链。

  • AFBC 不能替代(它独立于)纹理压缩(如 ASTC),因此请尽可能压缩所有内容。

  • 避免在运行时更改图像配置(使用具有无效 AFBC 要求的 vkCmdCopyImage),因为它会触发解压缩。

  • 在多重采样时,请确保使用 pResolveAttachments 解析图像。任何 SAMPLE_COUNT > 1VkImage 都不会应用 AFBC。

不要

  • 除非您确实需要(例如,在特定图像上进行计算),否则请勿使用图像用法标志,例如 VK_IMAGE_USAGE_STORAGE_BIT

影响

  • 图像的配置不正确会导致所有表面 VkImage 变为未压缩状态,从而损失大量系统范围的带宽减少。

调试

  • 要测试是否启用或禁用 AFBC,您可以使用诸如 Streamline 之类的分析器,并在启用 AFBC 或禁用 AFBC 时记录带宽值。

  • 您还可以使用扩展 VK_EXT_image_compression_control 来查询是否启用了 AFBC。有关更多详细信息,请参阅图像压缩控制示例