Android API Guides---Advanced RenderScript

来源:互联网 发布:忧伤说唱 网络歌手mp3 编辑:程序博客网 时间:2024/05/06 16:37
因为,利用RenderScript应用程序仍然在Android虚拟机内运行,您可以访问所有你熟悉的框架API,但在适当的时候可以利用RenderScript。为了便于框架和RenderScript运行时之间的这种相互作用,的代码的中间层也是本便利的代码在两个电平之间的通信和存储器管理。这份文件进入关于这些代码不同层次的更详细,以及内存是如何Android的虚拟机和RenderScript运行时之间共享。


RenderScript运行时层


您的RenderScript代码被编译并在一个紧凑的和明确的运行时层执行。该RenderScript运行时API提供密集的计算是便携和自动扩展到核心的处理器上可用的量支持。


注:在NDK标准的C函数必须保证在CPU上运行,因此RenderScript无法访问这些库,因为RenderScript被设计成不同类型的处理器上运行。


您可以定义.RS和.rsh文件在你的Andr​​oid项目的src /目录中RenderScript代码。该代码是由运行作为一个Android版本的一部分,LLVM编译器编译到中间字节码。当应用程序在设备上运行时,字节码,然后由驻留在设备上的另一个LLVM编译器编译(刚刚好时间)为机器代码。本机代码是为设备进行了优化,同时缓存中,RenderScript,使后续使用启用应用程序不重新编译字节码。


在RenderScript运行时库的一些关键特性包括:


内存分配请求的功能
大集既标量和矢量数学函数重载的类型很多常见的程序版本。操作如加,乘,点积和叉积可以及原子算术和比较功能。
对于原始数据类型和向量,矩阵程序,以及日期和时间程序转换例程
数据类型和结构,以支持RenderScript系统,如向量类型定义二,三或四的载体。
日志记录功能
请参阅可用的功能的更多信息,RenderScript运行时API参考。


反射层


反射层是一套Android编译工具生成允许从Android框架访问RenderScript运行时类。该层还提供了方法和构造,让您分配和使用内存工作在你的RenderScript代码中定义的指针。下面的列表描述所反映的主要组成部分:


您创建的每个.RS文件生成到一个名为project_root / /包/类型ScriptC的代名称/ ScriptC_renderscript_filename类。这个文件是.RS文件,您可以从Android框架调用将.java版本。此类包含从.RS文件反映了以下项目:
非静态函数
非静态,全局RenderScript变量。为每个变量产生存取​​方法,这样你就可以读取和Android框架编写RenderScript变量。如果一个全局变量在运行时RenderScript初始化层,这些值用在Android框架层初始化相应的值。如果全局变量被标记为const,则不会产生一套方法。
全球指针
一个结构反映到名为project_root / GEN /包/名/ ScriptField_struct_name自己的类,它扩展Script.FieldBase。这个类代表的结构,它允许您为这个结构的一个或多个实例分配内存的数组。

功能

功能反映到脚本类本身,位于project_root / GEN /包/名/ ScriptC_renderscript_filename。例如,如果你声明下面的函数在RenderScript的代码:

void touch(float x, float y, float pressure, int id) {    if (id >= 10) {        return;    }    touchPos[id].x = x;    touchPos[id].y = y;    touchPressure[id] = pressure;}
然后将以下代码生成:

public void invoke_touch(float x, float y, float pressure, int id) {    FieldPacker touch_fp = new FieldPacker(16);    touch_fp.addF32(x);    touch_fp.addF32(y);    touch_fp.addF32(pressure);    touch_fp.addI32(id);    invoke(mExportFuncIdx_touch, touch_fp);}

功能不能有一个返回值,因为RenderScript系统被设计为异步的。当你的Android框架代码调用到RenderScript,呼叫排队,并在执行时可能。此限制允许RenderScript系统功能,无需不断中断,提高了效率。如果职能允许有返回值,调用将阻塞,直到返回的值。
如果你想在RenderScript的代码,将值回Android框架,使用rsSendToClient()函数。
变量
支持的类型变量反映到脚本类本身,位于project_root/ GEN /包/名/脚本_render SCRIPT_FILENAME。一组访问方法为每个变量生成。例如,如果你声明以下变量在RenderScript的代码:

