android--graphics

来源:互联网 发布:淘宝商铺怎么激活 编辑:程序博客网 时间:2024/05/17 01:43

Graphics

有三种,根据需要选择合适的:
1、Canvas and Drawables:Android provides a set of View widgets that provide general functionality for a wide array of user interfaces. You can also extend these widgets to modify the way they look or behave. In addition, you can do your own custom 2D rendering using the various drawing methods contained in the Canvas class or create Drawable objects for things such as textured buttons or frame-by-frame animations.
2、Hardware Acceleration:android3.0之后即支持硬件加速
3、OpenGL:使用OpenGL ES 1.0 and 2.0, with Android framework APIs as well as natively with the Native Development Kit (NDK),Using the framework APIs is desireable when you want to add a few graphical enhancements to your application that are not supported with the Canvas APIs, or if you desire platform independence and don't demand high performance. There is a performance hit in using the framework APIs compared to the NDK, so formany graphic intensive applications such as games, using the NDK is beneficial (It is important to note though that you can still get adequate performance using the framework APIs. For example, the Google Body app is developed entirely using the framework APIs). OpenGL with the NDK is also useful if you have a lot of native code that you want to port over to Android. For more information about using the NDK, read the docs in the docs/ directory of the NDK download.
 
 
OpenGL:
Android2.2之前,OpenGL ES1.0
Android 2.2开始支持OpenGL ES2.0
android支持OpenGL有两种方式:API和NDK方式
OpenGL API有两个关健类:
GLSurfaceView:类,绘制图像的类
GLSurfaceView.Renderer:接口,定义一些能够在GLSurfaceView绘图的方法,使用该接口,需要实现的方法有:onSurfaceCreated(),onDrawFrame(),onSurfaceChanged()。使用该接口,需要单独定义一个实现该接口的类,然后使用 GLSurfaceView.setRenderer()使其关联到GLSurfaceView
onSurfaceCreated:
onDrawFrame:
onSurfaceChanged:
 
绘图映射:
opengl绘制的图放到android设备上会有一定程度的变形,所以需要经过映射修正形状。解决方法是:applyOpenGL projection modes andcamera views to transform coordinates so your graphic objects have the correct proportions on any display.
In order to apply projection and camera views, youcreate a projection matrix anda camera view matrix andapply them to the OpenGL rendering pipeline.The projection matrix recalculates the coordinates of your graphics so that they map correctly to Android device screens. Thecamera view matrix creates a transformation that renders objects from a specific eye position.
如:原图为左图,经过映射修正过的图为右图
 
 
OpenGL版本和设备兼容:
Android2.2之前,OpenGL ES1.0
Android 2.2开始支持OpenGL ES2.0
 
纹理压缩的支持
纹理压缩有很多版本,每一个设备支持的版本可能有所不同:
Run the following code on your target devices to determine what texture compression formats are supported
String extensions = javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
当然这个结果也会因设备差异。
 
选择OpenGL版本:
性能:OpenGL ES2.0比OpenGL ES1.0快
编码速度:OpenGL ES1.0上手比较快
图形控制:OpenGL ES2.0的可编程管线使得OpenGL ES2.0的对图形有更高程度的控制。
 
 

Renderscript:

Renderscript提供高性能3D图形和计算,处于native level,使用C99标准,

优点是:

  • Portability:可使用在不同处理架构的设备上(CPU, GPU, and DSP for instance) ,It supports all of these architectures without having to target each device, because the code is compiled and cached on the device at runtime.
  • Performance:Renderscript provides similar performance to OpenGL with the NDK and also provides a high performance compute API that is not offered by OpenGL.
  • Usability:Renderscript simplifies development when possible, such as eliminating JNI glue code and simplifying mesh setup.

缺点:
  • Development complexity:Renderscript introduces a new set of APIs that you have to learn,Renderscript also allocates memory differently compared to OpenGL with the Android framework APIs. 
  • Debugging visibility: debug难度加大

 

Renderscript概述:

Renderscript运行在native level,但是仍然需要与android VM通信,因此Renderscript应用程序跟纯VM应用程序不同。Renderscript平台独立。

Renderscript采用C/S结构,底层的Renderscript程序由vm中运行高层的android系统控制。android vm管理内存绑定分配给Renderscript 运行时以供Renderscript程序使用。android framework异步调用renderscript,

