从 RenderScript 迁移

从 Android 12 开始,RenderScript API 已被弃用。它们将继续正常运行,但我们预计设备和组件制造商会逐渐停止提供硬件加速支持。为充分利用 GPU 加速功能,我们建议将脚本迁移到 Vulkan,或使用我们的替换工具包弃用内建函数

从内建函数迁移

尽管 RenderScript 内建函数在 RenderScript 弃用后将继续正常运行,但它们只能针对 CPU(而非 GPU)执行。

如果您的应用使用了内建函数,您就可以使用独立的替换库;我们的测试表明,其速度比使用现有 RenderScript CPU 实现更快。

该工具包包含以下函数:

  • 混合函数 (blend)
  • 模糊处理函数 (blur)
  • 颜色矩阵函数 (colorMatrix)
  • 卷积函数 (convolve)
  • 直方图函数 (histogram) 和 histogramDot
  • 对照表函数 (lut) 和 lut3d
  • 大小调整函数 (resize)
  • 将 YUV 转换为 RGB 的函数 (yuvToRgb)

如需了解完整详情和限制条件,请参阅该工具包的 README.mdToolkit.kt 文件。

如需下载、添加和使用该库,请执行以下步骤:

  1. 从 GitHub 下载相应项目

  2. 找到并构建 renderscript-toolkit module

  3. 通过修改应用的 build.gradle 文件,将该库添加到您的 Android Studio 项目中。

  4. 调用该工具包的相应方法。

示例:从 ScriptIntrinsicBlur 函数迁移

如需替换 ScriptIntrinsicBlur 函数,请执行以下操作:

  • 如需对位图进行模糊处理,请调用 Toolkit.blur

    var blurredBitmap = Toolkit.blur(myBitmap, radius)
    
  • 如果您需要对由字节数组表示的图片进行模糊处理,请指定宽度、高度和每像素字节数。

    val outArray = Toolkit.blur(inputArray, bytesPerPixel, width, height, radius)
    

如果以 Android 12(API 级别 31)及更高版本为目标平台,请考虑使用 RenderEffect 类(而非 Toolkit.blur())。

从脚本迁移

为充分利用 GPU 加速功能,我们建议将 RenderScript 脚本迁移到跨平台 Vulkan API。即使您不迁移,脚本也会继续运行,但这些脚本可能会针对 CPU(而非 GPU)执行,具体取决于驱动程序是否可用。

为了更好地了解如何迁移功能,请查看示例应用。该示例演示了如何使用 RenderScript 对位图进行模糊处理并执行颜色矩阵转换,以及如何使用 Vulkan 编写等效的代码。

如果您的应用需要支持一系列版本,请为搭载 Android 9(API 级别 28)及更低版本的设备使用 RenderScript,为 Android 10(API 级别 29)及更高版本使用 Vulkan。

Vulkan 不提供 Kotlin API 和 Java API,因此不存在从 RenderScript 到 Vulkan 的直接映射。如需通过 Kotlin 或 Java 访问此代码,您需要使用 NDK 编写 Vulkan 代码,并创建 JNI 函数。

以下几部分介绍了从 RenderScript 迁移的各个方面。示例应用几乎涵盖了上述所有考虑因素。为了更好地理解这些因素,请对比以下 RenderScript 和 Vulkan 等效代码。

初始化

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

  1. 创建一个 Vulkan 实例。

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

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

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

示例应用演示了如何在 VulkanContext.h 中初始化 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 规范中的资源创建资源描述符部分。

脚本

您的 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 规范中的命令缓冲区内存屏障部分。