3

ゲーム内グラフィカル プロファイラー (CPU および GPU) を作成しましたが、Nvidia ドライバーで奇妙な動作が 1 つあります。

通常の場合のスクリーンショットを次に示し GPU プロファイラー、vysnc on ます。ここに表示されているのは、3 つの連続したフレームで、上部が GPU、下部が CPU です。両方のグラフが同期されます。

「END FRAME」バーには、への呼び出しのみが含まれますSwapBuffers。GPU がすべての作業を完了するまでブロックしているのは奇妙に思えるかもしれませんが、vsync がオンで、すべての作業 (CPU と GPU) が 16ms に収まる場合にドライバーが選択することがあります (AMD も同じです)。私の推測では、入力の遅れを最小限に抑えるためにそれを行うということです。

今私の問題は、それが常にそうであるとは限らないということです。フレーム内で何が起こるかによって、グラフは次のようになることがあります: GPU プロファイラー、vysnc オン、V2 ここで実際に起こることは、SwapBuffers. この特定のケースでは、ブロッキング コールはglBufferData. それを行うダミーコードを追加すると、はるかに目立ちます(均一なバッファを作成し、ランダムな値をロードして破棄します):

GPU プロファイラー、vysnc on、ダミーコード付き V2

これは、明らかな理由もなくグラフのバーが非常に大きくなる可能性があることを意味するため、問題です。これを見た人は、一部のコードが遅いという誤った結論を導き出す可能性があります。

私の質問は、このケースをどのように処理できますか? 意味のある CPU タイミングを常に表示する方法が必要です。

ユニフォーム バッファをロードするダミー コードを追加するのはあまり洗練されておらず、ドライバーの将来のバージョンでは機能しない可能性があります (ドライバーが代わりにドローコールのみをブロックするとしたらどうなるでしょうか?)。

フレームレートが低下すると、ドライバーはブロックを停止してCPUとGPUフレームを並行してglClientWaitSync実行できるようにするため、呼び出しを停止するにはそれを検出する必要があるためですglClientWaitSync(ただし、どうすればよいかわかりません。)

(より良いタイトルの提案は大歓迎です。)

編集: GPU がボトルネックである場合、vsync なしで何が起こるか: GPU プロファイラー、vysnc オフ、V2 GPU フレームは CPU フレームよりも時間がかかるため、ドライバーglBufferDataは GPU が追いつくまで CPU をブロックすることにしました。

条件は同じではありませんが、問題は、ドライバーが OpenGL 関数ブロックの一部を作成するため、CPU タイミングが「間違っている」ことです。これは実際には、vsync をオンにしたものよりも理解しやすい例かもしれません。

4

1 に答える 1

3

これは実際に意図したとおりに機能しています。VSYNC によるブロッキングは、 への呼び出し中に必ずしも発生する必要はありませんSwapBuffers (...)。VSYNC がブロッキングを引き起こす理由はいくつかありますが、それらはほとんど完全に制御できません。

スワップチェーンがスワップを待っているバックバッファでいっぱいになっている場合 (通常、バックバッファは 1 つしかありません)、フレームバッファを変更するコマンドは、スワップが完了するまで実行できません。これはパイプラインの停止を引き起こし、最初のストライキです。パイプラインが停止していても、GL はこの状態でコマンドをキューに入れる可能性があることに注意してください。

ほとんどのプラットフォームでは、ウィンドウ システムのスワップチェーン内のバックバッファの数を明示的に要求できる API はありません。シングルまたはダブルバッファリングを要求でき、ドライバはダブル バッファリングを 2 つ以上を意味すると解釈する場合があります (一部のドライバでは、「トリプル バッファリングを有効にする」というラベルが表示されます)。

ストライク 2 は、「レンダー アヘッド」と呼ばれるものに由来します。これは、新しいコマンドの受け入れを拒否する前に GL がキューに入れるドライバー固有の作業量です。繰り返しますが、OpenGL ソフトウェアの開発者として、これを制御することはできません。一部のドライバーでは、非常に深く掘り下げて手動で構成できます。この値を大きくすると、パイプラインが停止している間、CPU はより多くの作業をキューに入れることができますが、レイテンシが増加する傾向があります (特に、D3D がフレーム ドロップを禁止する実装方法)。

レンダー パイプラインがバッファ スワップを待って停止し、レンダー アヘッドの制限を使い果たすと、ストライク 3 になります。呼び出し元のスレッドは、VBLANK がロールアラウンドしてパイプラインの詰まりを解消するまで、次の GL コマンドでブロックされます。


glClientWaitSync (...)、あなたが説明したように、すべての先読みを効果的に排除します。タイミングの変動を最小限に抑えるにはこれが望ましいかもしれませんが、リフレッシュ レートに問題がある場合は、全体的なフレームレートに悪影響を及ぼします。

適応型 VSYNC を最初に追求する必要があります。この機能をサポートするドライバーでは、負のスワップ間隔を設定して有効にすると、リフレッシュ レートを維持できない場合にブロックが回避されます。実際、アダプティブ VSYNC の目的は、描画が速すぎる場合にレンダリングを抑制することです。モニターが処理できるよりも速く描画している場合、GL API 呼び出しのプロファイリングは特に重要ではないようです。

最悪の場合、いつでも VSYNC を完全に無効にすることができます。Windows Vista で導入されたような最新の合成ウィンドウ マネージャーでは、VSYNC を有効にするかどうかに関係なく、ウィンドウ モードでティアリングが防止されます。VSYNC は実際にはそのような状況で電力を節約するだけであり、より正確なプロファイリングのためにオフにすることは、おそらく許容できる妥協点です。独自のスロットリング メカニズムを簡単に実装して、VSYNC が導入する予測不可能な動作なしに、エンジンが途方もなく高いフレームレートで描画するのを防ぐことができます。

于 2015-02-22T23:09:10.657 に答える