日別アーカイブ: 2011年11月2日

Android 3.x RenderScript (2) 描画と Allocation

RenderScript には Compute 用と Graphics 用の 2種類あります。
前回のサンプルは Compute 用です。
下記のように root 関数の宣言が異なります。

Compute :    void  root( const T* input, T* output )
Graphics:    int   root()

・Compute
 ForEach 命令によりデータの数だけ root() が呼ばれる。
 Shader のような実行方法。

・Graphics
 RSSurfaceView を使い bindRootScript() で登録すると毎フレーム
 root() が呼ばれる。
 1フレーム分の描画セットアップコードを記述できる。

RenderScript にはいくつか組み込まれた描画命令があります。
内蔵の固定シェーダーを用いて描画を行なっているようです。
簡単に描画できる反面、大量に描画する用途には向いていません。
デバッグやテスト時には便利そうです。使ってみます。

特に何もしない Activity。SimpleView を呼び出しているだけ。

// SimpleActivity.java
package jp.flatlib.ap02;

import android.app.Activity;
import android.os.Bundle;

public class SimpleActivity extends Activity {
    private SimpleView  mSimpleView= null;

    @Override
    public void onCreate( Bundle savedInstanceState ) {
        super.onCreate( savedInstanceState );
        mSimpleView= new SimpleView( this );
        setContentView( mSimpleView );
    }

    @Override
    protected void onPause() {
        super.onPause();
        mSimpleView.pause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mSimpleView.resume();
    }
}

View では RSSurfaceView を使い renderloop.rs を bind します。
これで renderloop.rs の root() が呼ばれるようになります。

// SimpleView.java
package jp.flatlib.ap02;

import android.content.Context;
import android.content.res.Resources;
import android.renderscript.RSSurfaceView;
import android.renderscript.RenderScriptGL;

public class SimpleView extends RSSurfaceView {
    private RenderScriptGL      mRS;
    private ScriptC_renderloop  mScript;

    public SimpleView( Context context ) {
        super( context );
        initRS();
    }

    private void initRS() {
        if( mRS != null ){
            return;
        }
        // RenderScriptGL を作る
        RenderScriptGL.SurfaceConfig    sc= new RenderScriptGL.SurfaceConfig();
        mRS= createRenderScriptGL( sc );

        Resources res= getContext().getResources();

        // renderloop.rs を登録する
        mScript= new ScriptC_renderloop( mRS, res, R.raw.renderloop );
        mRS.bindRootScript( mScript );
    }

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        initRS();
    }

    @Override
    public void onDetachedFromWindow() {
        if( mRS != null ){
            mRS= null;
            destroyRenderScriptGL();
        }
    }
}

Graphics 用 RenderScript では 1フレーム分の描画命令を記述します。
戻り値は描画の更新間隔です。msec

// renderloop.rs
#pragma version(1)
#pragma rs java_package_name(jp.flatlib.ap02)

#include    "rs_graphics.rsh"

int root()
{
    // 背景クリア
    rsgClearColor( 1.0f, 0.5f, 0.0f, 0.0f );

    // 塗りつぶし四角形描画
    rsgDrawRect( 100.0f, 200.0f, 150.0f, 250.0f, 0.0f );

    // 文字列描画
    rsgFontColor( 1.0f, 1.0f, 1.0f, 1.0f );
    rsgDrawText( "RenderScript test", 50.0f, 50.0f );

    return  33; // 30fps
}

任意メッシュを使った描画、GLSL シェーダーの利用、RenderScript による
動的な頂点生成を行うにはもう少し複雑な初期化手順が必要となります。

その前に RenderScript のメモリについて整理します。

● Allocation

Allocation は RenderScript が扱うメモリ確保します。
Java のメモリを直接触ることは出来ず、転送には専用の命令が必要です。

(1) Java Heap        Java
(2) Native Heap      RenderScript
(3) GPU Resource     GPU

Allocation は (2)/(3) の両方を管理します。
Allocation で確保したメモリは RenderScript でアクセスでき、
GPU Resource としてマップすることが可能です。
任意のタイミングで HW への転送や同期が行われます。

GPU ハードウエアリソースにマップする場合は確保時に USAGE フラグで
用途を指定します。
この指定方法は Direct3D API に非常によく似ています。名称も。

Allocation.USAGE_GRAPHICS_CONSTANTS      Uniform
Allocation.USAGE_GRAPHICS_RENDER_TARGET  (Android 4.0 API Lv14 以上で対応)
Allocation.USAGE_GRAPHICS_TEXTURE        Texture
Allocation.USAGE_GRAPHICS_VERTEX         Buffer (Vertex/Index)
Allocation.USAGE_SCRIPT                  Script

(1) から (2)/(3) への転送は容易ですが逆方向は簡単ではありません。

● Element と Type

Shader 等 GPU がアクセスするリソースのフォーマットを指定します。

Element     頂点フォーマット、ピクセルフォーマット等
Type        Element の配列。Uniform や Texture の構造を定義

Element は構造体の定義です。
データ型とメンバ変数名の組み合わせでできています。
例えば RGBA8888 256×26 の 2D テクスチャは、I8_4 の Basic Element が
256×256 の 2次元に並んだ構造として Type で表現できます。

● Element/Type Reflection

render.rs の中で、下記のように構造体として頂点フォーマットを定義すると
自動的に class ScriptFiled_VertexType が作られます。

// render.rs
typedef struct VertexType {
	float3	position;
	float3	normal;
	float2	texcoord;
} VertexType_t;

VertexType_t*	VertexType_n; // unuse

(VertexType_n はダミーです。何らかの参照がないと class が作られないため。)

この場合の Element のイメージは↓こんな感じ。

Element:
   F32_3  "position"
   F32_3  "normal"
   F32_2  "texcoord"

ScriptFiled_VertexType の中では構造に従った Element や Type が生成される
ので、これを使って GPU 用のメモリを Allocation することができます。

ScriptFiled_VertexType  vtype= new ScriptFiled_VertexType( rs, 100 );
Element     element= vtype.getElement(); // Element の参照
Allocation  vbuffer= Allocation.createTyped( rs, vtype.getType(), Allocation.USAGE_GRAPHICS_VERTEX ); // Type を使った確保

ScriptFiled_VertexType は中で Allocation を作ってくれるので↓これで OK

ScriptFiled_VertexType  vtype= new ScriptFiled_VertexType( rs, 100, Allocation.USAGE_GRAPHICS_VERTEX );
Allocation vbuffer= vtype.getAllocation();

続きます 「Android 3.x RenderScript (3) 独自シェーダーの割り当てとメッシュの描画(2D)」

関連エントリ
Android 3.x RenderScript (1)