将脚本迁移到 Vulkan

对于非常适合使用 GPU 计算的工作负载,将 RenderScript 脚本迁移到 Vulkan 计算,有助于应用更直接地控制 GPU 硬件,从而有望释放比其他 API 更多的性能。

下面简要介绍了相关内容,旨在帮助您使用 Vulkan 计算着色器替换 RenderScript 脚本。

Vulkan 初始化

通过执行以下步骤,使用 NDK 创建 Vulkan 上下文,而不要使用 Kotlin 或 Java 创建 RenderScript 上下文对象。

  1. 创建一个 Vulkan 实例。

  2. 选择支持计算队列的 Vulkan 实体设备。

  3. 创建一个 Vulkan 逻辑设备并获取计算队列。

(可选)您可以在 Android 上设置 Vulkan 验证层,以加速 Vulkan 应用开发。

示例应用演示了如何在 VulkanContext.h 中初始化 Vulkan 上下文。如需了解详情,请参阅 Vulkan 规范中的初始化以及设备和队列部分。

Vulkan 分配

RenderScript 分配可以迁移到 Vulkan 存储映像Vulkan 存储缓冲区。为了提升只读图片的性能,请通过提取操作使用示例图片,要么将其用作组合图片采样器,要么将其与独特的采样器采样图片绑定结合使用。

Vulkan 资源在 Vulkan 中分配。为避免在与其他 Android 组件交互时产生内存复制开销,请考虑使用 VK_ANDROID_external_memory_android_hardware_buffer 扩展程序将 Android AHardwareBuffer 导入到 Vulkan 中。此扩展程序适用于所有支持 Vulkan 1.1 的 Android 设备。如需了解详情,请参阅 FEATURE_VULKAN_HARDWARE_VERSION

示例应用演示了如何在 VulkanResources.h 中创建 Vulkan 资源。如需了解详情,请参阅 Vulkan 规范中的资源创建资源描述符部分。

转换为 Vulkan 计算着色器

您的 RenderScript 脚本必须转换为 Vulkan 计算着色器。您可能还需要根据 RenderScript 全局变量的用法调整代码。

编写 Vulkan 计算着色器

Vulkan 计算着色器通常采用 OpenGL 着色语言 (GLSL) 编写,然后编译为标准便携式中间表示 (SPIR-V) 格式。

如需详细了解如何将着色器集成到您的应用中,请参阅 Android 上的 Vulkan 着色器编译器

调整脚本全局变量

根据脚本全局变量的特性,我们建议对未在着色器中修改的全局变量使用特化常量、推送常量或统一缓冲区对象:

  • 特化常量:建议用于在不同内核调用中基本一致的脚本全局变量。更改特化常量的值需要重新创建计算流水线。
  • 推送常量:建议用于频繁更改且小于 maxPushConstantsSize(保证的最低大小:128 字节)的脚本全局变量。
  • 统一缓冲区:建议用于频繁更改且大于推送常量上限的脚本全局变量。

对于着色器中发生变化的全局变量,您可以使用 Vulkan 存储映像Vulkan 存储缓冲区

计算

您需要创建 Vulkan 计算流水线,目的是让 GPU 执行计算着色器。

创建 Vulkan 计算流水线

示例应用中的 ComputePipeline.h 文件演示了如何创建 Vulkan 计算流水线。

如需在 Vulkan 中使用已编译的 SPIR-V 着色器,请按如下步骤构建 Vulkan 计算流水线:

  1. 使用已编译的 SPIR-V 着色器创建一个着色器模块。
  2. 创建一个用于指定资源绑定的描述符集布局(如需了解详情,请参阅分配)。
  3. 通过描述符集布局创建描述符集。
  4. 通过描述符集布局创建流水线布局。
  5. 使用着色器模块和流水线布局创建计算流水线。

如需了解详情,请参阅 Vulkan 规范中的计算流水线部分。

启动计算

如需使用计算流水线启动计算,请执行以下操作:

  1. 使用 Vulkan 资源更新描述符集。
  2. 创建一个 Vulkan 命令缓冲区,并记录以下命令:
    1. 绑定流水线和描述符集。
    2. 分派计算工作组。
  3. 将命令缓冲区提交到计算队列。
  4. 在队列中等待,也可以选择性地返回同步栅栏。

如需将多个内核链接在一起(例如,如需使用 ScriptGroup 迁移代码),请将它们记录在单个命令缓冲区中,并与内存屏障进行同步。

示例应用演示了两项计算任务:

  • HUE 旋转:一个具有单个计算着色器的简单计算任务。如需查看代码示例,请参阅 ImageProcessor::rotateHue
  • 模糊处理:一个按顺序执行两个计算着色器的更复杂的计算任务。如需查看代码示例,请参阅 ImageProcessor::blur

如需详细了解命令缓冲区或内存屏障,请参阅 Vulkan 规范中的命令缓冲区内存屏障部分。