Android高效计算——RenderScript(二)
3 RenderScript运行时层与反射层
3.1 RenderScript运行时层
RenderScript运行时层是指.rs代码运行时所在的层级。当对安卓项目进行编译的时候,.rs或者.rsh中编写的代码都会被llvm编译器编译成字节码。当该安卓应用在设备上运行的时候,这些字节码将会被设备上另外一个llvm编译(just-in-time)成机器码。这些机器码是针对该设备进行了优化的,且缓存在设备上,等到下次被应用的时候就不需要重新编译了,以加快速度。虽然RenderScript运行时层很像NDK,但是由于NDK中的C函数只针对CPU设计,与RenderScript还能够在GPU和DSP上运行的目标不同,因此在RenderScript中不能使用NDK中的C函数。
RenderScript运行时库的特性包括:
- 请求内存分配,即其内存是由Android framework层负责分配的。
- 一系列针对标量与向量计算的数学函数
- 提供基本数据到向量/矩阵或者数据到时间的转换函数
- 预定义的一系列二维、三维、四维向量类型
- Log功能,rsDebug函数
3.2 反射层
反射层由安卓编译工具基于开发者编写的.rs/.rsh文件自动生成的,反射层的作用就是给Android framework层提供对RenderScript运行时层操作的Java接口,包括内存分配、计算任务启动、数据交互等。
每一个.rs文件都会被映射成继承于ScriptC的类:ScriptC_RenderScript_filename,该类被生成在gen目录下与.rs文件相同的包下。该类就是.rs文件的Java版本。该类主要包含.rs中的如下内容:
- 非静态函数。.rs中的非kernel函数不能有返回值,因为RenderScript系统被设计成异步执行。当你从安卓层调用RenderScript函数的时候,这个调用被放在队列中,然后当轮到该调用的时候再执行。这样的话可以使RenderScript避免被经常打断以提升性能。如果想在RenderScript代码(.rs)中给安卓层返回值,则可以使用rsSendToClient()
- 非静态全局变量。而且会对这些变量生成get/set方法(const变量则不会生成set方法),且如果在RenderScript中对这些变量进行了初始化,那么在反射层也会进行相同的初始化。
- 全局指针。指针会被映射到.rs对应的类中。可以声明一个指针指向struct或者其他任何RenderScript支持的类型的指针。因为不容许在.rs中给指针分配内存,对于每个指针,都会生成一个对应的get方法以及bind_pointer_name,这个函数用于把在安卓VM中分配的内存绑定到RenderScript运行时。
- 定义的struct。Struct也是定义在.rs文件中,无论是单独定义struct还是和其他RenderScript代码放在一起,都会给每个单独的struct生成一个ScriptField_struct_name.java的类文件,你可以通过它来给一个或者多个该struct实例分配内存。但是注意:只有当你定义的struct在RenderScript代码中被用到了才会生成对应的类文件,若是没有使用的话则不会生成。在struct中不能含有指针或者数列。
Struct映射的详细解释
反射层生成的Struct主要包括:
- 构造函数:ScriptField_struct_name(RenderScript rs, int count),这个构造函数用来分配count数量的struct内存
- 构造函数:ScriptField_struct_name(RenderScript rs, int count, int usages)不仅通过count指定要分配的struct数量,并且通过usages指定这些内存被分配在哪个区域。主要有:
- USAGE_SCRIPT:指定在脚本内存区分配内存,这也是默认的内存分配区
- USAGE_GRAPHICS_TEXTURE: 在GPU的纹理内存区分配,API对其描述是:"The Allocation will be used as a texture source by one or more graphics programs.",所以如果么有打算需要绘制这些图片就不要在TEXTURE分配了。
- USAGE_GRAPHICS_VERTEX:在GPU的顶点内存区分配,API对其描述是:"The Allocation will be used as a graphics mesh. This was deprecated in API level 16.",已经在API16废弃。
- USAGE_GRAPHICS_CONSTANTS:在GPU的常量内存区分配。常量内存区被多个应用共同使用。API中对其描述是:“The Allocation will be used as the source of shader constants by one or more programs. This was deprecated in API level 16.”,同样也是在API16中就已经废弃。
可以使用或操作符来指定在多个内存区分配该内存,这样做表示向RenderScript表明:我想在多个内存区来访问该数据。
综上,能用的或者建议使用的就只有SCRIPT和TEXTURE两个,只需要记住:后面一个当你有使用GL绘制你分配的Allocation的时候才用即可。
- 一个Item内部类,通过该内部类你可以创建该结构的实例,这对于如果需要在安卓层中使用结构实例就非常有用。可以使用set(Item i, int index, boolean copyNow)方法来把某个Item实例插入到已经分配好的内存的指定位置。
- 结构中的每个字段都会有一个对应的set/get方法,且这些方法中都有一个index参数来指定要设置/读取内存区的哪个对象。每一个set方法都有一个copyNow参数来说明是否立即同步该内存到RenderScript运行时。通过调用copyAll方法可以同步所有还没有同步的内存。
- 创建该结构在内存中的描述Element,通过该Element可以分配由一个或者多个该结构对应的Element组成的内存。
- resize()函数。就像C中的realloc()一样,可以扩展之前分配的内存,并保持之前创建的对象的值。
- copyAll()用来同步在framework层设置的值到RenderScript运行时层。当调用set方法时,如果给copyNow设置的false,则将会在调用copyNow时同步到RenderScript运行时层。
代码举例:
.rs文件,文件名:script.rs
#pragma version(1)
#pragma rs java_package_name(com.example.renderscripttest)
#pragma rs_fp_relaxed uint32_t width;
uint32_t height; rs_allocation inBitmap;
rs_allocation rgbBitmap;
rs_allocation yuvBitmap; //multipliers to convert a RGB colors to black and white
const static float3 gMonoMult = {0.299f, 0.587f, 0.114f}; typedef struct Point_2D{
int x;
int y;
}Point; static Point *spPoint;
static Point sPoint;
Point point;
Point *pPoint; //google sample
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);
} void __attribute((kernel)) setPoint(const uint2 in, uint32_t x, uint32_t y){
rsDebug("lyh", point.x);
point.x = ; //struct is used
point.y = ;
rsSendToClient(, &point, );
rsDebug("willhua", point.x);
} uchar4 __attribute__((kernel)) halveBitmap(uchar4 in){
uchar4 out = in;
out.r = in.r / ;
out.r = in.r / ;
out.r = in.r / ;
return out;
} uchar4 __attribute__((kernel)) averageBitmap(uchar4 in, uint32_t x, uint32_t y){
uchar4 out = in; uchar4 left = in;
uchar4 top = in;
uchar4 right = in;
uchar4 bottom = in; if(x - > -){ //access other element
left = rsGetElementAt_uchar4(inBitmap, x - , y);
}
if(y - > -){
top = rsGetElementAt_uchar4(inBitmap, x , y - );
}
if(x + < width){
right = rsGetElementAt_uchar4(inBitmap, x + , y);
}
if(y + < height){
bottom = rsGetElementAt_uchar4(inBitmap, x, y + );
} out.r = (left.r + top.r + right.r + bottom.r) / ;
out.g = (left.g + top.g + right.g + bottom.g) / ;
out.b = (left.b + top.b + right.b + bottom.b) / ; return out;
}
反射层生成的ScriptC子类:
/*
* Copyright (C) 2011-2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ /*
* This file is auto-generated. DO NOT MODIFY!
* The source Renderscript file: G:\\Files\\EclipseWorkSpace\\RenderScriptTest\\src\\com\\example\\renderscripttest\\script.rs
*/ package com.example.renderscripttest; import android.support.v8.renderscript.*;
import android.content.res.Resources; /**
* @hide
*/
public class ScriptC_script extends ScriptC {
private static final String __rs_resource_name = "script";
// Constructor
public ScriptC_script(RenderScript rs) {
this(rs,
rs.getApplicationContext().getResources(),
rs.getApplicationContext().getResources().getIdentifier(
__rs_resource_name, "raw",
rs.getApplicationContext().getPackageName()));
} public ScriptC_script(RenderScript rs, Resources resources, int id) {
super(rs, resources, id);
__U32 = Element.U32(rs);
__ALLOCATION = Element.ALLOCATION(rs);
__ScriptField_Point_2D = ScriptField_Point_2D.createElement(rs);
__U8_4 = Element.U8_4(rs);
__U32_2 = Element.U32_2(rs);
} private Element __ALLOCATION;
private Element __ScriptField_Point_2D;
private Element __U32;
private Element __U32_2;
private Element __U8_4;
private FieldPacker __rs_fp_ALLOCATION;
private FieldPacker __rs_fp_ScriptField_Point_2D;
private FieldPacker __rs_fp_U32;
private final static int mExportVarIdx_width = 0;
private long mExportVar_width;
public synchronized void set_width(long v) {
if (__rs_fp_U32!= null) {
__rs_fp_U32.reset();
} else {
__rs_fp_U32 = new FieldPacker(4);
}
__rs_fp_U32.addU32(v);
setVar(mExportVarIdx_width, __rs_fp_U32);
mExportVar_width = v;
} public long get_width() {
return mExportVar_width;
} public Script.FieldID getFieldID_width() {
return createFieldID(mExportVarIdx_width, null);
} private final static int mExportVarIdx_height = 1;
private long mExportVar_height;
public synchronized void set_height(long v) {
if (__rs_fp_U32!= null) {
__rs_fp_U32.reset();
} else {
__rs_fp_U32 = new FieldPacker(4);
}
__rs_fp_U32.addU32(v);
setVar(mExportVarIdx_height, __rs_fp_U32);
mExportVar_height = v;
} public long get_height() {
return mExportVar_height;
} public Script.FieldID getFieldID_height() {
return createFieldID(mExportVarIdx_height, null);
} private final static int mExportVarIdx_inBitmap = 2;
private Allocation mExportVar_inBitmap;
public synchronized void set_inBitmap(Allocation v) {
setVar(mExportVarIdx_inBitmap, v);
mExportVar_inBitmap = v;
} public Allocation get_inBitmap() {
return mExportVar_inBitmap;
} public Script.FieldID getFieldID_inBitmap() {
return createFieldID(mExportVarIdx_inBitmap, null);
} private final static int mExportVarIdx_rgbBitmap = 3;
private Allocation mExportVar_rgbBitmap;
public synchronized void set_rgbBitmap(Allocation v) {
setVar(mExportVarIdx_rgbBitmap, v);
mExportVar_rgbBitmap = v;
} public Allocation get_rgbBitmap() {
return mExportVar_rgbBitmap;
} public Script.FieldID getFieldID_rgbBitmap() {
return createFieldID(mExportVarIdx_rgbBitmap, null);
} private final static int mExportVarIdx_yuvBitmap = 4;
private Allocation mExportVar_yuvBitmap;
public synchronized void set_yuvBitmap(Allocation v) {
setVar(mExportVarIdx_yuvBitmap, v);
mExportVar_yuvBitmap = v;
} public Allocation get_yuvBitmap() {
return mExportVar_yuvBitmap;
} public Script.FieldID getFieldID_yuvBitmap() {
return createFieldID(mExportVarIdx_yuvBitmap, null);
} private final static int mExportVarIdx_point = 5;
private ScriptField_Point_2D.Item mExportVar_point;
public synchronized void set_point(ScriptField_Point_2D.Item v) {
mExportVar_point = v;
FieldPacker fp = new FieldPacker(8);
fp.addI32(v.x);
fp.addI32(v.y);
int []__dimArr = new int[1];
__dimArr[0] = 1;
setVar(mExportVarIdx_point, fp, __ScriptField_Point_2D, __dimArr);
} public ScriptField_Point_2D.Item get_point() {
return mExportVar_point;
} public Script.FieldID getFieldID_point() {
return createFieldID(mExportVarIdx_point, null);
} private final static int mExportVarIdx_pPoint = 6;
private ScriptField_Point_2D mExportVar_pPoint;
public void bind_pPoint(ScriptField_Point_2D v) {
mExportVar_pPoint = v;
if (v == null) bindAllocation(null, mExportVarIdx_pPoint);
else bindAllocation(v.getAllocation(), mExportVarIdx_pPoint);
} public ScriptField_Point_2D get_pPoint() {
return mExportVar_pPoint;
} private final static int mExportForEachIdx_root = 0;
public Script.KernelID getKernelID_root() {
return createKernelID(mExportForEachIdx_root, 3, null, null);
} public void forEach_root(Allocation ain, Allocation aout) {
forEach_root(ain, aout, null);
} public void forEach_root(Allocation ain, Allocation aout, Script.LaunchOptions sc) {
// check ain
if (!ain.getType().getElement().isCompatible(__U8_4)) {
throw new RSRuntimeException("Type mismatch with U8_4!");
}
// check aout
if (!aout.getType().getElement().isCompatible(__U8_4)) {
throw new RSRuntimeException("Type mismatch with U8_4!");
}
Type t0, t1; // Verify dimensions
t0 = ain.getType();
t1 = aout.getType();
if ((t0.getCount() != t1.getCount()) ||
(t0.getX() != t1.getX()) ||
(t0.getY() != t1.getY()) ||
(t0.getZ() != t1.getZ()) ||
(t0.hasFaces() != t1.hasFaces()) ||
(t0.hasMipmaps() != t1.hasMipmaps())) {
throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
} forEach(mExportForEachIdx_root, ain, aout, null, sc);
} private final static int mExportForEachIdx_setPoint = 1;
public Script.KernelID getKernelID_setPoint() {
return createKernelID(mExportForEachIdx_setPoint, 57, null, null);
} public void forEach_setPoint(Allocation ain) {
forEach_setPoint(ain, null);
} public void forEach_setPoint(Allocation ain, Script.LaunchOptions sc) {
// check ain
if (!ain.getType().getElement().isCompatible(__U32_2)) {
throw new RSRuntimeException("Type mismatch with U32_2!");
}
forEach(mExportForEachIdx_setPoint, ain, null, null, sc);
} private final static int mExportForEachIdx_halveBitmap = 2;
public Script.KernelID getKernelID_halveBitmap() {
return createKernelID(mExportForEachIdx_halveBitmap, 35, null, null);
} public void forEach_halveBitmap(Allocation ain, Allocation aout) {
forEach_halveBitmap(ain, aout, null);
} public void forEach_halveBitmap(Allocation ain, Allocation aout, Script.LaunchOptions sc) {
// check ain
if (!ain.getType().getElement().isCompatible(__U8_4)) {
throw new RSRuntimeException("Type mismatch with U8_4!");
}
// check aout
if (!aout.getType().getElement().isCompatible(__U8_4)) {
throw new RSRuntimeException("Type mismatch with U8_4!");
}
Type t0, t1; // Verify dimensions
t0 = ain.getType();
t1 = aout.getType();
if ((t0.getCount() != t1.getCount()) ||
(t0.getX() != t1.getX()) ||
(t0.getY() != t1.getY()) ||
(t0.getZ() != t1.getZ()) ||
(t0.hasFaces() != t1.hasFaces()) ||
(t0.hasMipmaps() != t1.hasMipmaps())) {
throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
} forEach(mExportForEachIdx_halveBitmap, ain, aout, null, sc);
} private final static int mExportForEachIdx_averageBitmap = 3;
public Script.KernelID getKernelID_averageBitmap() {
return createKernelID(mExportForEachIdx_averageBitmap, 59, null, null);
} public void forEach_averageBitmap(Allocation ain, Allocation aout) {
forEach_averageBitmap(ain, aout, null);
} public void forEach_averageBitmap(Allocation ain, Allocation aout, Script.LaunchOptions sc) {
// check ain
if (!ain.getType().getElement().isCompatible(__U8_4)) {
throw new RSRuntimeException("Type mismatch with U8_4!");
}
// check aout
if (!aout.getType().getElement().isCompatible(__U8_4)) {
throw new RSRuntimeException("Type mismatch with U8_4!");
}
Type t0, t1; // Verify dimensions
t0 = ain.getType();
t1 = aout.getType();
if ((t0.getCount() != t1.getCount()) ||
(t0.getX() != t1.getX()) ||
(t0.getY() != t1.getY()) ||
(t0.getZ() != t1.getZ()) ||
(t0.hasFaces() != t1.hasFaces()) ||
(t0.hasMipmaps() != t1.hasMipmaps())) {
throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
} forEach(mExportForEachIdx_averageBitmap, ain, aout, null, sc);
} }
反射层生成的struct,Point_2D, 对应的类:
/*
* Copyright (C) 2011-2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ /*
* This file is auto-generated. DO NOT MODIFY!
* The source Renderscript file: G:\\Files\\EclipseWorkSpace\\RenderScriptTest\\src\\com\\example\\renderscripttest\\script.rs
*/ package com.example.renderscripttest; import android.support.v8.renderscript.*;
import android.content.res.Resources; /**
* @hide
*/
public class ScriptField_Point_2D extends android.support.v8.renderscript.Script.FieldBase {
static public class Item {
public static final int sizeof = 8; int x;
int y; Item() {
} } private Item mItemArray[];
private FieldPacker mIOBuffer;
private static java.lang.ref.WeakReference<Element> mElementCache = new java.lang.ref.WeakReference<Element>(null);
public static Element createElement(RenderScript rs) {
Element.Builder eb = new Element.Builder(rs);
eb.add(Element.I32(rs), "x");
eb.add(Element.I32(rs), "y");
return eb.create();
} private ScriptField_Point_2D(RenderScript rs) {
mItemArray = null;
mIOBuffer = null;
mElement = createElement(rs);
} public ScriptField_Point_2D(RenderScript rs, int count) {
mItemArray = null;
mIOBuffer = null;
mElement = createElement(rs);
init(rs, count);
} public ScriptField_Point_2D(RenderScript rs, int count, int usages) {
mItemArray = null;
mIOBuffer = null;
mElement = createElement(rs);
init(rs, count, usages);
} public static ScriptField_Point_2D create1D(RenderScript rs, int dimX, int usages) {
ScriptField_Point_2D obj = new ScriptField_Point_2D(rs);
obj.mAllocation = Allocation.createSized(rs, obj.mElement, dimX, usages);
return obj;
} public static ScriptField_Point_2D create1D(RenderScript rs, int dimX) {
return create1D(rs, dimX, Allocation.USAGE_SCRIPT);
} public static ScriptField_Point_2D create2D(RenderScript rs, int dimX, int dimY) {
return create2D(rs, dimX, dimY, Allocation.USAGE_SCRIPT);
} public static ScriptField_Point_2D create2D(RenderScript rs, int dimX, int dimY, int usages) {
ScriptField_Point_2D obj = new ScriptField_Point_2D(rs);
Type.Builder b = new Type.Builder(rs, obj.mElement);
b.setX(dimX);
b.setY(dimY);
Type t = b.create();
obj.mAllocation = Allocation.createTyped(rs, t, usages);
return obj;
} public static Type.Builder createTypeBuilder(RenderScript rs) {
Element e = createElement(rs);
return new Type.Builder(rs, e);
} public static ScriptField_Point_2D createCustom(RenderScript rs, Type.Builder tb, int usages) {
ScriptField_Point_2D obj = new ScriptField_Point_2D(rs);
Type t = tb.create();
if (t.getElement() != obj.mElement) {
throw new RSIllegalArgumentException("Type.Builder did not match expected element type.");
}
obj.mAllocation = Allocation.createTyped(rs, t, usages);
return obj;
} private void copyToArrayLocal(Item i, FieldPacker fp) {
fp.addI32(i.x);
fp.addI32(i.y);
} private void copyToArray(Item i, int index) {
if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
mIOBuffer.reset(index * mElement.getBytesSize());
copyToArrayLocal(i, mIOBuffer);
} public synchronized void set(Item i, int index, boolean copyNow) {
if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
mItemArray[index] = i;
if (copyNow) {
copyToArray(i, index);
FieldPacker fp = new FieldPacker(mElement.getBytesSize());
copyToArrayLocal(i, fp);
mAllocation.setFromFieldPacker(index, fp);
} } public synchronized Item get(int index) {
if (mItemArray == null) return null;
return mItemArray[index];
} public synchronized void set_x(int index, int v, boolean copyNow) {
if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
if (mItemArray[index] == null) mItemArray[index] = new Item();
mItemArray[index].x = v;
if (copyNow) {
mIOBuffer.reset(index * mElement.getBytesSize());
mIOBuffer.addI32(v);
FieldPacker fp = new FieldPacker(4);
fp.addI32(v);
mAllocation.setFromFieldPacker(index, 0, fp);
} } public synchronized void set_y(int index, int v, boolean copyNow) {
if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
if (mItemArray[index] == null) mItemArray[index] = new Item();
mItemArray[index].y = v;
if (copyNow) {
mIOBuffer.reset(index * mElement.getBytesSize() + 4);
mIOBuffer.addI32(v);
FieldPacker fp = new FieldPacker(4);
fp.addI32(v);
mAllocation.setFromFieldPacker(index, 1, fp);
} } public synchronized int get_x(int index) {
if (mItemArray == null) return 0;
return mItemArray[index].x;
} public synchronized int get_y(int index) {
if (mItemArray == null) return 0;
return mItemArray[index].y;
} public synchronized void copyAll() {
for (int ct = 0; ct < mItemArray.length; ct++) copyToArray(mItemArray[ct], ct);
mAllocation.setFromFieldPacker(0, mIOBuffer);
} }
4 内存
我们已经知道,应用自身运行在安卓VM中,而RenderScript部分代码则运行在本地,且其内存是由上层的应用分配的。
4.1 内存分配API
内存API主要包含三个类:Element,Type与Allocation。他们三者对应的关系能用malloc函数的使用来很好的说明,例如:
int *array = (int *)malloc(sizeof(int) * 10);
malloc函数的参数可以分成两个部分:第一个就是sizeof(int),该过程指定每个内存单元需要多个内存;第二个就是*10,该过程指定需要分配多个这样的内存单元。对应的内存分配APIs就是Element类,表示的是一个内存单元,就像一个float或者一个struct所表示的内存。而Type表示的就是“*10”部分,就像一个Element序列一样。Allocation则用来执行由Type所描述的内存分配,且最终代表分配得到的内存。
大部分情况下都不需要直接使用这些API,因为系统在自动生成反射层的时候已经做好了封装,需要做的就是调用对应类的构造函数并把分配的内存绑定到RenderScript而已。但是比如当你加载一张图片到RenderScript层或者给一个指针分配内存时,就需要应用到这些API。
4.2 静态内存
4.2.1 静态内存的分配
这里的静态内存指的是在RenderScript中声明的非静态的全局变量(静态的或者局部的变量就无法在Android framework层访问,也就不讨论),他们在编译时就分配了内存,在RenderScript代码中可以直接使用它们而不需要在Android Framework层给他们分配内存。在Android Framework层也可以通过反射层生成的函数来访问他们。如果这些变量在RenderScript中被初始化,那么他们也将在Android Framework层中被进行同样的初始化。
注意:如果在RenderScript中使用到了RenderScript中预定义了的一些含有指针的结构体,比如rs_program_fragment和rs_allocation,那么就需要先在Android Framework层构造一个该结构对应类的实例,然后调用set方法把内存绑定到RenderScript运行时,而不能直接在RenderScript层操作。但是这个对于用户自定义的包含指针的结果无效,因为根本就无法自定义包含指针的结构。
4.2.2 静态内存的读写
在RenderScript层对静态分配的内存的写操作是单向的。当你在RenderScript层修改了某个变量的值,出于性能方面的考虑,这个变化不会反应给安卓层。在安卓层调用get方法获得的是安卓层最后一次通过set方法设置的值,除非通过rsSendToClient()等手段,否则安卓层是永远获取不到RenderScript对静态分配的内存的修改的。但是,当安卓层修改了某个变量的值后,该值的变化随后就会自动同步到RenderScript层。
下面是读写示例。假如在rsfile.rs中定义了全局变量point:
typedef struct Point {
int x;
int y;
} Point_t; Point_t point;
那么在RenderScript中可以如下直接给变量赋值:
point.x = 1;
point.y = 1;
在Android framework层中可以这样修改该变量的值,且修改的值会通知到RenderScript层:
ScriptC_rsfile mScript;
...
Item i = new ScriptField_Point.Item();
i.x = 1;
i.y = 1;
mScript.set_point(i);
在RenderScript中读取变量的值:
rsDebug("Printing out a Point", point.x, point.y);
在Android framework中读取变量的值。再一次强调:读取到的永远是Android framework层最后一次调用set方法给该变量赋的值,而如果在Android framework层没有用set方法给变量赋过值的话,那么读取的将是null,下面代码也会报空指针错误
Log.i("TAGNAME", "Printing out a Point: " + mScript.get_point().x + " " + mScript.get_point().y);
System.out.println(point.get_x() + " " + point.get_y());
4.3 动态内存
4.3.1 动态内存的分配
对于动态内存,比如指针,就必须在Android Framework层中给它分配内存。需要两个过程:分配内存与绑定内存。这样做的好处在于:安卓VM能够完全掌握RenderScript内存的分配与回收。
无论在Android Framework层还是RenderScript中,都可以通过该指针来访问分配的内存。
为了给RenderScript动态分配内存,最常见的做法是调用Script.FieldBase的构造函数,当然好也可以手动创建Allocation来实现,为了简单起见,应该使用Script.FieldBase.当获取分配的内存对象后,就可以通过反射层的bind方法把该内存绑定到RenderScript。下面代码是两种实现方式的例子:
private RenderScript myRenderScript;
private ScriptC_example mScript;
private Resources resources;
public void init(RenderScript rs, Resources res) {
myRenderScript = rs;
resources = res;
//使用反射层生成的类分配内存
ScriptField_Point touchPoints = new ScriptField_Point(myRenderScript, 2);
//自己使用API分配内存
intPointer = Allocation.createSized(myRenderScript, Element.I32(myRenderScript), 2);
mScript = new ScriptC_example(myRenderScript, resources, R.raw.example);
//绑定内存
mScript.bind_touchPoints(touchPoints);
mScript.bind_intPointer(intPointer);
...
}
4.3.2 动态内存的读写
对于动态内存,在Android framework层可以通过反射层的set/get方法来读/写内存,在RenderScript中也可以像往常一样读/写,且任意一方的写操作都会通知到另外一方。
下面是示例。假设在rsfile.rs定义了如下全局指针:
typedef struct Point {
int x;
int y;
} Point_t;
Point_t *point;
只要你已经在Android framework层给分配了内存,那么就可以像往常一样使用它,且任何的修改都会通知到Android framework层。
point[index].x = 1;
point[index].y = 1;
在Android framework 层通过反射层提供的方法读写:
ScriptField_Point p = new ScriptField_Point(mRS, 1);
Item i = new ScriptField_Point.Item();
i.x=100;
i.y = 100;
p.set(i, 0, true);
mScript.bind_point(p);
points.get_x(0); //read x and y from index 0
points.get_x(0);
内存只需要绑定一次就可以了,不需要每次修改值的时候再次绑定
5 基本应用场景
5.1 RenderScript层回调Android framework层
前面我们提到过,RenderScript中的invokable不能有返回值,以及对于静态内存,RenderScript层对其修改不会通知到Android framework层。对于这两种情况,配套使用RSMessageHandler和rsSendToClient是很好的解决方案。对于二者的关系,从命名就可以看出一二,RSMessageHandler相当于常用的handleMessage函数,而rsSendToClient则相当于Handler.sendMessage,只是RSMessageHandler运行在Android framework层,而rsSendToClient运行在RenderScript层。
RenderScript.RSMessageHandler它implements Runnable,在使用过程中只需要重写run函数即可。其有三个重要的字段:
- mData:int[],对应rsSendToClient中的data,表示从RenderScript发送过来的数据的地址
- mID:消息标志,对应rsSendToClient中的cmdID,类似使用Handler发送Message时的what
- mLength:对应rsSendToClient时的len,mData中数据的个数
使用范例:
- 在RenderScript(.rs文件)中调用回调函数rsSendToClicent,reSendToClient函数有四个: rsSendToClient (int cmdID) rsSendToClient (int cmdID, const void *data, uint len) rsSendToClientBlocking (int cmdID) rsSendToClientBlocking (int cmdID, const void *data, uint len),其中cmdID即相当于message中的what参数。
- 在安卓层中,设定RenderScript中消息的Handler。即继承RenderScript.RSMessageHandler写一个类RSHandler,重写其中的run函数。在RenderScript.RSMessageHandler中有一个mID参数,即若与reSendToClient中的cmdID相等则表示是该reSendToClient发送过来的消息。
mRenderScript.setMessageHandler(new RSMessageHandler(){
@Override
public void run(){
switch (mID) {
case type:
//do something
break;
default:
break;
}
}
});
注意:run函数不是运行在主线程,所以在run函数中不能直接做操作主界面UI的操作。
5.2 在RenderScript kernel中访问更多的元素
我们提到过,对于一个kernel,最多只能有一个输入Allocation,假如需要在kernel中访问更多的Allocation,那怎么办呢?
在kernel中,仅容许对当前元素进行操作,即当前坐标(x,y)表示的元素,如果想访问其他元素,则需要定义一个全局的输入allocation,然后使用rsGetElementAt_type()来获取其他元素,比如:下面的averageBitmap就访问了全局变量inBitmap的数据:
rs_allocation inBitmap; uchar4 __attribute__((kernel)) averageBitmap(uchar4 in, uint32_t x, uint32_t y){
uchar4 out = in; uchar4 left = in;
uchar4 top = in;
uchar4 right = in;
uchar4 bottom = in; if(x - 1 > -1){ //access other element
left = rsGetElementAt_uchar4(inBitmap, x - 1, y);
}
if(y - 1 > -1){
top = rsGetElementAt_uchar4(inBitmap, x , y - 1);
}
if(x + 1 < width){
right = rsGetElementAt_uchar4(inBitmap, x + 1, y);
}
if(y + 1 < height){
bottom = rsGetElementAt_uchar4(inBitmap, x, y + 1);
} out.r = (left.r + top.r + right.r + bottom.r) / 4;
out.g = (left.g + top.g + right.g + bottom.g) / 4;
out.b = (left.b + top.b + right.b + bottom.b) / 4; return out;
}
Android高效计算——RenderScript(二)的更多相关文章
- Android高效计算——RenderScript(一)
高效计算——RenderScript RenderScript是安卓平台上很受谷歌推荐的一个高效计算平台,它能够自动把计算任务分配到各个可用的计算核心上,包括CPU,GPU以及DSP等,提供十分高效的 ...
- Android高效内存:让图片占用尽可能少的内存
Android高效内存:让图片占用尽可能少的内存 一.让你的图片最小化 1.1 大图小图内存使用情况对比 大图:440 * 336 小图:220 * 168 小图的高宽都是大图的1/2--> ...
- Android高效内存之让你的图片省内存
Android高效内存之让你的图片省内存 在做内存优化的时候,我们发现除了解决内存泄露问题,剩下的就只有想办法减少真实的内存占用.而在App中,大部分内存可能被我们图片占用了,所以减少图片的内存占用可 ...
- Android高效内存2:让图片占用尽可能少的内存
Android高效内存:让图片占用尽可能少的内存 一.让你的图片最小化 1.1 大图小图内存使用情况对比 大图:440 * 336 小图:220 * 168 资源目录:xhdpi 小图的高宽都是 ...
- Android高效异步图片加载框架
概述 Android高效异步图片加载框架:一个高效的异步加载显示的图片加载框架,同时具备图片压缩,缓存机制等特性. 详细 代码下载:http://www.demodashi.com/demo/1214 ...
- 【转】Android手机客户端关于二维码扫描的源码--不错
原文网址:https://github.com/SkillCollege/QrCodeScan QrCodeScan 这是Android手机客户端关于二维码扫描的源码,使用了高效的ZBar解码库,并修 ...
- Android高效加载大图、多图解决方案,有效避免程序内存溢出现象
好久没有写博客了,今天就先写一个小的关于在Android中加载大图如何避免内存溢出的问题. 后面会写如何使用缓存技术的核心类,android.support.v4.util.LruCache来加载图片 ...
- Android studio 使用心得(四)—android studio 多渠道打包(二)
Android studio 使用心得(四)—android studio 多渠道打包 这篇文章讲了一种打包方式.是直接在android studio 里面可视化操作,结合配置文件.我个人觉得严格上来 ...
- Android Volley完全解析(二),使用Volley加载网络图片
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17482165 在上一篇文章中,我们了解了Volley到底是什么,以及它的基本用法. ...
随机推荐
- EntityFramework之你不知道的那些事(七)
前言 前面一系列几乎都是循序渐进式的进行叙述,似乎脚步走得太快了,于是我开始歇一歇去追寻一些我所不太了解的细枝末节,在此过程中也屡次碰壁,但是唯有如此才能更好的成长,不是吗!希望此文对你亦有帮助. 属 ...
- Python深入06 Python的内存管理
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 语言的内存管理是语言设计的一个重要方面.它是决定语言性能的重要因素.无论是C语言的 ...
- 十进制(decimal system)转换函数说明
一,十进制(decimal system)转换函数说明 1,十进制转二进制 decbin() 函数,如下实例 echo decbin(12); //输出 1100 echo decbin(26); / ...
- MySQL索引下推技术
索引下推整个思路如下: To see how this optimization works, consider first how an index scan proceeds when Index ...
- 如何添加并设置远程桌面(RD)授权服务器
上一篇日志中介绍了如何将现成的远程桌面授权服务器添加到对应的远程桌面回话主机中. 本篇日志将引导您如何添加配置相应的远程桌面授权服务器,这样就可以根据所购买的授权类型和授权级别添加需要甚至" ...
- 数据结构:C_链表队列的实现
数据结构链表形式队列的实现(C语言版) 1.写在前面 队列是一种和栈相反的,遵循先进先出原则的线性表. 本代码是严蔚敏教授的数据结构书上面的伪代码的C语言实现代码. 分解代码没有包含在内的代码如下: ...
- svn 几个常用命令(持续更新)
1:获取某个版本号(3583)下的代码 svn co http://tech.yoai.com:8300/c ...
- 2.Java基础之Runtime对象
毕向东老师Java基础学习笔记——Runtime对象 今天学习Java中的Runtime对象后,感觉这个对象对我们主要有以下几点用处. 1.使用java代码打开本地可执行文件,比如打开一个计算器. 2 ...
- css学习--css基础
学习慕课网笔记,课程:http://www.imooc.com/code/2024 1.css选择器 子选择器:parent>child 子选择器是指选择parent的范围内的第一个子元素.这里 ...
- 内存中OLTP与内存不足
我已经写了好几次内存中OLTP的文章和”为什么我还不推荐内存中OLTP给用户”.今天我想进一步谈下内存中OLTP背后的内存需求,还有如果你内存不够的话会发生什么. 一切都与内存有关! 我们都知道很久之 ...