web-dev-qa-db-ja.com

opengl:glFlush()vs. glFinish()

glFlush()glFinish()の呼び出しの実際の違いを区別するのに問題があります。

ドキュメントは、glFlush()glFinish()がすべてのバッファされた操作をOpenGLにプッシュし、すべてが実行されることを保証できると言っています。違いは、glFlush()すべての操作が完了するまで、glFinish()ブロックとしてすぐに。

定義を読んで、glFlush()を使用すると、OpenGLに実行できるよりも多くの操作を送信するという問題が発生する可能性があると考えました。それで、試してみるために、glFinish()glFlush()とloに交換しました。見れば、私のプログラムは(私が知る限り)実行されました。フレームレート、リソース使用量、すべてが同じでした。

だから、2つの呼び出しに大きな違いがあるのか​​、それとも私のコードがそれらを実行するのに違いはないのか疑問に思っています。または、一方を他方に対して使用する場所。また、OpenGLがglIsDone()のような呼び出しを行って、glFlush()のすべてのバッファーコマンドが完了しているかどうかを確認することも考えました(したがって、オペレーションをOpenGLに高速で送信しません)実行できるよりも)、しかし、私はそのような機能を見つけることができませんでした。

私のコードは典型的なゲームループです。

while (running) {
    process_stuff();
    render_stuff();
}
101
jay.lee

これらのコマンドは、OpenGLの初期から存在していることに注意してください。 glFlushは、以前のOpenGLコマンドが有限時間で完了する必要があることを保証しますOpenGL 2.1仕様 、245ページ)。フロントバッファーに直接描画する場合、これにより、OpenGLドライバーが遅延なしで描画を開始することが保証されます。各オブジェクトの後にglFlushを呼び出すと、画面上でオブジェクトの後に表示される複雑なシーンを考えることができます。ただし、ダブルバッファリングを使用する場合、バッファをスワップするまで変更は表示されないため、glFlushは事実上まったく効果がありません。

glFinishは、以前に発行されたコマンド[...]からのすべての効果が完全に実現されるまで戻りません。これは、最後のピクセルがすべて描画され、OpenGLがそれ以上何もするまで、プログラムの実行がここで待機することを意味します。フロントバッファに直接レンダリングする場合、glFinishは、オペレーティングシステムの呼び出しを使用してスクリーンショットを撮る前に行う呼び出しです。強制的に行われた変更が表示されないため、ダブルバッファリングにはあまり役立ちません。

したがって、ダブルバッファリングを使用する場合、おそらくglFlushもglFinishも必要ないでしょう。 SwapBuffersは、暗黙的にOpenGL呼び出しを正しいバッファーに転送します 最初にglFlushを呼び出す必要はありません 。また、OpenGLドライバーにストレスをかけることを気にしないでください。glFlushはあまり多くのコマンドを停止しません。この呼び出しがimmediately(その意味は何でも)を返すことは保証されないため、コマンドの処理に必要な時間はいつでもかかります。

90
Malte Clasen

他の答えが示唆しているように、仕様によると本当に良い答えはありません。 glFlush()の一般的な目的は、それを呼び出した後、ホストCPUがOpenGL関連の作業を行う必要がないことです。コマンドはグラフィックハードウェアにプッシュされます。 glFinish()の一般的な目的は、返された後、no残りの作業が残り、すべての適切な非OpenGL API(フレームバッファーからの読み取り、スクリーンショットなど...)。それが本当に起こるかどうかは、ドライバーに依存します。仕様では、何が合法であるかに関して、多くの自由度が認められています。

21
Andy Ross

私は常にこれらの2つのコマンドについても混乱していましたが、このイメージは私にすべてを明確にしました: Flush vs Finish いくつかのGPUドライバーは、一定数のコマンドが蓄積されない限り、発行されたコマンドをハードウェアに送信しないようです。この例では、その数は5です。
この画像は、発行されたさまざまなOpenGLコマンド(A、B、C、D、E ...)を示しています。一番上にあるように、キューはまだいっぱいではないため、コマンドはまだ発行されていません。

中央では、glFlush()がキューに入れられたコマンドにどのように影響するかがわかります。キューに入れられたすべてのコマンドをハードウェアに送信するようドライバーに指示します(キューがまだいっぱいではない場合でも)。これは呼び出しスレッドをブロックしません。追加のコマンドを送信していない可能性があることをドライバーに通知するだけです。したがって、キューがいっぱいになるのを待つのは時間の無駄です。

一番下には、glFinish()を使用した例があります。 glFlush()とほぼ同じことを行いますが、すべてのコマンドがハードウェアで処理されるまで呼び出しスレッドを待機させます。

「OpenGLを使用した高度なグラフィックプログラミング」の本からの画像。

14
Tara

パフォーマンスに違いが見られない場合は、何か間違ったことをしていることを意味します。他の人が言ったように、どちらも呼び出す必要はありませんが、glFinishを呼び出すと、GPUとCPUが達成できる並列性が自動的に失われます。深く掘り下げてみましょう。

実際には、ドライバーに送信するすべての作業はバッチ処理され、潜在的にかなり後でハードウェアに送信されます(例:SwapBuffer時)。

