Android 3.0 Honeycomb (API Level 11) から RenderScript が
使えるようになりました。
ハードウエア機能を用いた高速な描画を行うための仕組みです。
これまでも Java + OpenGL ES とか NDK + OpenGL ES など、ハードウエア
機能を活用できる描画手段がありました。
RenderScript は全く新しい描画のためのフレームワークとなっています。
RenderScript の特徴は、NDK のように Cコンパイラによる高速動作が
可能なこと。そして NDK と違い CPU アーキテクチャに依存しないので、
生成したバイナリの互換性が保たれることです。
また開発環境も統合されており Eclipse 上でビルド可能です。
同時に Java からアクセスするための Reflected layer class も作られます。
RenderScript から扱う描画 API は OpenGL ES の上位に位置し、
リソースの扱いなど簡略化されています。
欠点としては以下のとおり。
・Android の中でしか使えない
NDK(C/C++) + OpenGL ES 2.0 の利点はソースコードの汎用性が非常に
高いことです。NDK は Windows, Linux, iOS 等とソースを共有可能ですが
RenderScript は今のところ Android 環境でしか使えません。
・描画 API
描画 API は OpenGL ES をカプセル化したもので、OpenGL の全機能が
そのまま使えるわけではないようです。
・ドキュメントが少ない
サンプルソースを見ないとわからない仕様がいろいろあります。
描画なしの簡単なコードを走らせてみます。
// simple.rs #pragma version(1) #pragma rs java_package_name(jp.flatlib.ap02) #include "rs_cl.rsh" void root( const float* vin, float* vout ) { *vout= *vin * 2.0f; } float* istream; float* ostream; rs_script script; void run() { rsForEach( script, rsGetAllocation( istream ), rsGetAllocation( ostream ), 0 ); }
RenderScript のエントリ関数は root() です。
run() の中の rsForEach() は第一引数で与えられた script をデータの数だけ
呼び出します。与えた script の中の root() 関数が呼ばれるわけです。
ソースツリーに入れると simple.rs はバイトコードにコンパイルされ、
同時に class ScriptC_simple が作られます。
// java ScriptC_simple script= new ScriptC_simple( rs, res, R.raw.simple );
この class には global 変数へのアクセスや関数呼び出しのエントリも
含まれています。
上のコードの run() の呼び出しは script.invoke_run() です。
class ScriptC_ファイル名 Script そのもの class ScriptFiled_構造体名 中で宣言した構造体 R.raw.ファイル名 バイトコードのリソース名 invoke_関数名() 関数呼び出し set_変数() global 変数への書き込み get_変数() 前回 set した値を参照 bind_ポインタ() データ領域の割り当て
実際に呼び出してみます。
演算するためのバッファ (Allocation) を float * 100 個分作成し、
istream/ostream に bind します。
// java public void rstest( Context context ) { RenderScript rs= RenderScript.create( context ); ScriptC_simple script= new ScriptC_simple( rs, context.getResources(), R.raw.simple ); // メモリ領域の作成 float x 100 Allocation a_in= Allocation.createSized( rs, Element.F32(rs), 100, Allocation.USAGE_SCRIPT ); Allocation a_out= Allocation.createSized( rs, Element.F32(rs), 100, Allocation.USAGE_SCRIPT ); // global 変数に書き込み script.bind_istream( a_in ); script.bind_ostream( a_out ); script.set_script( script ); // 実行 script.invoke_run(); }
初期値を渡して RenderScript で実行した演算結果を受け取ってみます。
// java public void rstest( Context context ) { RenderScript rs= RenderScript.create( context ); Resources res= context.getResources(); // script ScriptC_simple script= new ScriptC_simple( rs, res, R.raw.simple ); // メモリ領域の作成 float x 100 Allocation a_in= Allocation.createSized( rs, Element.F32(rs), 100, Allocation.USAGE_SCRIPT ); Allocation a_out= Allocation.createSized( rs, Element.F32(rs), 100, Allocation.USAGE_SCRIPT ); // 初期値を書き込む float[] srcbuf= new float[100]; for( int i= 0 ; i< 100 ; i++ ){ srcbuf[i]= i; } a_in.copyFrom( srcbuf ); // global 変数に書き込み script.bind_istream( a_in ); script.bind_ostream( a_out ); script.set_script( script ); // 実行 script.invoke_run(); // 結果を受け取る float[] destbuf= new float[100]; a_out.copyTo( destbuf ); for( int i= 0 ; i< 100 ; i++ ){ Log.i( "rs", "a_out=" + destbuf[i] ); } }
RenderScript の問題など
先日 OS 4.0 対応 SDK r14 がリリースされたばかりですが、バグ修正のため
r15 が出ています。
API Level 13 以前の RenderScript project が動かなかった問題が修正され
たようです。これで Android 3.0 向け Sample も動くようになりました。
*.rs をビルドすると class を生成しますが、このソース中に元ファイルの
パスを埋め込んでしまいます。
Windows の場合パスの区切りが '\' なので、u で始まるフォルダ名が
あると不正な unicode とみなされエラーとなります。
例えば C:\home\users の '\u' 等。
取り敢えず生成されたソースのエラー行を削除すればコンパイルできます。
script を更新したあと実行時にエラーが出る場合は Project を一旦
clean してリビルドした方が良いかもしれません。