渲染脚本(Renderscript)提供用C语言(C99标准)编写的原生级高性能的计算API。Renderscript 让你的应用程序有能力跨越所有可用的处理器内核来自动的平行的运行各种操作。它还提供了对不同类型 的处理的支持,如CPU、GPU或DSP等。Renderscript对于图形处理、数学模型或其他任何需要大量的数 学计算的应用程序都使用有用的。
另外,不需要编写代码你就能够访问所有这些功能来支持不同的架构或不同数量的处理器内核。也不需要 针对不同的处理器类型来编译你的应用程序,因为Renderscript代码是在设备上运行时被编译的。
注意:早期的Renderscript版本包含了一个实验性的图形引擎组件。这个组件限制被Android4.1 弃用了(rs_graphics.rsh中的大多数API和android.renderscript中对应的API)。如果你有使用 Renderscript来渲染图形的应用程序,强烈推荐你把代码转换到另外的Android图形渲染选项。
Renderscript运行时的操作是原生级别的,并且依然需要跟Android的虚拟机(VM)进行通信,因此 创建一个Renderscript应用程序的方法不同于纯粹的虚拟机应用程序。除了你为程序编写的所需要的 Renderscript代码之外,使用Renderscript的应用程序依然是一个运行在虚拟机(VM)中的应用程序, 不管你使用它做什么,Renderscript依然保留它的平台独立性,因此不必编写多架构 (例如:ARM v5、ARM v7、x86)的Renderscript代码。
Renderscript系统采用了一个控制和从属的架构,在这个架构中低级别的Renderscript运行时代码是 由运行在虚拟机(VM)中高级别的Android来控制的。Android VM依然保留所有的对内存管理和分配给 Renderscript运行时的绑定内存的控制,因此Renderscript的代码能够访问它。Android框架使用 异步的方式调用Renderscript,并且调用会被放到消息队列中,直到它被处理。 图1显示了Renderscript系统的结构:
Renderscript扩大了设备上可用的处理器内核的范围。这种能力是通过名叫rsForEach() (或者是Android框架级别下的forEach_root()方法)方法来获得的。它会自动的区分访问设备设备上 可用的处理器内核的工作。目前,Renderscript只能利用CPU内核的优势,但是在将来,它们会能够 运行在其他类型的处理器上,如GPU和DSP等。
实现一个Renderscript要涉及创建一个包含Renderscript代码的.rs文件和在Android框架级别下 用forEach_root()方法调用该文件(或者是在Renderscript级别下用rsForEach()函数调用该文件)。 下图介绍了如何建立一个典型的Renderscript:
这个例子使用了SDK开发指南中提供的HelloCompute Renderscript示例。
Renderscript代码要保留在/src/目录中的*.rs和*.rsh文件中。代码中包含了计算 的逻辑和所有必要的变量和指针的声明。通常,每个*.rs文件要包含下列项目:
#pragma version(1)
#pragma rs java_package_name(com.example.android.rs.hellocompute)
//multipliers to convert a RGB colors to black and white
const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
void root(const uchar4 *v_in, uchar4 *v_out) {
//unpack a color to a float4
float4 f4 = rsUnpackColor8888(*v_in);
//take the dot product of the color and the multiplier
float3 mono = dot(f4.rgb, gMonoMult);
//repack the float to a color
*v_out = rsPackColorTo8888(mono);
}
你能够通过由实例化的类(ScriptC_script_name)来创建一个Renderscript对象从Android框架代 码中调用Renderscript。这个类包含了一个forEach_root()方法,它会调用rsForeach()方法。 你能够传递给它与Renderscript运行时级别调用相同的参数。这种技术允许你的Android应用程序把 高精度的数学计算转交给Renderscript。
以下示例来自HellCompute示例,它处理一张位图,并输出它的黑白版本。CreateScript()方法 安装前面描述的步骤来执行。这个方法调用Renderscript对象,执行mono.rs脚本,把最终的处理 结果位图保存在输出的内存中,然后把处理后的位图显示在屏幕上:
package com.example.android.rs.hellocompute;
import android.app.Activity;
import android.os.Bundle;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap;
import android.renderscript.RenderScript;
import android.renderscript.Allocation;
import android.widget.ImageView;
public class HelloCompute extends Activity {
private Bitmap mBitmapIn;
private Bitmap mBitmapOut;
private RenderScript mRS;
private Allocation mInAllocation;
private Allocation mOutAllocation;
private ScriptC_mono mScript;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mBitmapIn = loadBitmap(R.drawable.data);
mBitmapOut = Bitmap.createBitmap(mBitmapIn.getWidth(), mBitmapIn.getHeight(),
mBitmapIn.getConfig());
ImageView in = (ImageView) findViewById(R.id.displayin);
in.setImageBitmap(mBitmapIn);
ImageView out = (ImageView) findViewById(R.id.displayout);
out.setImageBitmap(mBitmapOut);
createScript();
}
private void createScript() {
mRS = RenderScript.create(this);
mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT);
mOutAllocation = Allocation.createTyped(mRS, mInAllocation.getType());
mScript = new ScriptC_mono(mRS, getResources(), R.raw.mono);
mScript.forEach_root(mInAllocation, mOutAllocation);
mOutAllocation.copyTo(mBitmapOut);
}
private Bitmap loadBitmap(int resource) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
return BitmapFactory.decodeResource(getResources(), resource, options);
}
}
在这个例子中,假定在Android框架层脚本和内存已经被分配和绑定,并且UserData_t是一个被事前 声明的结构。把这个结构的指针和它的大小传递一个rsForEach()方法,这是一个可选的参数。如果你 的Renderscript需要一些输入内存中之外的信息,就可以使用这个参数。
你能够定义计算规则所需要的浮点精度。如果你需要比IEEE 754-2008标准(默认使用的标准)更小的精度, 使用这个定义是有用的。你能够使用下列编译指令来定义脚本的浮点精度级别:
#pragma rs_fp_full
(如果没指定,这是默认的精度级别):指示应用程序需要由IEEE 754-2008 标准所描述的浮点精度。#pragma rs_fp_relaxed
对于不需要严格遵从IEEE 754-2008标准要求精度的应用程序可以 使用这种编译指令,对于de-norms(去模)计算这种模式启用了flush-to-zero(清零), 并且round-towards-zero(向零方向舍入)。#pragma rs_fp_imprecise
对于没有严格精度要求的应用程序使用这种模式。这种模式沿用了 rs_fp_relaxed模式以下的所有规则: