2011/11/01
Android 3.x RenderScript (1)
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 の全機能が
そのまま使えるわけではないようです。
・ドキュメントが少ない
サンプルソースを見ないとわからない仕様がいろいろあります。
描画なしの簡単なコードを走らせてみます。
RenderScript のエントリ関数は root() です。
run() の中の rsForEach() は第一引数で与えられた script をデータの数だけ
呼び出します。与えた script の中の root() 関数が呼ばれるわけです。
ソースツリーに入れると simple.rs はバイトコードにコンパイルされ、
同時に class ScriptC_simple が作られます。
この class には global 変数へのアクセスや関数呼び出しのエントリも
含まれています。
上のコードの run() の呼び出しは script.invoke_run() です。
実際に呼び出してみます。
演算するためのバッファ (Allocation) を float * 100 個分作成し、
istream/ostream に bind します。
初期値を渡して RenderScript で実行した演算結果を受け取ってみます。
RenderScript の問題など
先日 OS 4.0 対応 SDK r14 がリリースされたばかりですが、バグ修正のため
r15 が出ています。
API Level 13 以前の RenderScript project が動かなかった問題が修正され
たようです。これで Android 3.0 向け Sample も動くようになりました。
・Download the Android SDK
*.rs をビルドすると class を生成しますが、このソース中に元ファイルの
パスを埋め込んでしまいます。
Windows の場合パスの区切りが '\' なので、u で始まるフォルダ名が
あると不正な unicode とみなされエラーとなります。
例えば C:\home\users の '\u' 等。
取り敢えず生成されたソースのエラー行を削除すればコンパイルできます。
script を更新したあと実行時にエラーが出る場合は Project を一旦
clean してリビルドした方が良いかもしれません。
続きます 「Android 3.x RenderScript (2) 描画と Allocation」
使えるようになりました。
ハードウエア機能を用いた高速な描画を行うための仕組みです。
これまでも 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 も動くようになりました。
・Download the Android SDK
*.rs をビルドすると class を生成しますが、このソース中に元ファイルの
パスを埋め込んでしまいます。
Windows の場合パスの区切りが '\' なので、u で始まるフォルダ名が
あると不正な unicode とみなされエラーとなります。
例えば C:\home\users の '\u' 等。
取り敢えず生成されたソースのエラー行を削除すればコンパイルできます。
script を更新したあと実行時にエラーが出る場合は Project を一旦
clean してリビルドした方が良いかもしれません。
続きます 「Android 3.x RenderScript (2) 描画と Allocation」