« RenderScript で画像の拡大-ニアレストネイバー | メイン | メモリの断片化によるメモリ確保失敗に関して »

2015年06月10日

吉里吉里Z モバイル開発:: EGLImageKHR を使うテクスチャの高速書き換えはハードル高い

    

glTexSubImage2D でのテクスチャ書き換えは遅いから、EGLImageKHR を使って書き換えると速いと言うのを見るが、ややハードルが高い。
Using direct textures on Android が良く引用されている。

GraphicBuffer クラスは公開されていないので、libui.so を dlopen して、dlsym で各種メンバ関数を取得して、それを使う必要がある。
メンバ関数はマングリングされているので、_ZN7android13GraphicBufferC1Ejjij などの名前を使う必要がある。
コンストラクタを呼び出す前にオブジェクトのメモリを確保しないといけないが、これはある程度大きめのサイズで確保して渡すと言う方法がとられている。
この辺りトリッキーだけど、まあ GraphicBuffer が巨大化せずメンバ関数が取得できればそれほど問題なく動くので何とかなる。

eglCreateImageKHR、eglDestroyImageKHR、glEGLImageTargetTexture2DOES は、eglGetProcAddress を使って関数ポインタを取得できる。
これは OpenGL ES の拡張機能と同じだからそれほど問題ではない。
EGL_EXTENSIONS に EGL_KHR_image_base と EGL_KHR_gl_texture_2D_image が、GL_EXTENSIONS に GL_OES_EGL_image があれば行けるっぽい。

問題は、画像の stride がわからないこと。
eglQuerySurface(eglDisplayHandle, eglImageHandle, EGL_BITMAP_PITCH_KHR, &BitmapPitch); で取得できるのかと思いきや、渡した EGLImageKHR が BAD SURFACE とエラーが出て取得できない。
stride は、画像幅×ピクセルフォーマットからわかる画素サイズで計算して、特にパディングなどされていないものとして処理してうまく行く環境もあるようなので、そのようにする。

基本的には、上記のような問題点があるが動く。
xperia acro HD だと特に問題なかった。
Nexus 5 だと、stride がおかしいのか画像が壊れる。
少し古い機種だとうまく行くのかもしれない。

機種によっては、テクスチャにバインド済みだとロックが失敗するようなので、ダブルバッファリングして切り替える必要があるようだ。
また、GraphicBuffer で生成できる数が少ない環境もあるようなので、画面と対応するテクスチャ1枚だけにするなどした方が良いようだ。
Firefox では、ホワイトリストを使用して期待通り動作する機種を限定しているよう。

以上のことを考えると、使うのは厳しそう。
様々な機種でテスト出来て、ホワイトリストが充実させられるのなら何とかなりそうではあるけど。
後、4.3 以降で OpenGL ES3.0 に対応しているのなら PBO を使えるので、それ以前の端末と言うことになるので、少しは限定される。
とは言っても、現実的には ANativeWindow_setBuffersGeometry / ANativeWindow_lock を使う方がいいかな?
速度的な部分はまだ計っていないけれども。


投稿者 Takenori : 2015年06月10日 15:45




comments powered by Disqus
Total : Today : Yesterday : なかのひと