Renderscript 简介
本指南介绍了 Renderscript,并说明如何在面向 API 级别 17 或更高级别的 Xamarin.Android 应用程序中使用内部 Renderscript API。
概述
Renderscript 是 Google 创建的编程框架,目的在于提高需要大量计算资源的 Android 应用程序的性能。 它是基于 C99 的低级别、高性能 API。 由于它是将在 CPU、GPU 或 DSP 上运行的低级别 API,Renderscript 非常适合用于可能需要执行以下任一操作的 Android 应用:
- 图形
- 图像处理
- 加密
- 信号处理
- 数学例程
Renderscript 将使用 clang
,并将脚本编译为绑定到 APK 的 LLVM 字节代码。 首次运行应用时,LLVM 字节代码将编译为设备上处理器的机器代码。 此体系结构允许 Android 应用程序利用机器代码的优点,而无需开发人员为设备自身的每个处理器编写该代码。
Renderscript 例程有两个组件:
Renderscript 运行时 – 这是负责执行 Renderscript 的本机 API。 这包括为应用程序编写的任何 Renderscript。
Android Framework 中的托管包装器 – 托管类,使 Android 应用能够控制 Renderscript 运行时和脚本并与之交互。 除了框架提供的用于控制 Renderscript 运行时的类,Android 工具链还会检查 Renderscript 源代码,并生成托管包装类以供 Android 应用程序使用。
下图说明了这些组件之间的关系:
在 Android 应用程序中使用 Renderscripts 有三个重要概念:
上下文 – 由 Android SDK 提供的托管 API,它向 Renderscript 分配资源并允许 Android 应用从 Renderscript 传递和接收数据。
计算 内核 – 也称为 根内核 或 内核,这是一个执行工作的例程。 内核非常类似于 C 函数;它是一个可并行化例程,将在已分配内存中的所有数据上运行。
分配的内存 – 数据通过 分配传入和传出内核。 一个内核可以有一个输入和/或一个输出分配。
Android.Renderscripts 命名空间包含用于与 Renderscript 运行时进行交互的类。 特别是,Renderscript
类将管理 Renderscript 引擎的生命周期和资源。 Android 应用必须初始化一个或多个 Android.Renderscripts.Allocation
对象。 分配是一个托管 API,负责分配和访问在 Android 应用与 Renderscript 运行时之间共享的内存。 通常,为输入创建一个分配,并根据需要创建另一个分配来保存内核的输出。 Renderscript 运行时引擎和关联的托管包装类将管理对分配所持有的内存的访问,无需 Android 应用开发人员执行任何其他工作。
分配将包含一个或多个 Android.Renderscripts.Elements。 元素是一种专用类型,用于描述每个分配中的数据。 输出分配的元素类型必须匹配输入元素的类型。 在执行时,Renderscript 将并行遍历输入分配中的每个元素,并将结果写入输出分配。 有以下两种类型的元素:
简单类型 – 从概念上讲,这与 C 数据类型
float
或 .char
复杂类型 – 此类型 类似于 C
struct
。
Renderscript 引擎将执行一个运行时检查,以确保每个分配中的元素与内核所需的元素兼容。 如果分配中元素的数据类型与内核期望的数据类型不匹配,将引发异常。
所有 Renderscript 内核都将由 类的子代类型包装Android.Renderscripts.Script
类。 Script
类用于设置 Renderscript 参数,设置相应的 Allocations
,并运行 Renderscript。 Android SDK 中有两个 Script
子类:
Android.Renderscripts.ScriptIntrinsic
– 某些较常见的 Renderscript 任务捆绑在 Android SDK 中,可通过 ScriptIntrinsic 类的子类进行访问。 开发人员无需执行任何额外的步骤即可在应用中使用这些脚本,因为已经提供了这些脚本。ScriptC_XXXXX
– 也称为 用户脚本,这些脚本由开发人员编写,并打包在 APK 中。 在编译时,Android 工具链将生成托管包装类,以允许在 Android 应用中使用这些脚本。 这些生成的类的名称是 Renderscript 文件的名称,以ScriptC_
为前缀。 Xamarin.Android 并不正式支持编写和合并用户脚本,这些内容不在本指南范围内。
对于这两种类型,Xamarin.Android 仅支持 StringIntrinsic
。 本指南将讨论如何在 Xamarin.Android 应用程序中使用内部脚本。
要求
本指南适用于面向 API 级别 17 或更高级别的 Xamarin.Android 应用程序。 本指南不讨论用户脚本的使用。
Xamarin.Android V8 支持库支持面向旧版本 Android SDK 的应用的内部 Renderscript API。 如果将此包添加到 Xamarin.Android 项目,则应允许面向旧版本 Android SDK 的应用程序利用内部脚本。
在 Xamarin.Android 中使用内部 Renderscript
内部脚本是执行密集型计算任务的好方法,只需用到很少的额外代码。 已对其进行手动优化,以便在大量设备上提供最佳性能。 内部脚本的运行速度是托管代码的 10 倍,是自定义 C 实现的 2-3 倍,这种情况并不少见。 内部脚本涵盖了许多典型的处理场景。 此内部脚本列表介绍了 Xamarin.Android 中的当前脚本:
ScriptIntrinsic3DLUT – 使用 3D 查找表将 RGB 转换为 RGBA。
ScriptIntrinsicBLAS – 向 BLAS 提供高性能呈现脚本 API。 BLAS(基本线性代数子程序)是提供标准构建基块执行基本矢量和矩阵操作的例程。
ScriptIntrinsicBlend – 将两个分配混合在一起。
ScriptIntrinsicBlur – 将高斯模糊应用于分配。
ScriptIntrinsicColorMatrix – 将颜色矩阵应用于分配(即更改颜色、调整色调)。
ScriptIntrinsicConvolve3x3 – 将 3x3 颜色矩阵应用于分配。
ScriptIntrinsicConvolve5x5 – 将 5x5 颜色矩阵应用于分配。
ScriptIntrinsicHistogram – 内部直方图筛选器。
ScriptIntrinsicLUT – 将每通道查找表应用于缓冲区。
ScriptIntrinsicResize – 用于执行 2D 分配大小的脚本。
ScriptIntrinsicYuvToRGB – 将 YUV 缓冲区转换为 RGB。
有关每个内部脚本的详细信息,请参阅 API 文档。
下面介绍了在 Android 应用程序中使用 Renderscript 的基本步骤。
创建 Renderscript 上下文 – Renderscript
类是 Renderscript 上下文周围的托管包装器,用于控制初始化、资源管理和清理。 Renderscript 对象是使用 RenderScript.Create
工厂方法创建的,该方法采用 Android 上下文(例如活动)作为参数。 下面的代码行演示如何初始化 Renderscript 上下文:
Android.Renderscripts.RenderScript renderScript = RenderScript.Create(this);
创建分配 – 根据内部脚本,可能需要创建一两 Allocation
个分配。 此 Android.Renderscripts.Allocation
类具有多个工厂方法,可帮助实例化内部函数的分配。 作为一个示例,下面的代码片段演示了如何为位图创建分配。
Android.Graphics.Bitmap originalBitmap;
Android.Renderscripts.Allocation inputAllocation = Allocation.CreateFromBitmap(renderScript,
originalBitmap,
Allocation.MipmapControl.MipmapFull,
AllocationUsage.Script);
通常,需要创建 Allocation
来保存脚本的输出数据。 下面的代码片段展示了如何使用 Allocation.CreateTyped
helper 来实例化第二个与原始类型相同的 Allocation
:
Android.Renderscripts.Allocation outputAllocation = Allocation.CreateTyped(renderScript, inputAllocation.Type);
实例化脚本包装器 – 每个内部脚本包装器类都应具有帮助程序方法(通常调用 Create
)来实例化该脚本的包装器对象。 下面的代码片段演示了如何实例化 ScriptIntrinsicBlur
模糊对象。 Element.U8_4
helper 方法将创建一个元素来描述数据类型,该数据类型包含 4 个 8 位无符号整数值字段,适合保存 Bitmap
对象的数据:
Android.Renderscripts.ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.Create(renderScript, Element.U8_4(renderScript));
分配分配(s)、设置参数和运行脚本 – 类 Script
提供 ForEach
实际运行 Renderscript 的方法。 该方法将遍历 Allocation
中持有输入数据的每个 Element
。 在某些情况下,可能需要提供持有输出数据的 Allocation
。
ForEach
将重写输出分配的内容。 为了继续使用前面步骤中的代码片段,本示例展示了如何指定输入分配,设置参数,最后运行脚本(将结果复制到输出分配):
blurScript.SetInput(inputAllocation);
blurScript.SetRadius(25); // Set a pamaeter
blurScript.ForEach(outputAllocation);
你可能想要了解使用 Renderscript 对图像进行模糊处理的秘诀,它完整演示了如何在 Xamarin.Android 中使用内部脚本。
总结
本指南介绍了 Renderscript 以及如何在 Xamarin.Android 应用程序中使用它。 简要讨论了什么是 Renderscript,以及它在 Android 应用程序中的工作方式。 介绍了 Renderscript 中的一些关键组件,以及用户脚本和内部脚本的区别。 最后,本指南讨论了在 Xamarin.Android 应用程序中使用内部脚本的步骤。