uint32_t unsignedInteger = 1;
然后将以下代码生成:

private long mExportVar_unsignedInteger;public void set_unsignedInteger(long v){    mExportVar_unsignedInteger = v;    setVar(mExportVarIdx_unsignedInteger, v);}public long get_unsignedInteger(){    return mExportVar_unsignedInteger;}

结构


结构反映到自己的班级,位于<project_root>/根/ COM/例子/ renderscript/ ScriptField_struct_name。此类表示结构的数组,并允许您为结构指定数量的分配内存。例如,如果你声明如下结构:

typedef struct Point {    float2 position;    float size;} Point_t;
那么下面的代码在ScriptField_Point.java产生:

package com.example.android.rs.hellocompute;import android.renderscript.*;import android.content.res.Resources;  /**  * @hide  */public class ScriptField_Point extends android.renderscript.Script.FieldBase {    static public class Item {        public static final int sizeof = 12;        Float2 position;        float size;        Item() {            position = new Float2();        }    }    private Item mItemArray[];    private FieldPacker mIOBuffer;    public static Element createElement(RenderScript rs) {        Element.Builder eb = new Element.Builder(rs);        eb.add(Element.F32_2(rs), "position");        eb.add(Element.F32(rs), "size");        return eb.create();    }    public  ScriptField_Point(RenderScript rs, int count) {        mItemArray = null;        mIOBuffer = null;        mElement = createElement(rs);        init(rs, count);    }    public  ScriptField_Point(RenderScript rs, int count, int usages) {        mItemArray = null;        mIOBuffer = null;        mElement = createElement(rs);        init(rs, count, usages);    }    private void copyToArray(Item i, int index) {        if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count        */);        mIOBuffer.reset(index * Item.sizeof);        mIOBuffer.addF32(i.position);        mIOBuffer.addF32(i.size);    }    public 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);            mAllocation.setFromFieldPacker(index, mIOBuffer);        }    }    public Item get(int index) {        if (mItemArray == null) return null;        return mItemArray[index];    }    public void set_position(int index, Float2 v, boolean copyNow) {        if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */);        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];        if (mItemArray[index] == null) mItemArray[index] = new Item();        mItemArray[index].position = v;        if (copyNow) {            mIOBuffer.reset(index * Item.sizeof);            mIOBuffer.addF32(v);            FieldPacker fp = new FieldPacker(8);            fp.addF32(v);            mAllocation.setFromFieldPacker(index, 0, fp);        }    }    public void set_size(int index, float v, boolean copyNow) {        if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */);        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];        if (mItemArray[index] == null) mItemArray[index] = new Item();        mItemArray[index].size = v;        if (copyNow)  {            mIOBuffer.reset(index * Item.sizeof + 8);            mIOBuffer.addF32(v);            FieldPacker fp = new FieldPacker(4);            fp.addF32(v);            mAllocation.setFromFieldPacker(index, 1, fp);        }    }    public Float2 get_position(int index) {        if (mItemArray == null) return null;        return mItemArray[index].position;    }    public float get_size(int index) {        if (mItemArray == null) return 0;        return mItemArray[index].size;    }    public void copyAll() {        for (int ct = 0; ct < mItemArray.length; ct++) copyToArray(mItemArray[ct], ct);        mAllocation.setFromFieldPacker(0, mIOBuffer);    }    public void resize(int newSize) {        if (mItemArray != null)  {            int oldSize = mItemArray.length;            int copySize = Math.min(oldSize, newSize);            if (newSize == oldSize) return;            Item ni[] = new Item[newSize];            System.arraycopy(mItemArray, 0, ni, 0, copySize);            mItemArray = ni;        }        mAllocation.resize(newSize);        if (mIOBuffer != null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */);    }}
生成的代码提供给你作为一个方便由RenderScript运行时所需的结构分配内存,并在内存结构交互。每个结构的类定义了以下方法和构造函数:


