GLUtils.texSubImage2Dは転送サイズを指定できないという問題があります。ラップされていないGL10.glTexSubImage2Dは転送サイズを指定できるので、GLUtilsを使わずにGL10のglTexSubImage2Dを使うことで高速化できないかを考えてみました。

GLUtilsでは、bmpを与えて、
 GLUtils.texSubImage2D(GL10.GL_TEXTURE_2D, 0, 0, 0, m_texture.image);
のようにテクスチャを上書きします。

GL10.glTexSubImage2Dでは、ByteBufferを引数に与える必要があるため、
 private ByteBuffer m_byte_buffer;
 m_byte_buffer=ByteBuffer.allocate(TEXTURE_SIZE*TEXTURE_SIZE);

 m_byte_buffer.position(0);
 m_texture.image.copyPixelsToBuffer(m_byte_buffer);
として、bmpからByteバッファに転送します。

その後、
 m_byte_buffer.position(0);
 gl.glTexSubImage2D(GL10.GL_TEXTURE_2D, 0, 0, 0, TEXTURE_SIZE,height, GL10.GL_ALPHA,GL10.GL_UNSIGNED_BYTE, m_byte_buffer);
として転送を行います。

GL10ではheightが指定できるのがポイントです。つまり、
 GLUtil:1024x1024のVRAMへの転送
 GL10の場合:1024x1024のCPU RAMへの転送+1024xheightのVRAMの転送
のどちらが早いかという話になります。

一般にVRAMへの転送はかなりコストが大きいため、フォント描画などheightが動的に変わるような用途では、GL10の方を使った方が効率的になるのではないかと考えられます。

ということで、メトセラの街の画面で200回計測して処理時間の平均を算出してみました。

VDPGLUtils.texSubImage2D(1024x1024)copyPixelsToBuffer(1024x1024)GL10.texSubImage2D(1024x1024)GL10.texSubImage2D(1024x128)
Tegra2(Xoom)20.985ms1.815ms8.305ms1.1ms
Adreno200(NexusOne)12.695ms5.67ms15.02ms1.03ms
Adreno205(XperiaArc)3.775ms1.695ms3.415ms0.525ms
powerVR(galaxy)7.815ms2.61ms8.145ms1.255ms


平均的に1024x128程度の転送が発生するのであれば、copyPixelsToBufferのコストを考えたとしても、GL10の方が二倍程度性能が改善します。逆に、1024x1024の転送が発生する場合は、性能が悪化します。GL10.texSubImage2Dは転送サイズに応じてほぼリニアにパフォーマンスが低下していくので、転送高さ512程度でGLUtilsの方が有利になりそうです。ということで、動的にフォントを転送する場合はGL10.texSubImage2Dが良さそうです。

気になるのは、Tegra2だけGLUtilsが遅すぎることです。Adreno200でGLUtilsの方がGL10より良いのはByteBufferの転送コストで大体理解できるのですが、Tegra2は謎ですね。

この最適化によって、現在のJavaScript&Native Bridgeゲームエンジンの1フレームは次のようなパフォーマンスになっています。

a


大分速くなってきました。後はjavascriptから受け取ったコマンドリストのsplitを何とか高速化できればいいんですが。