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回計測して処理時間の平均を算出してみました。
平均的に1024x128程度の転送が発生するのであれば、copyPixelsToBufferのコストを考えたとしても、GL10の方が二倍程度性能が改善します。逆に、1024x1024の転送が発生する場合は、性能が悪化します。GL10.texSubImage2Dは転送サイズに応じてほぼリニアにパフォーマンスが低下していくので、転送高さ512程度でGLUtilsの方が有利になりそうです。ということで、動的にフォントを転送する場合はGL10.texSubImage2Dが良さそうです。
気になるのは、Tegra2だけGLUtilsが遅すぎることです。Adreno200でGLUtilsの方がGL10より良いのはByteBufferの転送コストで大体理解できるのですが、Tegra2は謎ですね。
この最適化によって、現在のJavaScript&Native Bridgeゲームエンジンの1フレームは次のようなパフォーマンスになっています。

大分速くなってきました。後はjavascriptから受け取ったコマンドリストのsplitを何とか高速化できればいいんですが。
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回計測して処理時間の平均を算出してみました。
VDP | GLUtils.texSubImage2D(1024x1024) | copyPixelsToBuffer(1024x1024) | GL10.texSubImage2D(1024x1024) | GL10.texSubImage2D(1024x128) |
Tegra2(Xoom) | 20.985ms | 1.815ms | 8.305ms | 1.1ms |
Adreno200(NexusOne) | 12.695ms | 5.67ms | 15.02ms | 1.03ms |
Adreno205(XperiaArc) | 3.775ms | 1.695ms | 3.415ms | 0.525ms |
powerVR(galaxy) | 7.815ms | 2.61ms | 8.145ms | 1.255ms |
平均的に1024x128程度の転送が発生するのであれば、copyPixelsToBufferのコストを考えたとしても、GL10の方が二倍程度性能が改善します。逆に、1024x1024の転送が発生する場合は、性能が悪化します。GL10.texSubImage2Dは転送サイズに応じてほぼリニアにパフォーマンスが低下していくので、転送高さ512程度でGLUtilsの方が有利になりそうです。ということで、動的にフォントを転送する場合はGL10.texSubImage2Dが良さそうです。
気になるのは、Tegra2だけGLUtilsが遅すぎることです。Adreno200でGLUtilsの方がGL10より良いのはByteBufferの転送コストで大体理解できるのですが、Tegra2は謎ですね。
この最適化によって、現在のJavaScript&Native Bridgeゲームエンジンの1フレームは次のようなパフォーマンスになっています。

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