在使用renderscropt时,有3个层次的api为renderscript和android framework之间提供通信
1、 Renderscript runtime APIs :allow you to do the computation or graphics rendering that is required by your application.
2、The reflected layer APIs are a set of classes that are reflected from your Renderscript runtime code. It is basically a wrapper around the Renderscript code that allows the Android framework to interact with the Renderscript runtime. The Android build tools automatically generate the classes for this layer during the build process. These classes eliminate the need to write JNI glue code, like with the NDK.
3、The Android framework APIs, which include the android.renderscript package, allow you to build your application using traditional Android components such as activities and views. When using Renderscript, this layer calls the reflected layer to access the Renderscript runtime.

Renderscript Runtime Layer
renderscript 在压缩和定义好的runtime 层编译和执行。renderscript API提供密集计算和图形渲染。注释:因为NDK中的标准C函数只能运行在CPU上,因此renderscript不能访问这些库,因为renderscript会用在各种不同处理设备中。
在android工程的src/文件夹下写扩展名为.rs和.rsh 的renderscript 代码,这些代码被vm编译成中间字节码,这些字节码会作为android build的一部分。当在设备上运行时,这些字节码将会被设备上的vm重新编译成经过优化的使用于设备的机器码同时被cache,因此多次使用renderscript代码时不需要重复编译字节码。
Renderscript Runtime Libraries的特性:
图形渲染函数
内存申请
矢量和标量数学函数集合。
数据类型转换
适用于renderscript system的特有数据类型和结构,比如:Vector types for defining two-, three-, or four-vectors。
log函数。
除了renderscript graphics 头文件,renderscript 头文件会自动包含,而renderscript graphics的头文件的使用如下:
#include "rs_graphics.rsh"
更多可用函数,请参考Renderscript runtime API reference。


Reflected Layer:
Reflected Layer是一系列由android build 工具生成的类,android framework通过这些类访问renderscript runtime。这些类也提供方法和构造函数,这些方法和构造函数允许你分配和操作在renderscript code中定义的函数指针。
映射的一些主要组件包括:

每一个.rs文件被生成一个命名为ScriptC类型的 project_root/gen/package/name/ScriptC_renderscript_filename 的类。这个文件是一个与.rs文件对应的java文件,以供android framework调用。这个类包含以下内容():
1、非静态函数
2、非静态、全局 renderscript变量。每个变量有一个存取器方法(Accessor methods),因此可以从android framework读写renderscript变量。如果在renderscript runtime layer初始化全局变量,这些变量用来初始化android framework中相关的值。如果全局变量是一个常量,则就不会再有set方法。
3、全局指针


数据结构
数据结构被映射成名为 project_root/gen/package/name/ScriptField_struct_name的继承自Script.FieldBase的自有类。这个类代表这个结构的数组,这些数组允许为这些结构的实体分配空间。


函数
函数被映射成脚本类,并放在project_root/gen/package/name/ScriptC_renderscript_filename目录中,例如:如下一段renderscript代码映射成脚本类:
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 framework调用renderscript时,调用被放到队列中并适时执行。这个限制This restriction allows the Renderscript system to function without constant interruption and increases efficiency.如果允许函数有返回值,这个调用就会被中断等待返回值。如果renderscript需要传递变量到android framework,使用rsSendToClient()函数。


变量
许多类型可以映射成脚本类,脚本类路径为:project_root/gen/package/name/ScriptC_renderscript_filename,每一个变量都会有一个accessor methods,如在renderscript 代码中声明一个变量,
uint32_t unsignedInteger = 1;
对应的accessor methods是:
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>/gen/com/example/renderscript/ScriptField_struct_name,这个类代表结构的数组并允许为特定数量的结构分配内容。例如,renderscript中定义结构:
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 */);    }}
产生的这些代码的意义:The generated code is provided to you as a convenience to allocate memory for structs requested by the Renderscript runtime and to interact with structs in memory.每个结构的类定义如下的方法的构造函数:
  • Overloaded constructors that allow you to allocate memory
  • A static nested class, Item, allows you to create an instance of the struct, in the form of an object.
  • The createElement() method creates a description of the struct in memory.
  • resize() works much like a realloc() in C, allowing you to expand previously allocated memory, maintaining the current values that were previously created.
  • copyAll() synchronizes memory that was set on the framework level to the Renderscript runtime.


指针:
指针被映射成类,位置在project_root/gen/package/name/ScriptC_renderscript_filename,可以声明任何renderscript支持的类型,包括数据结构。但是数据结构不包括指针或nested array,例如:
分别定义一个数据结构的指针和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)的特殊方法。这个方法允许绑定由vm分配给renderscript runtime的内存。例如,Working with Allocated Memory
 
 
Memory Allocation APIs
使用renderscript的应用运行在vm中,但实际的renderscript 代码,运行在本地并且需要访问vm申请的内存。为了完成这个任务,需要attach vm申请的内存到renderscript runtime,这个过程被称为绑定,允许renderscript 使用但是不允许显示分配内存,绑定只用在动态内存分配。静态内存在编译renderscript的时候生成。见图1了解内存分配的过程。
 
vm有一系列API提供类似malloc函数的功能来支持这种内存分配系统。这些类描述如何分配内存以及如何实现分配。为了更好的理解,请参见malloc的例子:
array = (int *)malloc(sizeof(int)*10);
这个malloc氛围两部分,一部分声明类型,一部分声明大小,android framework类提供这两部分的映射同样也会有malloc功能的类。
Element类代表sizeof(int)
Type封装Element和数量,也可以把type理解为Element的数据
Allocation类执行实际的内存分配
 
大多数情况并不需要调用这些API来申请内存,reflected层会自动使用这些类,用户需要做的就是调用构造函数然后绑定Allocation 到renderscript。但是在一些情况下,可能会直接调用这些类,如load一个bitmap或者会基本类型指针申请内存。例子,参见Allocating and binding memory to the Renderscript部分。以下表格描述三个内存管理类。
Android Object TypeDescriptionElement

An element describes one cell of a memory allocation and can have two forms: basic or complex.

A basic element contains a single component of data of any valid Renderscript data type. Examples of basic element data types include a single float value, a float4 vector, or a single RGB-565 color.

Complex elements contain a list of basic elements and are created from structs that you declare in your Renderscript code. For instance an allocation can contain multiplestructs arranged in order in memory. Each struct is considered as its own element, rather than each data type within that struct.

Type

A type is a memory allocation template and consists of an element and one or more dimensions. It describes the layout of the memory (basically an array of Elements) but does not allocate the memory for the data that it describes.

A type consists of five dimensions: X, Y, Z, LOD (level of detail), and Faces (of a cube map). You can assign the X,Y,Z dimensions to any positive integer value within the constraints of available memory. A single dimension allocation has an X dimension of greater than zero while the Y and Z dimensions are zero to indicate not present. For example, an allocation of x=10, y=1 is considered two dimensional and x=10, y=0 is considered one dimensional. The LOD and Faces dimensions are booleans to indicate present or not present.

Allocation

An allocation provides the memory for applications based on a description of the memory that is represented by a Type. Allocated memory can exist in many memory spaces concurrently. If memory is modified in one space, you must explicitly synchronize the memory, so that it is updated in all the other spaces in which it exists.

Allocation data is uploaded in one of two primary ways: type checked and type unchecked. For simple arrays there are copyFrom() functions that take an array from the Android system and copy it to the native layer memory store. The unchecked variants allow the Android system to copy over arrays of structures because it does not support structures. For example, if there is an allocation that is an array of n floats, the data contained in a float[n] array or a byte[n*4] array can be copied.

 
 
 
Working with Memory
 
在renderscript中声明的非静态、全局变量在编译时分配内存。这样就不要android framework level分配内存。android framework layer可以使用在reflect layer layer生成的accessor methods。如果只写变量在renderscript runtimelayer初始化,则这些变量被用来初始化android framework layer的相关值。如果全局变量是常量,则就不要set method。
 
renderscript也支持指针,但是必须在android framework 中显式申请内存。当在.rs文件中声明全局指针时,在reflected layer类中为它申请空间并绑定到本地renderscript layer。You can interact with this memory from the Android framework layer as well as the Renderscript layer, which offers you the flexibility to modify variables in the most appropriate layer.
 

Allocating and binding dynamic memory to the Renderscript