重载构造函数,允许您分配内存。该ScriptField_struct_name(RenderScript RS,诠释计数)构造允许您定义要与计数参数分配内存结构的数量。该ScriptField_struct_name(RenderScript RS,诠释计数,诠释用途)构造函数定义一个额外的参数,用途,让您指定该内存分配的内存空间。有四个存储空间的可能性:
USAGE_SCRIPT:分配脚本的内存空间。这是默认的内存空间,如果你不指定内存空间。
USAGE_GRAPHICS_TEXTURE:分配在GPU的纹理存储器空间。
USAGE_GRAPHICS_VERTEX:分配在GPU的顶点存储器空间。
USAGE_GRAPHICS_CONSTANTS:分配中所使用的各种程序对象GPU的常量存储空间。
您可以通过使用位OR运算符指定多个存储空间。这样做会通知你打算在指定的存储空间访问数据的RenderScript运行。下面的例子在这两个剧本和顶点的内存空间自定义数据类型分配内存:

       ScriptField_Point touchPoints = new ScriptField_Point(myRenderScript, 2,        Allocation.USAGE_SCRIPT | Allocation.USAGE_GRAPHICS_VERTEX);      
静态嵌套类,项目,可以让你创建结构的实例,以对象的形式。如果它使更多的意义在你的Andr​​oid的代码结构来解决这个嵌套类是非常有用的。当您完成操作物体,可以通过调用一套推对象分配的内存(项目我,INT指数,布尔copyNow)和项目设置到阵列中所需的位置。该RenderScript运行时自动访问新写入的内存。
存取方法来获取和设置每个字段的值在一个结构。每一种访问方法有一个索引参数来指定要读取或写入到阵列中的结构。每个setter方法​​也有指定是否立即同步此内存到RenderScript运行时copyNow参数。要同步尚未同步任何存储,调用copyAll()。
的的createElement()方法创建在内存中的结构的描述。该描述用于分配存储器由一个或多个元件。
调整()的作品很像一个realloc的(c)中,允许你扩大先前分配的内存,保持先前创建的当前值。
copyAll()将同步于该框架级到RenderScript运行时设置内存。当你调用一个set访问方法的成员,还有就是你可以指定一个可选的copyNow布尔参数。指定true同步,当你调用该方法的内存。如果指定假的,你可以调用一次copyAll(),它对于那些尚未同步的所有属性同步内存。
指针


指针反映到脚本类本身,位于project_root / GEN /包/名/ ScriptC_renderscript_filename。你可以声明指向结构或任何支持RenderScript类型,而是一个结构不能包含指针或嵌套数组。例如,如果你声明如下指向一个struct和int32_t

typedef struct Point {    float2 position;    float size;} Point_t;Point_t *touchPoints;int32_t *intPointer;
然后将以下代码中产生:

private ScriptField_Point mExportVar_touchPoints;public void bind_touchPoints(ScriptField_Point v) {    mExportVar_touchPoints = v;    if (v == null) bindAllocation(null, mExportVarIdx_touchPoints);    else bindAllocation(v.getAllocation(), mExportVarIdx_touchPoints);}public ScriptField_Point get_touchPoints() {    return mExportVar_touchPoints;}private Allocation mExportVar_intPointer;public void bind_intPointer(Allocation v) {    mExportVar_intPointer = v;    if (v == null) bindAllocation(null, mExportVarIdx_intPointer);    else bindAllocation(v, mExportVarIdx_intPointer);}public Allocation get_intPointer() {    return mExportVar_intPointer;}  
生成一个GET方法和一种特殊的方法命名bind_pointer_name(而不是set()方法)。这种方法允许你绑定是在Android虚拟机分配到RenderScript运行时(你不能在你的.RS文件分配内存)内存。欲了解更多信息,请参阅使用分配的内存工作。


内存分配的API


使用RenderScript仍然在Android虚拟机运行的应用程序。实际RenderScript的代码,但是,本地运行和需要访问在Android虚拟机分配的内存。要做到这一点,必须附上在虚拟机分配给RenderScript运行时的内存。这个过程被称为绑定,允许RenderScript运行时内存无缝工作,它要求但没有明确分配。最终的结果是本质上是一样的,如果你曾要求在的malloc C的好处是,Android的虚拟机可以进行垃圾收集,以及共享内存与RenderScript运行时层。绑定仅适用于动态分配的内存需要。静态分配的内存在编译时您RenderScript代码自动生成。参见图1的内存分配是如何发生的更多信息。


