Renderscript 简介An Introduction to Renderscript

本指南介绍了 Renderscript,并说明了如何在面向 API 级别17或更高版本的 Xamarin Android 应用程序中使用内部 Renderscript API。This guide introduces Renderscript and explains how to use the intrinsic Renderscript API's in a Xamarin.Android application that targets API level 17 or higher.

概述Overview

Renderscript 是 Google 创建的编程框架,目的在于提高需要大量计算资源的 Android 应用程序的性能。Renderscript is a programming framework created by Google for the purpose of improving the performance of Android applications that require extensive computational resources. 这是一个基于C99的低级别、高性能 API。It is a low level, high performance API based on C99. 由于它是将在 Cpu、Gpu 或 Dsp 上运行的低级别 API,Renderscript 非常适合用于可能需要执行以下任一操作的 Android 应用:Because it is a low level API that will run on CPUs, GPUs, or DSPs, Renderscript is well suited for Android apps that may need to perform any of the following:

  • 图形Graphics
  • 图像处理Image Processing
  • 加密Encryption
  • 信号处理Signal Processing
  • 数学例程Mathematical Routines

Renderscript 将使用 clang,并将脚本编译为绑定到 APK 的 LLVM 字节代码。Renderscript will use clang and compile the scripts to LLVM byte code which is bundled into the APK. 首次运行应用时,LLVM 字节代码将被编译为设备上的处理器的机器代码。When the app is run for the first time, the LLVM byte code will be compiled into machine code for the processors on the device. 此体系结构允许 Android 应用程序利用机器代码的优点,而开发人员无需为设备自身的每个处理器编写该代码。This architecture allows an Android application to exploit the advantages of machine code without the developers themselves having to write it for each processor on the device themselves.

Renderscript 例程有两个组件:There are two components to a Renderscript routine:

  1. Renderscript 运行时– 这是负责执行 Renderscript 的本机 api。The Renderscript runtime – This is the native APIs that are responsible for executing the Renderscript. 这包括为应用程序编写的任何 Renderscripts。This includes any Renderscripts written for the application.

  2. Android Framework 中的托管包装– 托管类,它们允许 Android 应用程序控制 Renderscript 运行时和脚本并与之交互。Managed Wrappers from the Android Framework – Managed classes that allow an Android app to control and interact with the Renderscript runtime and scripts. 除了 framework 提供的用于控制 Renderscript 运行时的类,Android 工具链还会检查 Renderscript 源代码,并生成托管包装器类以供 Android 应用程序使用。In addition to the framework provided classes for controlling the Renderscript runtime, the Android toolchain will examine the Renderscript source code and generate managed wrapper classes for use by the Android application.

下图说明了这些组件之间的关系:The following diagram illustrates how these components relate:

阐释 Android Framework 如何与 Renderscript 运行时进行交互的关系图

在 Android 应用程序中使用 Renderscripts 有三个重要概念:There are three important concepts for using Renderscripts in an Android application:

  1. 上下文– 由 Android SDK 提供的托管 API,该 API 将资源分配给 Renderscript,并允许 Android 应用程序通过 Renderscript 传递和接收数据。A context – A managed API provided by the Android SDK that allocates resources to Renderscript and allows the Android app to pass and receive data from the Renderscript.

  2. 计算内核 – 也称为_根内核_或_内核_,这是执行工作的例程。A compute kernel – Also known as the root kernel or kernel, this a routine that does the work. 内核非常类似于 C 函数;它是一个可并行化例程,将对分配的内存中的所有数据运行。The kernel is very similar to a C function; it is a parallelizable routine that will be run over all the data in allocated memory .

  3. 分配的内存– 通过 分配 将数据传入和向内核传入。Allocated Memory – Data is passed to and from a kernel through an Allocation. 一个内核可以有一个输入和/或一个输出分配。A kernel may have one input and/or one output Allocation.

Renderscripts命名空间包含用于与 Renderscript 运行时进行交互的类。The Android.Renderscripts namespace contains the classes for interacting with the Renderscript runtime. 具体而言, Renderscript类将管理 Renderscript 引擎的生命周期和资源。In particular, the Renderscript class will manage the lifecycle and resources of the Renderscript engine. Android 应用必须初始化一个或多个Android.Renderscripts.AllocationThe Android app must initialize one or more Android.Renderscripts.Allocation 对象.objects. 分配是一个托管 API,负责分配和访问 Android 应用与 Renderscript 运行时之间共享的内存。An Allocation is a managed API that is responsible for allocation and accessing the memory that is shared between the Android app and the Renderscript runtime. 通常,为输入创建一个分配,并根据需要创建另一个分配来保存内核的输出。Typically, one Allocation is created for input, and optionally another Allocation is created to hold the output of the kernel. Renderscript 运行时引擎和关联的托管包装器类将管理对分配所持有的内存的访问,无需 Android 应用开发人员执行任何额外的工作。The Renderscript runtime engine and the associated managed wrapper classes will manage access to the memory held by the Allocations, there is no need for an Android app developer to do any extra work.