常用的申请动态内存的方法是调用Script.FieldBase  类的构造函数,也可以通过手动创建Allocation。但是更为简单的方法是使用Script.FieldBase 。当申请完内存后,调用reflected layer的bind方法将内存绑定到renderscript runtime。
The example below allocates memory for both a primitive type pointer, intPointer, and a pointer to a struct, touchPoints. It also binds the memory to the Renderscript:
private RenderScriptGL glRenderer;private ScriptC_example script;private Resources resources;public void init(RenderScriptGL rs, Resources res) {    //get the rendering context and resources from the calling method    glRenderer = rs;    resources = res;    //allocate memory for the struct pointer, calling the constructor    ScriptField_Point touchPoints = new ScriptField_Point(glRenderer, 2);    //Create an element manually and allocate memory for the int pointer    intPointer = Allocation.createSized(glRenderer, Element.I32(glRenderer), 2);    //create an instance of the Renderscript, pointing it to the bytecode resource    mScript = new ScriptC_example(glRenderer, resources, R.raw.example);    //bind the struct and int pointers to the Renderscript    mScript.bind_touchPoints(touchPoints);    script.bind_intPointer(intPointer);   ...}
 
 

Reading and writing to memory

不管是在renderscript runtime 还是 android framework layer都可以读取动态/静态分配的内存。
静态内存在renderscript runtime level有一个限制。当renderscript 代码改变这个值,android framework的响应值并不改变。反之,情况不同,也即android framework的值改变一会反映到renderscript runtime中。如果要想将renderscript runtime中的值传递到android framework中,需要调用rsSendToClient来克服这个限制。
但是动态内存的处理,android framework & renderscript runtime,一个改变,另外一个也要跟着改变。这指的指针。
参见如下两个例子:

Reading and writing to global variables

Reading and writing to global variables is a straightforward process. You can use the accessor methods at the Android framework level or set them directly in the Renderscript code. Keep in mind that any changes that you make in your Renderscript code are not propagated back to the Android framework layer.

For example, given the following struct declared in a file named rsfile.rs:

typedef struct Point {    int x;    int y;} Point_t;Point_t point;

You can assign values to the struct like this directly in rsfile.rs. These values are not propagated back to the Android framework level:

point.x = 1;point.y = 1;

You can assign values to the struct at the Android framework layer like this. These values are propagated back to the Renderscript runtime level:

ScriptC_rsfile mScript;...Item i = new ScriptField_Point.Item();i.x = 1;i.y = 1;mScript.set_point(i);

You can read the values in your Renderscript code like this:

rsDebug("Printing out a Point", point.x, point.y);

You can read the values in the Android framework layer with the following code. Keep in mind that this code only returns a value if one was set at the Android framework level. You will get a null pointer exception if you only set the value at the Renderscript runtime level:

Log.i("TAGNAME", "Printing out a Point: " + mScript.get_point().x + " " + mScript.get_point().y);System.out.println(point.get_x() + " " + point.get_y());
 

Reading and writing global pointers

Assuming that memory has been allocated in the Android framework level and bound to the Renderscript runtime, you can read and write memory from the Android framework level by using the get and setmethods for that pointer. In the Renderscript runtime layer, you can read and write to memory with pointers as normal and the changes are propagated back to the Android framework layer, unlike with statically allocated memory.

For example, given the following pointer to a struct in a file named rsfile.rs:

typedef struct Point {    int x;    int y;} Point_t;Point_t *point;

Assuming you already allocated memory at the Android framework layer, you can access values in the struct as normal. Any changes you make to the struct via its pointer variable are automatically available to the Android framework layer:

point[index].x = 1;point[index].y = 1;

You can read and write values to the pointer at the Android framework layer as well:

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);

Once memory is already bound, you do not have to rebind the memory to the Renderscript runtime every time you make a change to a value。

 
 
 
 
compute

Compute API用于密集计算,在context of a graphics Renderscript 中使用,比如计算位置,也可以用于脱机计算renderscript,比如图像处理和照片编辑等。

 
 
graphics
drawing:如何在renderscript的基础上使用图形函数绘图。

Simple drawing简单的绘图:

renderscript自带的API可以方便的绘制多边形。在root函数中可以调用这些函数渲染内容到RSSurfaceView orRSTextureView
  • rsgDrawRect(): Sets up a mesh and draws a rectangle to the screen. It uses the top left vertex and bottom right vertex of the rectangle to draw.
  • rsgDrawQuad(): Sets up a mesh and draws a quadrilateral to the screen.
  • rsgDrawQuadTexCoords(): Sets up a mesh and draws a quadrilateral to the screen using the provided coordinates of a texture.
  • rsgDrawText(): Draws specified text to the screen. Use rsgFontColor() to set the color of the text.

Drawing with a mesh:

在绘制复杂场景使用mesh时,调用rsgDrawMesh。mesh是一个顶点的集合(点、法线、纹理坐标)或者索引(如何利用顶点绘制三角形或者线)的集合。有三种方式建立mesh。
  • Build the mesh with the Mesh.TriangleMeshBuilder class, which allows you to specify a set of vertices and indices for each triangle that you want to draw.
  • Build the mesh using an Allocation or a set of Allocations with the Mesh.AllocationBuilder class. This approach allows you to build a mesh with vertices already stored in memory, which allows you to specify the vertices in Renderscript or Android framework code.
  • Build the mesh with the Mesh.Builder class. You should use this convenience method when you know the data types you want to use to build your mesh, but don't want to make separate memory allocations like with Mesh.AllocationBuilder. You can specify the types that you want and this mesh builder automatically creates the memory allocations for you.
使用 Mesh.TriangleMeshBuilder创建mesh,需要提供构成三角形的顶点和索引。For example, the following code specifies three vertices, which are added to an internal array, indexed in the order they were added. The call to addTriangle() draws the triangle with vertex 0, 1, and 2 (the vertices are drawn counter-clockwise).
int float2VtxSize = 2;Mesh.TriangleMeshBuilder triangles = new Mesh.TriangleMeshBuilder(renderscriptGL,float2VtxSize, Mesh.TriangleMeshBuilder.COLOR);triangles.addVertex(300.f, 300.f);triangles.addVertex(150.f, 450.f);triangles.addVertex(450.f, 450.f);triangles.addTriangle(0 , 1, 2);Mesh smP = triangle.create(true);script.set_mesh(smP);
使用 Mesh.AllocationBuilder创建mesh,
you need to supply it with one or more allocations that contain the vertex data:
Allocation vertices;...Mesh.AllocationBuilder triangle = new Mesh.AllocationBuilder(mRS);smb.addVertexAllocation(vertices.getAllocation());smb.addIndexSetType(Mesh.Primitive.TRIANGLE);Mesh smP = smb.create();script.set_mesh(smP);

In your Renderscript code, draw the built mesh to the screen:

rs_mesh mesh;...int root(){...rsgDrawMesh(mesh);...return 0; //specify a non zero, positive integer to specify the frame refresh.          //0 refreshes the frame only when the mesh changes.}
 
Programs
可以把四个程序对象关联到RenderScriptGL内容去定制化渲染管道。例如:可以使用GLSL创建顶点和片段着色器或者build a raster program object that controls culling.
四个程序对象对应着传统的图形渲染管线:
Android Object TypeRenderscript Native TypeDescription
ProgramVertex
 
rs_program_vertex

The Renderscript vertex program, also known as a vertex shader, describes the stage in the graphics pipeline responsible for manipulating geometric data in a user-defined way. The object is constructed by providing Renderscript with the following data:

  • An Element describing its varying inputs or attributes
  • GLSL shader string that defines the body of the program
  • Type that describes the layout of an Allocation containing constant or uniform inputs

Once the program is created, bind it to the RenderScriptGL graphics context by calling bindProgramVertex(). It is then used for all subsequent draw calls until you bind a new program. If the program has constant inputs, the user needs to bind an allocation containing those inputs. The allocation's type must match the one provided during creation.

The Renderscript runtime then does all the necessary plumbing to send those constants to the graphics hardware. Varying inputs to the shader, such as position, normal, and texture coordinates are matched by name between the input Element and the mesh object that is being drawn. The signatures don't have to be exact or in any strict order. As long as the input name in the shader matches a channel name and size available on the mesh, the Renderscript runtime handles connecting the two. Unlike OpenGL there is no need to link the vertex and fragment programs.

To bind shader constants to the program, declare a struct that contains the necessary shader constants in your Renderscript code. This struct is generated into a reflected class that you can use as a constant input element during the program's creation. It is an easy way to create an instance of this struct as an allocation. You would then bind this Allocation to the program and the Renderscript runtime sends the data that is contained in thestruct to the hardware when necessary. To update shader constants, you change the values in the Allocation and notify the Renderscript code of the change.

The ProgramVertexFixedFunction.Builder class also lets you build a simple vertex shader without writing GLSL code.

ProgramFragmentrs_program_fragment

The Renderscript fragment program, also known as a fragment shader, is responsible for manipulating pixel data in a user-defined way. It's constructed from a GLSL shader string containing the program body, texture inputs, and a Type object that describes the constants used by the program. Like the vertex programs, when an Allocation with constant input values is bound to the shader, its values are sent to the graphics program automatically. Note that the values inside the Allocation are not explicitly tracked. If they change between two draw calls using the same program object, notify the runtime of that change by calling rsgAllocationSyncAll(), so it can send the new values to hardware. Communication between the vertex and fragment programs is handled internally in the GLSL code. For example, if the fragment program is expecting a varying input called varTex0, the GLSL code inside the program vertex must provide it.

To bind shader constructs to the program, declare a struct that contains the necessary shader constants in your Renderscript code. This struct is generated into a reflected class that you can use as a constant input element during the program's creation. It is an easy way to create an instance of this struct as an allocation. You would then bind this Allocation to the program and the Renderscript runtime sends the data that is contained in thestruct to the hardware when necessary. To update shader constants, you change the values in the Allocation and notify the Renderscript code of the change.

The ProgramFragmentFixedFunction.Builder class also lets you build a simple fragment shader without writing GLSL code.

ProgramStorers_program_storeThe Renderscript store program contains a set of parameters that control how the graphics hardware writes to the framebuffer. It could be used to enable and disable depth writes and testing, setup various blending modes for effects like transparency and define write masks for color components.ProgramRasterrs_program_rasterThe Renderscript raster program is primarily used to specify whether point sprites are enabled and to control the culling mode. By default back faces are culled.
The following example defines a vertex shader in GLSL and binds it to a Renderscript context object:
private RenderScriptGL glRenderer;      //rendering context    private ScriptField_Point mPoints;      //vertices    private ScriptField_VpConsts mVpConsts; //shader constants    ...     ProgramVertex.Builder sb = new ProgramVertex.Builder(glRenderer);        String t =  "varying vec4 varColor;\n" +                    "void main() {\n" +                    "  vec4 pos = vec4(0.0, 0.0, 0.0, 1.0);\n" +                    "  pos.xy = ATTRIB_position;\n" +                    "  gl_Position = UNI_MVP * pos;\n" +                    "  varColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +                    "  gl_PointSize = ATTRIB_size;\n" +                    "}\n";        sb.setShader(t);        sb.addConstant(mVpConsts.getType());        sb.addInput(mPoints.getElement());        ProgramVertex pvs = sb.create();        pvs.bindConstants(mVpConsts.getAllocation(), 0);        glRenderer.bindProgramVertex(pvs);

The RsRenderStatesRS sample has many examples on how to create a shader without writing GLSL.

 

Rendering to a Framebuffer Object:渲染到framebuffer对象,framebuffer用在存放即将渲染到屏幕上的数据信息,一个framebuffer对象有两个缓冲区:颜色缓冲区和深度缓冲区。

一般情况下,渲染到framebuffer需要做的事情:

1、为颜色缓冲区和深度缓冲区创建Allocation 对象,然后具体化它们的USAGE_GRAPHICS_RENDER_TARGET属性,以通知renderscript runtime 的framebuffer对象使用它们。对于颜色缓冲区,必须声明 USAGE_GRAPHICS_TEXTURE 属性来使用颜色缓冲区作为纹理,这是framebuffer对象的常用法。

2、通过调用rsgBindColorTarget来通知renderscript runtime使用渲染到framebuffer对象来代替其默认的framebuffer,同时传递颜色缓冲区Allocation。适当的时候,深度缓冲区也需要这么做,但是需要调用rsgBindDepthTarget而不是rsgBindColorTarget。

3、一般使用rsgDraw函数渲染场景,这些场景会被渲染到颜色缓冲区而不是默认直接显示到屏幕上。

4、当完成第3步的时候,告诉renderscript runtime停止渲染到颜色缓冲区而恢复到渲染默认缓冲区通过调用rsgClearAllRenderTargets。

5、创建片段着色器并将其作为纹理绑定到颜色缓冲区。

6、渲染场景到默认的framebuffer。根据setup片段着色器的方式使用这些纹理。

例子FountainFBO是通过修改Fountain 这个例子来展示如何渲染到framebuffer对象。二者的不同之处是,同样的场景,一个是渲染到默认的framebuffer,一个是渲染到framebuffer对象。

  1. Modify fountain.rs and add the following global variables. This creates setter methods when this file is reflected into a .java file, allowing you to allocate memory in your Android framework code and binding it to the Renderscript runtime.
    //allocation for color bufferrs_allocation gColorBuffer;//fragment shader for rendering without a texture (used for rendering to framebuffer object)rs_program_fragment gProgramFragment;//fragment shader for rendering with a texture (used for rendering to default framebuffer)rs_program_fragment gTextureProgramFragment;
  2. Modify the root function of fountain.rs to look like the following code. The modifications are commented:
    int root() {    float dt = min(rsGetDt(), 0.1f);    rsgClearColor(0.f, 0.f, 0.f, 1.f);    const float height = rsgGetHeight();    const int size = rsAllocationGetDimX(rsGetAllocation(point));    float dy2 = dt * (10.f);    Point_t * p = point;    for (int ct=0; ct < size; ct++) {        p->delta.y += dy2;        p->position += p->delta;        if ((p->position.y > height) && (p->delta.y > 0)) {            p->delta.y *= -0.3f;        }        p++;    }    //Tell Renderscript runtime to render to the frame buffer object    rsgBindColorTarget(gColorBuffer, 0);    //Begin rendering on a white background    rsgClearColor(1.f, 1.f, 1.f, 1.f);    rsgDrawMesh(partMesh);    //When done, tell Renderscript runtime to stop rendering to framebuffer object    rsgClearAllRenderTargets();    //Bind a new fragment shader that declares the framebuffer object to be used as a texture    rsgBindProgramFragment(gTextureProgramFragment);    //Bind the framebuffer object to the fragment shader at slot 0 as a texture    rsgBindTexture(gTextureProgramFragment, 0, gColorBuffer);    //Draw a quad using the framebuffer object as the texture    float startX = 10, startY = 10;    float s = 256;    rsgDrawQuadTexCoords(startX, startY, 0, 0, 1,                         startX, startY + s, 0, 0, 0,                         startX + s, startY + s, 0, 1, 0,                         startX + s, startY, 0, 1, 1);    //Rebind the original fragment shader to render as normal    rsgBindProgramFragment(gProgramFragment);    //Render the main scene    rsgDrawMesh(partMesh);    return 1;}
  3. In the FountainRS.java file, modify the init() method to look like the following code. The modifications are commented:
    /* Add necessary members */private ScriptC_fountainfbo mScript;private Allocation mColorBuffer;private ProgramFragment mProgramFragment;private ProgramFragment mTextureProgramFragment;public void init(RenderScriptGL rs, Resources res) {    mRS = rs;    mRes = res;    ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);    Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);    smb.addVertexAllocation(points.getAllocation());    smb.addIndexSetType(Mesh.Primitive.POINT);    Mesh sm = smb.create();    mScript = new ScriptC_fountainfbo(mRS, mRes, R.raw.fountainfbo);    mScript.set_partMesh(sm);    mScript.bind_point(points);    ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);    pfb.setVaryingColor(true);    mProgramFragment = pfb.create();    mScript.set_gProgramFragment(mProgramFragment);    /* Second fragment shader to use a texture (framebuffer object) to draw with */    pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,        ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);    /* Set the fragment shader in the Renderscript runtime */    mTextureProgramFragment = pfb.create();    mScript.set_gTextureProgramFragment(mTextureProgramFragment);    /* Create the allocation for the color buffer */    Type.Builder colorBuilder = new Type.Builder(mRS, Element.RGBA_8888(mRS));    colorBuilder.setX(256).setY(256);    mColorBuffer = Allocation.createTyped(mRS, colorBuilder.create(),    Allocation.USAGE_GRAPHICS_TEXTURE |    Allocation.USAGE_GRAPHICS_RENDER_TARGET);    /* Set the allocation in the Renderscript runtime */    mScript.set_gColorBuffer(mColorBuffer);    mRS.bindRootScript(mScript);}

    Note: This sample doesn't use a depth buffer, but the following code shows you how to declare an example depth buffer if you need to use one for your application. The depth buffer must have the same dimensions as the color buffer:

    Allocation mDepthBuffer;...Type.Builder b = new Type.Builder(mRS, Element.createPixel(mRS, DataType.UNSIGNED_16,    DataKind.PIXEL_DEPTH));b.setX(256).setY(256);mDepthBuffer = Allocation.createTyped(mRS, b.create(),Allocation.USAGE_GRAPHICS_RENDER_TARGET);

  4. Run and use the sample. The smaller, white quad on the top-left corner is using the framebuffer object as a texture, which renders the same scene as the main rendering.