9

レンダラーのプロファイリングを試みていますが、説明できない奇妙なプロファイリング動作が見られます。

継続的にレンダリングするように設定したglSurfaceViewを使用しています。

これが私のonDrawFrame()構造です

public void onDrawFrame(GL10 unused) {
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    executeAllDrawCommands();
}

これは軽負荷でゆっくりと動作していたので、タイマークラスを作成し、これをプロファイルし始めました。私は自分が見たものにかなり驚いた。

次のように、onDrawFrameメソッドにいくつかのプローブを配置します。

public void onDrawFrame(GL10 unused) {
   swapTimer.end();

   clearTimer.start();
     GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
   clearTimer.end();

   drawTimer.start();
     executeAllDrawCommands();
   drawTimer.end();

   swapTimer.start();
}

clearTimerglClearの呼び出しにかかる時間をdrawTimer測定し、すべての描画呼び出しの実行にかかる時間をswapTimer測定し、onDrawFrameが終了してから戻るまでの時間(eglSwapBuffersの呼び出しにかかる時間)を測定します。

非常に軽い負荷のシーンを実行したとき、説明できない非常に奇妙な数字がいくつか表示されました。

swapTimer  : 20ms (average)
clearTimer : 11ms (average)
drawTimer  :  2ms (average)

実際の「クリア」呼び出しが11ミリ秒ブロックされている理由はわかりませんが、デバイスのvsyncが約30 fpsで強制的に有効になっていると思われるため、スワップ時間はやや長いと予想しました。非同期コマンドを発行して戻ることになっていると思いましたか?

もっと忙しいシーンを描くと、数字はかなり変わります。

swapTimer  :  2ms (average)
clearTimer :  0ms (average)
drawTimer  : 44ms (average)

このシーンでは、描画呼び出しに時間がかかりすぎて、vsync期間の多くが隠れているように見え、クリア呼び出しのブロックが完全になくなります。

負荷の軽いシーンでglClearがブロックされている理由について何か説明はありますか?

誰かが私の測定技術に疑いを持っている場合に備えて、私の「タイマー」クラスのソースコードへのリンク:http://pastebin.com/bhXt368W

4

1 に答える 1

11

glFinish(およびその周りにfinishTimer.start()/ end())を配置すると、glClearからずっと時間がかかります。代わりに、glFinishは数ミリ秒かかり、glClearは瞬時になります。

なるほどね。

シーンが非常に明るく、描画が非常に高速にレンダリングされる場合、ピクセルをクリアして新しい色で塗りつぶすのに時間がかかります(常に時間がかかります。そうしないと、レンダラーが遅れて、現在新しいものを描画しています)。新しいAndroidデバイスにはフィルレート制限があります。たとえば、NexusOneには30Hzのフィルレートロックがあります。実際の描画の速度に関係なく、画面はその周波数で同期されます。描画が30Hz未満で終了すると、レンダラーは画面と同期します。glClear()これが、この遅延に気付く理由です。この遅延は、通話を削除した場合でも気付くはずです。レンダラーは、画面の更新よりも前で高速です。

レンダラーに描画するオブジェクトが多数ある場合、レンダラーは画面の更新後に実行されるため、同期は停止します(ビジーシーンのプロファイルデータが与えられた場合)。

を使用するglFinish()と、関数が他の方法で発生する時間を削除します。これglClear()は、フィルレートロジックに従うことglFinish()で、画面との同期を確保している関数であることを意味します。

計算

F = 1 / T

簡単なシーン

F = 1 / T = 1 /((20 + 11 + 2)* 10 ^ -3)=〜30 Hz

同期の遅延時間はプロファイラーに表示されます。レンダラーは画面と同期しています。つまり、glClear()またはglFinish()呼び出しを削除すると、遅延が別の場所に表示されます。

重いシーン

F = 1 / T = 1 /((2 + 0 + 44)* 10 ^ -3))=〜22 Hz

同期の遅延時間はプロファイラーに表示されません。レンダラーは、画面の更新頻度の後にあります。

これはすべてvsyncに関連しているようです

それは正しいようです。

于 2012-09-02T12:51:06.877 に答える