分配将包含一个或多个RenderscriptsAn Allocation will contain one or more Android.Renderscripts.Elements. 元素是一种专用类型,用于描述每个分配中的数据。Elements are a specialized type that describe data in each Allocation. 输出分配的元素类型必须匹配输入元素的类型。The Element types of the output Allocation must match the types of the input Element. 执行时,Renderscript 将并行迭代输入分配中的每个元素,并将结果写入到输出分配。When executing, a Renderscript will iterate over each Element in the input Allocation in parallel, and write the results to the output Allocation. 有两种类型的元素:There are two types of Elements:

  • 简单类型– 从概念上讲,这与 C 数据类型相同,floatcharsimple type – Conceptually this is the same as a C data type, float or a char.

  • 此类型 –复杂类型类似于 C structcomplex type – This type is similar to a C struct.

Renderscript 引擎将执行运行时检查,以确保每个分配中的元素都与内核所需的元素兼容。The Renderscript engine will perform a runtime check to ensure that the Elements in each Allocation are compatible with what is required by the kernel. 如果分配中的元素的数据类型与内核期望的数据类型不匹配,则将引发异常。If the data type of the Elements in the Allocation do not match the data type that the kernel is expecting, an exception will be thrown.

所有 Renderscript 内核都将按作为Android.Renderscripts.Script子代的类型包装All Renderscript kernels will be wrapped by a type that is a descendant of the Android.Renderscripts.Script 类的新实例。class. Script 类用于设置 Renderscript 的参数、设置相应的 Allocations并运行 Renderscript。The Script class is used to set parameters for a Renderscript, set the appropriate Allocations, and run the Renderscript. Android SDK 有两个 Script 子类:There are two Script subclasses in the Android SDK:

  • Android.Renderscripts.ScriptIntrinsic – 在 Android SDK 中捆绑了一些更常见的 Renderscript 任务,这些任务可通过ScriptIntrinsic类的子类访问。Android.Renderscripts.ScriptIntrinsic – Some of the more common Renderscript tasks are bundled in the Android SDK and are accessible by a subclass of the ScriptIntrinsic class. 开发人员无需执行任何额外的步骤即可在应用程序中使用这些脚本,因为已提供这些脚本。There is no need for a developer take any extra steps to use these scripts in their application as they are already provided.

  • ScriptC_XXXXX – 也称为_用户脚本_,这些脚本是由开发人员编写并打包在 APK 中的脚本。ScriptC_XXXXX – Also known as user scripts, these are scripts that are written by developers and packaged in the APK. 在编译时,Android 工具链将生成托管包装器类,这些类将允许在 Android 应用中使用这些脚本。At compile time, the Android toolchain will generate managed wrapper classes that will allow the scripts to be used in the Android app. 这些生成的类的名称是 Renderscript 文件的名称,以 ScriptC_为前缀。The name of these generated classes is the name of the Renderscript file, prefixed with ScriptC_. Xamarin 和本指南的范围之外,不支持编写和并入用户脚本。Writing and incorporating user scripts is not officially supported by Xamarin.Android and beyond the scope of this guide.

对于这两种类型,Xamarin 仅支持 StringIntrinsicOf these two types, only the StringIntrinsic is supported by Xamarin.Android. 本指南将讨论如何在 Xamarin Android 应用程序中使用内部脚本。This guide will discuss how to use intrinsic scripts in a Xamarin.Android application.

要求Requirements

本指南适用于面向 API 级别17或更高版本的 Xamarin Android 应用程序。This guide is for Xamarin.Android applications that target API level 17 or higher. 本指南未介绍如何使用_用户脚本_。The use of user scripts is not covered in this guide.

Xamarin V8 支持库Precise-backports 内部 Renderscript API,适用于面向 Android SDK 的旧版本的应用程序。The Xamarin.Android V8 Support Library backports the instrinsic Renderscript API's for apps that target older versions of the Android SDK. 如果将此包添加到 Xamarin Android 项目,则应允许面向 Android SDK 较早版本的应用程序利用内部脚本。Adding this package to a Xamarin.Android project should allow apps that target older versions of the Android SDK to leverage the intrinsic scripts.

在 Xamarin 中使用内部 RenderscriptsUsing Intrinsic Renderscripts in Xamarin.Android

内部脚本是使用最少数量的附加代码执行密集型计算任务的好方法。The intrinsic scripts are a great way to perform intensive computing tasks with a minimal amount of additional code. 它们已经过优化,可以在大量设备上提供最佳性能。They have been hand tuned to offer optimal performance on a large cross section of devices. 与托管代码相比,内部脚本的运行速度快10倍,而在自定义 C 实现后,这种情况并不常见。It is not uncommon for an intrinsic script to run 10x faster than managed code and 2-3x times after than a custom C implementation. 内部脚本涵盖了许多典型处理方案。Many of the typical processing scenarios are covered by the intrinsic scripts. 此内部脚本列表描述了 Xamarin 中的当前脚本:This list of the intrinsic scripts describes the current scripts in Xamarin.Android:

有关每个内部脚本的详细信息,请参阅 API 文档。Please consult the API documentation for details on each of the intrinsic scripts.