为了支持这种内存分配系统,还有一套API,允许Android的虚拟机分配内存和一个malloc调用提供了类似的功能。这些课程基本上是描述如何内存应分配,并进行分配。为了更好地理解这些类是如何工作的,就一个简单的malloc调用,可以是这样的认为他们是有用的:

array = (int *)malloc(sizeof(int)*10);
malloc调用可以分为两部分:被分配的内存的大小(sizeof的(INT)),以及如何内存的许多单位应分配(10)。 Android框架提供了这两个部分类以及一个类来表示的malloc本身。


Element类代表(的sizeof(INT))malloc调用的部分,并封装内存分配的一个细胞,如一个浮点值还是结构。 Type类封装了元素和元素来分配(在本例中10)的数量。你可以把一个类型为元素的数组中。该配置类执行基于给定类型的实际内存分配和代表实际分配​​的内存。


在大多数情况下,你不需要直接调用这些内存分配的API。反射层类生成代码来自动使用这些API,所有你需要做的分配内存的调用是在反射层的一个类中声明的构造函数,然后将得到的内存分配结合到RenderScript。有些情况下,您会希望直接使用这些类在自己的分配内存,如从资源加载位图或当你想为指针的原始类型分配内存。你可以看到如何做到这一点的分配和绑定内存到RenderScript部分。下表详细描述了三个内存管理类

Android的对象类型说明
Element
一个元素描述的存储器分配的一个单元,并可以有两种形式:基本的或复杂的。


一个基本元件包含任何有效RenderScript数据类型的数据的一个单一的组件。基本元素的数据类型的实例包括一个浮点值,一个float4载体或单一的RGB-565色。


复杂的元素包含基本元素的列表,从您在RenderScript代码声明结构被创建。例如分配可以包含在内存中的顺序排列的多个结构。每个结构被认为是它自己的元件,而不是该结构中的每个数据类型。
Type
A型是一个存储器分配模板和由一个元件和一个或多个尺寸。它描述了存储器的布局(基本上元件的阵列),但不分配用于它描述数据存储器。


A型由五个维度:X,Y,Z,LOD(层次细节)和面(的立方体贴图)。可以分配在X,Y,Z尺寸可用内存的限制范围内的任何正整数值。单个维度分配具有大于零的X尺寸而Y和Z维度是零,以指示不存在。例如,为X = 10的分配,Y = 1被认为是二维并且x = 10,Y = 0被认为是一维的。 LOD值和面尺寸为布尔值,表明存在或不存在。
Allocation
分配为基于由一个类型所表示的存储器的描述应用的存储器。分配的内存可以在很多存储空间同时存在。如果存储器在一个空间改性,必须明确同步存储器,使得它在所有在它存在的其他空间更新。


分配数据上传两种主要方法之一:进行类型检查和类型选中。对于简单的数组还有的copyfrom()即采取从Android系统中的数组并将其复制到本机的内存层存储的功能。未选中的变种允许Android系统,以结构数组,因为它不支持结构拷贝过来。例如,如果存在为n float数组分配,包含在浮子[n]的数组或字节[N * 4]数组可以被复制的数据。