したがって、glFinishを呼び出す場合、本質的には、ドライバーにコマンドをGPUにプッシュすることを強制し(それまでバッチ処理され、GPUに作業を依頼することはありません)、プッシュされたコマンドが完全に完了するまでCPUをストールさせます実行されました。そのため、GPUが動作している間は、CPUは動作しません(少なくともこのスレッドでは)。また、CPUが処理を実行するたびに(主にバッチコマンド)、GPUは何も実行しません。そのため、glFinishはパフォーマンスを低下させるはずです。 (多くのコマンドが既にバッチ処理されている場合、ドライバーはいくつかのコマンドでGPUを動作させ始める可能性があるため、これは近似値です。

では、なぜglFinishと呼ぶのでしょうか?使用したのは、ドライバーのバグがあったときだけです。実際、ハードウェアに送信するコマンドの1つがGPUをクラッシュさせる場合、どのコマンドが原因であるかを特定する最も簡単なオプションは、DrawごとにglFinishを呼び出すことです。そうすれば、クラッシュを引き起こすきっかけを絞り込むことができます

補足として、Direct3DのようなAPIは、Finishコンセプトをまったくサポートしていません。

6
Bahbar

glFlushは、実際にはクライアントサーバーモデルにまでさかのぼります。すべてのglコマンドをパイプを介してglサーバーに送信します。そのパイプはバッファリングする可能性があります。ファイルやネットワークのI/Oがバッファリングするのと同じように。 glFlushは、「バッファがまだ満杯ではない場合でも、今すぐバッファを送信してください!」とだけ言っています。ローカルシステムでは、ローカルOpenGL APIは自身をバッファリングする可能性が低く、コマンドを直接発行するだけなので、これはほとんど必要ありません。また、実際のレンダリングを引き起こすすべてのコマンドは、暗黙的なフラッシュを実行します。

一方、glFinishはパフォーマンス測定のために作成されました。 GLサーバーへのPINGの種類。コマンドを往復し、サーバーが「I am idle」と応答するまで待機します。

最近では、地元のドライバーは、アイドルになることの意味を非常に創造的に考えています。 「すべてのピクセルが描画されます」または「コマンドキューにスペースがありますか?」また、多くの古いプログラムは、多くの現代のドライバーがブードゥーコーディングを「最適化」として無視するため、コード全体に理由なくglFlushとglFinishを振りかけているためです。本当に彼らを責めることはできません。

要約すると、古代のリモートSGI OpenGLサーバー用にコーディングしているのでない限り、glFinishとglFlushの両方を、実際には操作なしとして扱います。

5
starmole

ご覧ください here 。要するに、それは言う:

glFinish()はglFlush()と同じ効果がありますが、加えて、送信されたすべてのコマンドが実行されるまでglFinish()がブロックされます。

別の 記事 は他の違いを説明しています:

  • スワップ関数(ダブルバッファーアプリケーションで使用)はコマンドを自動的にフラッシュするため、glFlushを呼び出す必要はありません。
  • glFinishは、OpenGLに未処理のコマンドを強制的に実行させますが、これは悪い考えです(例:VSyncを使用)

要約すると、これは、スワップバッファの実装がコマンドを自動的にフラッシュしない場合を除き、ダブルバッファリングを使用するときにこれらの関数さえ必要ないことを意味します。

4
AndiDog

バッファのステータスを照会する方法はないようです。これがあります Apple拡張 これは同じ目的を果たすことができますが、クロスプラットフォームではないようです(試したことはありません。)一見すると、flushより前のようですfenceコマンドをプッシュします。その後、そのフェンスがバッファ内を移動するときに、そのフェンスのステータスを照会できます。

コマンドをバッファリングする前にflushを使用できるかどうかは疑問ですが、次のフレームのレンダリングを開始する前にfinishを呼び出します。これにより、GPUの動作中に次のフレームの処理を開始できますが、戻るまでに処理が完了していない場合、finishはブロックされ、すべてが新鮮な状態にあることを確認します。

私はこれを試していませんが、まもなくします。

CPUとGPUをかなり使用する古いアプリケーションで試しました。 (もともとfinishを使用していました。)

終了時にflushに変更し、開始時にfinishに変更しても、すぐに問題は発生しませんでした。 (すべて正常に見えました!)プログラムの応答性が向上しました。おそらく、CPUがGPUを待機してストールしていないためです。間違いなくより良い方法。

比較のために、finishedをフレームの先頭から削除し、flushを残して、同じことを実行しました。

だから、flushfinishを使用すると言うでしょう。なぜなら、finishへの呼び出しでバッファが空のとき、パフォーマンスが低下しないからです。バッファがいっぱいになった場合、finishとにかくしたいはずです。

3
GManNickG

問題は、OpenGLコマンドの実行中にコードを実行し続けるのか、それともafter OpenGLコマンドが実行された後にのみ実行するのか、ということです。

これは、ネットワークの遅延など、特定のコンソール出力のみを持つ場合に問題になる可能性がありますafter画像が描画されたなど。

0
anon