下面介绍了如何在 Android 应用程序中使用 Renderscript 的基本步骤。The basic steps for using Renderscript in an Android application are described next.

Renderscript 创建 Renderscript 上下文Create a Renderscript Context – The Renderscript 类是围绕 Renderscript 上下文的托管包装,它将控制初始化、资源管理和清理。class is a managed wrapper around the Renderscript context and will control initialization, resource management, and clean up. Renderscript 对象是使用 RenderScript.Create 工厂方法创建的,该方法采用 Android 上下文(例如活动)作为参数。The Renderscript object is created using the RenderScript.Create factory method, which takes an Android Context (such as an Activity) as a parameter. 下面的代码行演示如何初始化 Renderscript 上下文:The following line of code demonstrates how to initialize the Renderscript context:

Android.Renderscripts.RenderScript renderScript = RenderScript.Create(this);

创建分配– 具体取决于内部脚本,可能需要创建一个或两个 AllocationCreate Allocations – Depending on the intrinsic script, it may be necessary to create one or two Allocations. Android.Renderscripts.AllocationThe Android.Renderscripts.Allocation 类具有多个工厂方法,可帮助为内部函数实例化分配。class has several factory methods to help with instantiating an allocation for an intrinsic. 例如,下面的代码段演示如何为位图创建分配。As an example, the following code snippet demonstrates how to create Allocation for Bitmaps.

Android.Graphics.Bitmap originalBitmap;
Android.Renderscripts.Allocation inputAllocation = Allocation.CreateFromBitmap(renderScript,
                                                     originalBitmap,
                                                     Allocation.MipmapControl.MipmapFull,
                                                     AllocationUsage.Script);

通常,需要创建一个 Allocation 来保存脚本的输出数据。Often, it will be necessary to create an Allocation to hold the output data of a script. 以下代码片段演示了如何使用 Allocation.CreateTyped 帮助器实例化与原始类型相同的第二个 AllocationThis following snippet shows how to use the Allocation.CreateTyped helper to instantiate a second Allocation that the same type as the original:

Android.Renderscripts.Allocation outputAllocation = Allocation.CreateTyped(renderScript, inputAllocation.Type);

实例化脚本包装– 每个内部脚本包装类应包含 helper 方法(通常称为 Create),以便为该脚本实例化包装对象。Instantiate the Script wrapper – Each of the intrinsic script wrapper classes should have helper methods (typically called Create)for instantiating a wrapper object for that script. 下面的代码片段举例说明了如何实例化 ScriptIntrinsicBlur 模糊对象。The following code snippet is an example of how to instantiate a ScriptIntrinsicBlur blur object. Element.U8_4 helper 方法将创建一个元素,该元素描述一个数据类型,该数据类型为8位无符号整数值的4个字段,适用于保存 Bitmap 对象的数据:The Element.U8_4 helper method will create an Element that describes a data type that is 4 fields of 8-bit, unsigned integer values, suitable for holding the data of a Bitmap object:

Android.Renderscripts.ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.Create(renderScript, Element.U8_4(renderScript));

Script 类中分配分配(s)、设置参数、& 运行脚本– 提供了一种用于实际运行 Renderscript 的 ForEach 方法。Assign Allocation(s), Set Parameters, & Run Script – The Script class provides a ForEach method to actually run the Renderscript. 此方法将遍历包含输入数据的 Allocation 中的每个 ElementThis method will iterate over each Element in the Allocation holding the input data. 在某些情况下,可能需要提供保存输出的 AllocationIn some cases, it may be necessary to provide an Allocation that holds the output. ForEach 将覆盖输出分配的内容。ForEach will overwrite the contents of the output Allocation. 为了附带前面步骤中的代码片段,此示例演示了如何分配输入分配、设置参数,最后运行脚本(将结果复制到输出分配):To carry on with the code snippets from the previous steps, this example shows how to assign an input Allocation, set a parameter, and then finally run the script (copying the results to the output Allocation):

blurScript.SetInput(inputAllocation);
blurScript.SetRadius(25);  // Set a pamaeter
blurScript.ForEach(outputAllocation);

你可能想要使用 Renderscript 食谱来查看对图像进行模糊处理,这是如何在 Xamarin 中使用内部脚本的完整示例。You may wish to check out the Blur an Image with Renderscript recipe, it is a complete example of how to use an intrinsic script in Xamarin.Android.

总结Summary

本指南介绍了 Renderscript 以及如何在 Xamarin Android 应用程序中使用它。This guide introduced Renderscript and how to use it in a Xamarin.Android application. 它简要讨论了什么是 Renderscript 以及它在 Android 应用程序中的工作方式。It briefly discussed what Renderscript is and how it works in an Android application. 它介绍了 Renderscript 中的一些关键组件以及_用户脚本_与_内部脚本_之间的差异。It described some of the key components in Renderscript and the difference between user scripts and instrinsic scripts. 最后,本指南介绍了在 Xamarin Android 应用程序中使用内部脚本的步骤。Finally, this guide discussed the steps in using an intrinsic script in a Xamarin.Android application.