使用内存
您在RenderScript声明非静态的,全局变量在编译时分配的内存。您可以直接与这些变量在RenderScript代码工作,而无需在Android框架水平为它们分配内存。 Android框架层也可以访问这些变量与在反射层类生成所提供的存取方法。如果这些变量在运行时RenderScript初始化层,这些值用在Android框架层初始化相应的值。如果全局变量被标记为const,则不会产生一套方法。
注:如果您使用的是包含指针,如s_program片段rs_allocation一定RenderScript结构,你必须获得相应的Andr​​oid框架类的一个对象,然后再调用set方法为结构内存绑定到RenderScript运行。在RenderScript运行时层不能直接操纵这些结构。这一限制不适用于包含指针,因为它们不能在第一时间被导出到反射层类的用户定义的结构。如果您尝试声明包含一个指向非静态,全局结构生成一个编译器错误。
RenderScript也有三分球支持,但是你必须明确地在你的Andr​​oid框架代码分配内存。当您在.RS文件中声明全局指针,您可以通过适当的反射层类的分配内存和绑定内存到本机RenderScript层。您可以从Android框架层还有RenderScript层,它为您提供了灵活地修改在最合适的层变量此内存交互。
分配和结合动态内存到RenderScript
要动态分配内存空间,你需要调用一个Script.FieldBase类,这是最常见的方式的构造。另一种方法是手动创建的分配,这是需要的东西,如基本类型的指针。您应该使用Script.FieldBase类构造函数时提供的简单性。获得的内存分配后,呼叫指示器的反射bind方法到分配的存储器结合到RenderScript运行时。
下面的例子分配内存两种基本类型的指针,intPointer,和一个指向一个结构,接触点。它也结合了内存到RenderScript:

private RenderScript myRenderScript;private ScriptC_example script;private Resources resources;public void init(RenderScript rs, Resources res) {    myRenderScript = rs;    resources = res;    //allocate memory for the struct pointer, calling the constructor    ScriptField_Point touchPoints = new ScriptField_Point(myRenderScript, 2);    //Create an element manually and allocate memory for the int pointer    intPointer = Allocation.createSized(myRenderScript, Element.I32(myRenderScript), 2);    //create an instance of the RenderScript, pointing it to the bytecode resource    mScript = new ScriptC_example(myRenderScript, resources, R.raw.example);    //bind the struct and int pointers to the RenderScript    mScript.bind_touchPoints(touchPoints);    script.bind_intPointer(intPointer);   ...}
读取和写入内存


您可以读取和写入静态和动态的RenderScript运行时和Android框架层分配的内存两者。


静态分配的内存中自带的RenderScript运行水平单向通信限制。当RenderScript代码改变一个变量的值,它不传回以提高效率Android框架层。这是从Android框架设置的最后一个值到调用get方法时总是返回。然而,当Android框架代码修改的变量,这种变化可以自动传达给RenderScript运行时或在稍后的时间同步。如果你需要从RenderScript运行时将数据发送到Android框架层,可以使用rsSendToClient()函数来克服这个限制。


当使用动态分配的内存工作,在RenderScript运行时层的任何变化,如果你使用其相关的指针修改的内存分配传播回Android框架层。修改在Android框架层的对象立即传播的变回了RenderScript运行时层。


读取和写入全局变量


读取和写入全局变量是一个简单的过程。您可以在Android框架级别使用存取方法或直接在RenderScript代码设置。请记住,您在RenderScript代码做任何更改都不会传播回Android框架层。


例如,给定下面的结构在rsfile.rs文件名为声明:

typedef struct Point {    int x;    int y;} Point_t;Point_t point;
您可以在rsfile.rs赋值给这个结构一样,直接。这些值不会传播回Android框架级别:

point.x = 1;point.y = 1;
你可以在这样的Android框架层赋值给结构。这些值传播回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框架层读取值。请记住,如果一个人被定为Android框架水平这个代码只返回一个值。你会得到一个空指针异常,如果你只设置在RenderScript运行级别的值:

Log.i("TAGNAME", "Printing out a Point: " + mScript.get_point().x + " " + mScript.get_point().y);System.out.println(point.get_x() + " " + point.get_y());
读取和写入全球指针


假设内存已经在Android框架层分配,并绑定到RenderScript运行时,您可以读取和使用get和该指针的设置方法写在Android框架级内存。在RenderScript运行时层,可以读取和写入的指针正常和改变内存中传播回Android框架层,不像静态分配的内存。


例如,给定以下指针在一个rsfile.rs文件名为一个结构:

typedef struct Point {    int x;    int y;} Point_t;Point_t *point;
假设你在Android框架层已分配的内存,您可以在结构正常访问值。你通过它的指针变量做出的struct任何更改都会自动提供给Android框架层:

point[index].x = 1;point[index].y = 1;
您可以读取和写入值在Android框架层的指针,以及:

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);
一旦内存已经绑定,您不必每次进行更改值时重新绑定内存到RenderScript运行。

0 0