将脚本迁移到 Vulkan

对于 GPU 计算非常理想的工作负载,将 RenderScript 脚本迁移到 Vulkan 计算可以让您的应用更直接地控制 GPU 硬件,与其他 API 相比,可能会释放额外的性能。

以下是一个高级概述,可帮助您使用 Vulkan 计算着色器替换 RenderScript 脚本。

Vulkan 初始化

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

  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) 编写,然后编译为 标准可移植中间表示-V (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 的代码),请在单个命令缓冲区中记录它们并使用内存屏障进行同步。

示例应用演示了两个计算任务

  • 色调旋转:一个使用单个计算着色器的简单计算任务。有关代码示例,请参阅 ImageProcessor::rotateHue
  • 模糊:一个更复杂的计算任务,依次执行两个计算着色器。有关代码示例,请参阅 ImageProcessor::blur

要了解有关命令缓冲区或内存屏障的更多信息,请参阅 Vulkan 规范中名为 命令缓冲区内存屏障 的部分。