次の方法で共有


ハードウェア フリップ キュー

この記事では、Windows 11 (WDDM 3.0) 以降でサポートされるハードウェア フリップ キュー機能について説明します。 ハードウェア フリップ キュー機能を使用すると、今後複数のフレームをディスプレイ コントローラー キューに送信できます。 CPU と GPU の一部は、ディスプレイ コントローラーが複数のキューに置かれたフレームを処理している間に、より低い電力状態に移行できるため、対応するハードウェアでのビデオ再生シナリオの電力効率が向上します。

WDDM 3.0 より前のフリップ キュー モデル

最新のディスプレイ コントローラーの多くは、シーケンスで表示される複数のフレームをキューに登録する機能をサポートしています。 WDDM 2.1 以降、OS では、次の VSync で提示される未解決のフリップ上書き要求が複数サポートされています。 ディスプレイ ミニポート ドライバー (KMD) は、DXGK_DRIVERCAPSの MaxQueuedMultiPlaneOverlayFlipVSync 値を 介してこのサポートを示します。 この機能は、複数のフレームが間隔 0 で順番にレンダリングされ、最新のフレームのみを表示する目的で、高フレーム レートのゲーム シナリオで待機時間を短縮するのに役立ちます。

ビデオ再生シナリオでは、順次表示される複数の将来のフレームの内容が事前にわかっており、GPU にキューに入れることもできます。 このアドバンス キューにより、キューに入ったフレームが処理されている間に CPU が低電力状態に入り、大幅な省電力が実現します。 ただし、WDDM 3.0 より前は、CPU の介入なしに少なくとも 1 つの VSync 間隔で画面に残る必要がある複数のフレームを OS が送信するメカニズムはありませんでした。 「基本的なハードウェア フリップ キュー」 セクションでは、CPU が低電力状態に入り、キューに入ったフレーム処理を GPU にオフロードできるようにするソリューションが導入されています。

WDDM 3.0 より前のゲーム シナリオでは、GPU がスワップ チェーン バック バッファーへのシーンのレンダリングを完了した後、フレームコンテンツを画面に表示する要求を送信するために CPU へのラウンドトリップがあります。 VSync に近い状態で終了する GPU ワークロードが多い場合、このラウンドトリップによりフレームが遅延し、目的のターゲット時間を逃し、フレームの障害が発生する可能性があります。 「高度なハードウェア フリップ キュー」 セクションでは、この CPU ラウンドトリップを回避し、待機時間が非常に短い完成したフレームを画面に表示するメカニズムが導入されています。 高度なハードウェア フリップ キューには、基本的なハードウェア フリップ キューと GPU ハードウェア スケジューリング ステージ 2 の両方の機能が存在する必要があります。

基本的なハードウェア フリップ キュー

次の図は、3 つのフレームを提示する場合を示しています。各フレームは 1 つの VSync 間隔で画面に表示されます。

Diagram illustrating three frames staying on the screen for one VSync interval each.

図の塗りつぶしパターンは、 Dxgkrnl ソフトウェア フリップ キュー処理とアプリケーション スレッドが起動して CPU 処理を実行する必要がある時間を示しています。 各 VSync で、ディスプレイ コントローラーは、完了したフリップのために OS に CPU 通知を発行する必要があり、OS は次のフリップ要求を送信する必要があります。 また、アプリケーションは、各 VSync で起動し、クエリを実行して統計を表示し、最終的に 3 つのバッチ内の最後のフレームが表示されるタイミングを学習する必要があります。

WDDM 3.0 以降では、ディスプレイ コントローラー キューに複数の将来のフレームを送信できるハードウェア フリップ キュー DDI を使用できます。 前述のように、このメカニズムにより、ディスプレイ コントローラーが複数のキューに登録されたフレームを処理している間に、CPU と GPU の一部が低い電源状態に遷移し、対応するハードウェアでのビデオ再生シナリオの電力効率が向上します。

次の図は、提案されたアーキテクチャを示しています。

Diagram demonstrating the basic hardware flip queue mechanism.

ハードウェア フリップ キューアプローチでは、アプリケーションと Dxgkrnl CPU コンポーネントの両方が v2v4の間の 2つの VSync 間隔で完全にアイドル状態になり、CPU が低電力状態になります。 CPU は、アプリケーションが待機を要求したフレーム N+2 が完了したときにのみ通知されます。

高度なハードウェア フリップ キュー

WDDM 3.0 以前のゲーム シナリオでは、GPU がスワップ チェーン バック バッファーへのシーンのレンダリングを完了した後、フレームコンテンツを画面に表示する要求を送信するために CPU へのラウンドトリップがあります。 次の図に、このシナリオを示します。

Diagram depicting frame completion requiring a CPU roundtrip.

次の図に示すように、このラウンドトリップのコストにより、レンダリングが VSync に近くなりすぎると、フレームがターゲットを見逃す可能性があります。

Diagram illustrating a missed frame due to the required CPU roundtrip.

一部のディスプレイ コントローラーでは、GPU が CPU ラウンドトリップなしでフレームのレンダリングが完了したら、ディスプレイがフリップ要求を送信できるようにする待機条件がネイティブにサポートされています。 ハードウェア フリップ キューは、完了したフレーム N を CPU ラウンドトリップなしでディスプレイに送信できるため、次の図に示すように、フレームの不足を回避できます。

Diagram displaying frame completion without the need for a CPU roundtrip.

この記事のメインでは、基本的なハードウェア フリップ キュー機能について説明します。

DDI サポート

ハードウェア フリップ キュー機能をサポートするために、次の DDI が追加されました。

機能の可用性の確認

ハードウェア フリップ キューには、OS の有効化/無効化ネゴシエーションが必要です。 ハードウェア フリップ キューをサポートする KMD では、まず デバイス の開始時刻に FeatureId DXGK_FEATURE_HWFLIPQUEUE を使用して DXGKCB_QUERYFEATURESUPPORT を呼び出して、OS でハードウェア フリップ キューを有効にできるかどうかを判断する必要があります。

ハードウェア フリップ キューは、コールバックが成功し [有効] が TRUE に設定されている場合にのみ使用できます。

KMD では、ハードウェア フリップ キューの起動および試験段階で、次のサンプル コードを使用できます。


DXGKARGCB_QUERYFEATURESUPPORT HwFlipQueueEnabledArgs = {};
HwFlipQueueEnabledArgs.DeviceHandle = DeviceHandle;
HwFlipQueueEnabledArgs.FeatureId = DXGK_FEATURE_HWFLIPQUEUE;
HwFlipQueueEnabledArgs.DriverSupportState = DXGK_FEATURE_SUPPORT_EXPERIMENTAL;

if (!NT_SUCCESS(pDxgkInterface->DxgkCbQueryFeatureSupport(&HwFlipQueueEnabledArgs)) ||
    !HwFlipQueueEnabledArgs.Enabled)
{
    // Disable hardware flip queue because the OS didn't allow it.           
}
else
{
    // Enable hardware flip queue because the OS allowed it.
}

ドライバーの起動中に、GPU ハードウェア スケジューリングを有効にせずにハードウェア フリップ キューを有効にすることはできますが、この組み合わせは正式にはサポートされていません。 Windows では現在、正式にリリースされたドライバーで基本的なハードウェア フリップ キューを有効にするために、GPU ハードウェア スケジューリングを有効にする必要があります。

ハードウェア キュー機能を示す

MaxHwQueuedFlips がハードウェア フリップ キューのサポートを示すために DXGK_DRIVERCAPS に追加されました。 前述のように OS でハードウェア フリップ キューのサポートが許可されている場合は、ハードウェア フリップ キューをサポートする KMD で MaxHwQueuedFlips を 1 より大きい値に設定する必要があります。 MaxHwQueuedFlips が 1 より 大きい場合、KMD は、GPU 上の特定の VidPnSource に対してキューに登録できる MaxHwQueuedFlips 以降のフレームまで、ディスプレイ ハードウェアがサポートしていることを示します。 OS では、事前にキューに登録できるフリップの種類に関するドライバー提供の制限が適用されます。

HwQueuedFlipCapsDXGK_DRIVERCAPSに追加されました。 このメンバーは現在、システム用に予約されており、ドライバーでは使用しないでください。

ターゲット時刻とターゲット タイムスタンプ形式を反転する

OS がハードウェア フリップ キューにフリップ要求を送信すると、ターゲット フリップ時間も送信されます。 フリップは、ターゲット フリップ時間に達した後にユーザーに表示できます。

OS は、 KeQueryPerformanceCounterから取得した CPU クロック カウンター ユニットを使用して、ターゲット フレーム時間を渡し、実際のフレーム時間を解釈します。

キューに入ったフリップの送信

KMDの DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 コールバック関数に渡される DXGKARG_Standard Edition TVIDPNSOURCEADDRESSWITHMULTIPLANEOVERLAY3 構造体は、キューに配置されたフリップの送信を有効にするために次のように変更されました。

  • 次の3 つのメンバーが OutputFlagsDXGK_Standard Edition TVIDPNSOURCEADDRESS_OUTPUT_FLAGS 構造体には追加されました。 これらのメンバーの詳細については、 DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 の再試行と失敗のケース を参照してください。

    • HwFlipQueueDrainNeeded
    • HwFlipQueueDrainAllPlanes
    • HwFlipQueueDrainAllSources
  • TargetFlipTime メンバーが追加されました。 TargetFlipTime は、QPC 単位のターゲット フリップ時間を表します。 クロックがこの値に達すると、VSync とティアリング フラグを受け入れながら、フレームをディスプレイに送信できます。 以前にキューに入れた保留中のフリップが存在する場合、OS はフリップ要求によって参照される各 MPO プレーンについて、 TargetFlipTime がこのプレーンの保留中のフリップ ターゲット時間以上であることを保証します。 言い換えると、同じタイムスタンプまたは増加するタイムスタンプを持つ一連のフリップが存在する可能性がありますが、時間をさかのぼって戻るシーケンスは存在できません。

DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 の再試行と失敗のケース

保留中のフリップが原因でハードウェアに要求をキューに登録できない

他のフリップ要求が保留中である間に KMD がフリップ要求をキューに入れないようにする特殊なケースがいくつかあります。 このような場合、KMD は DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 から STATUS_RETRYを返し、 HwFlipQueueDrainNeeded を 1 に設定する必要があります。 OS は、このフリップの影響を受ける平面上のすべての保留中のフリップが完了し、ターゲット時間に達すると、フリップ要求を再度送信しようとします。

場合によっては、ディスプレイ ハードウェアでは、着信フリップ要求によって参照される平面だけでなく、すべての平面で保留中のフリップの完了が必要になる場合があります。 この場合、 HwFlipQueueDrainNeededHwFlipQueueDrainAllPlanes フラグの両方を 1 に設定し、KMD はSTATUS_RETRYを返す必要があります。

同様に、表示ハードウェアでは、内部リソースを再割り当てするために、すべての VidPn ソースで保留中のフリップの完了が必要になる場合があります。その場合 HwFlipQueueDrainAllSourcesHwFlipQueueDrainNeeded フラグを設定する必要があり、KMD はSTATUS_RETRYを返す必要があります。

さらに、KMD は、デバイス IRQL (PrePresentNeeded を 0 に設定) で再送信する必要があるかどうか、または OS がPASSIVE_LEVEL (PrePresentNeeded を 1 に設定)でこの呼び出しを実行する必要があるかどうかを OS に示すことができます。 その VidPnSourceId に保留中のフリップがない場合でも KMD がSTATUS_RETRYを返す場合、この条件は 無効なパラメーター エラーとして扱われます。

MaxHwQueuedFlips の は、MPO プレーンにキューに入れることができる単純なアドレスのみの変更フリップの最大数を反映することが重要です。 STATUS_RETRY メカニズムは、プレーン構成の変更など、深くキューに入れることができない、より複雑なフリップ要求に使用する必要があります。

無効なパラメーターエラー

ハードウェア フリップ キュー モデルでは、デバッグの容易性を高めるために、失敗したフリップ要求に対する OS の処理が再調整されました。 KMD がフリップ要求を処理できない場合は、 DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3から STATUS_INVALID_PARAMETER を返す必要があります。 OS の設定に応じて、OS は次のいずれかのアクションを実行します。

  • カーネル デバッガーの中断とバグのチェック: この動作は、多くの場合、開発ビルドまたはプレリリース ビルドで有効になり、エラー状態が発生したときにデバッグが容易になります。
  • ライブ カーネル ダンプに続く TDR: リテール エンド ユーザーの動作。

VSync 割り込み動作の指定

キューに置かれたフリップ シナリオで省電力を実現するために、OS は通常の VSync 割り込みを中断して CPU を低電力状態に保ちます。 ただし、一部のフリップは、完了したプレゼンテーションのバッチをアプリケーションが観察し、さらに作業をキューに入れるには割り込みを発生させる必要があるものとしてマークされます。 また、保留中のフリップ要求があるかどうかに関係なく、アプリケーションが VSync 割り込みごとに起動を要求する場合もあります。 逆に、完全にアイドル状態のシステムでは、新しいプレゼンテーション アクティビティまたは VSync リスナーが表示されるまで、VSync 割り込みは中断されます。

これらのすべてのケースを処理するために、次のドライバーコールバックとコールバック構造が導入されました。

KMD は、DRIVER_INITIALIZATION_DATA の DxgkDdiSetInterruptTargetPresentId 関数への ポインターを提供します

OS は DxgkDdiSetInterruptTargetPresentId を呼び出して、対応するフリップが完了したときに VSync 割り込みが発生するターゲット PresentId を指定します。 DxgkDdiSetVidPnSourceAddress および VSync 割り込みと同期 するために、デバイス割り込みレベル (DIRQL) で呼び出されます。

DxgkDdiControlInterrupt との対話

DxgkDdiControlInterrupt DxgkDdiControlInterrupt2/DxgkDdiControlInterrupt3/を介してVSync 割り込みが完全に無効になっている場合、割り込みターゲット PresentId 値に関係なく無効のままです。 KMD は、VSync が再度有効になった後に受け入れることができるように、最新の割り込みターゲットの現在の ID を格納するために必要です。

DxgkDdiControlInterrupt Xxxを介して、VSync 割り込みが有効になっている場合、割り込みターゲットの現在の ID (pSetInterruptTargetPresentId) は、次のようにきめ細かい制御を提供します。

  • ターゲットの現在の ID が UINT64_MAX に設定されている場合、ターゲットの現在の ID が再度変更されるまで、VSync 割り込みは必要ありません。 VSync 割り込みは無効になっていますが、割り込みを再度有効にするための DXGK_VSYNC_DISABLE_KEEP_PHASE 動作を実装するには KMD が必要です。

  • ターゲットの現在の ID が 0 に設定されている場合は、すべての VSync に割り込みが必要です。

  • その他の現在の ID 値については、現在スキャンされている PresentId >= InterruptTargetPresentIdの場合、割り込みが発生します。

複数の MPO プレーンが使用可能な場合、いずれかの平面で必要な場合は、VSync 割り込みを発生させる必要があります。

DxgkDdiSetInterruptTargetPresentId による 2 段階 VSync の無効化

DxgkDdiSetInterruptTargetPresentId への OS 呼び出しで、この VidPnSource で VSync を完全に 無効にするプレーンに InterruptTargetPresentId を設定する場合 (つまり、このプレーンは VSync を有効にした最後のプレーンであり、VSync も無効にしています)、KMD は VSync 割り込みを無効にする必要がありますが、VSync フェーズはハードウェアで有効にしておく必要があります (DXGK_VSYNC_DISABLE_KEEP_PHASE)。 一定の期間 (通常は 2 つの VSync 期間に相当) の後、OS は DxgkDdiControlInterruptXxx をDXGK_VSYNC_DISABLE_NO_PHA Standard Editionで呼び出します。 この呼び出しにより、KMD は VSync フェーズと VSync クロックを無効にして最大電力を節約し、ハードウェア以外のフリップ キュー システムとのパフォーマンス パリティをメインします。

キューに入ったフリップの取り消し

全画面表示の状態遷移やアプリケーションの終了などの場合は、キューに入った将来のフリップを取り消す必要があります。 これらのケースを処理するために、次のドライバー コールバックと関連する構造体が導入されました。

KMD は、DRIVER_INITIALIZATION_DATA の DxgkDdiCancelFlips 関数への ポインターを提供します

OS は、 DxgkDdiCancelFlipsを呼び出すときに取り消すキューフリップの範囲を指定し、KMD は同期的に取り消すことができたフリップの範囲を OS に報告します。

次の例は、1 つの平面でのフリップ キャンセルのメカニズムと同期ケースを示しています。 (OS では、Windows 11 バージョン 22H2 での非同期キャンセルはサポートされていません)。次のフリップがハードウェア フリップ キューにキューに入っている場合を想像してください。

  • PresentId N
  • time t0 PresentId N+1
  • time t1 PresentId N+2
  • time t2 PresentId N+3
  • time t3 PresentId N+4
  • 時間 t4

その後、OS は N+2N+3、および N+4を取り消すと決定するため、 PresentIdCancelRequestedN+2 に設定して DxgkDdiCancelFlipsを呼び出します。

KMD は、ハードウェア フリップ キューの状態を調べるときに、フリップ N+2 がディスプレイ ハードウェアに既に送信されており、呼び出し時に取り消すことはできませんが、 N+3N+4 は、副作用なしでハードウェア フリップ キューから同期的に削除できます。 KMD は PresentIdCancelledN+3 に設定し、通常どおり N+2 を完了します。

OS は N+3 および N+4 をキャンセル済みとしてマークし、 NN+1N+2 を処理中として扱います。 次の VSync 割り込みが発生すると、フリップ キュー ログは、通常どおり NN+1N+2 のタイムスタンプを示します。

同期的に取り消されたフリップの範囲は連続する必要があり、0 でない場合は、KMD に送信された最後の現在の ID が含まれていると見なされます。 言い換えると、両方の同期キャンセルされたフリップ範囲の内部にギャップがない可能性があります。

複数の平面でインターロックされたフリップを取り消す

複数の平面と PresentIds を使用して DxgkDdiSetVidPnSourceAddress を呼び出すことによって、インターロックされたフリップが送信されます。 OS と KMD の間のコントラクトは次のとおりです。

  • 平面のセットは、同じ VSync で表示する必要があります。
  • 表示ハードウェアでは、これらのプレーンのサブセットを 1 つの VSync に、残りを次の VSync にのみ表示することはできません。

ハードウェア フリップ キュー モデルでは、 DxgkDdiCancelFlipsへの呼び出しで複数の平面と PresentIds を渡すことによって、このような連動フリップが取り消されます。 このような場合に渡される平面のセットは、保留中のインターロックされたフリップ要求に対応する必要があります。また、すべてのインターロックされた PresentId に関する KMD の決定は同じである必要があります。

  • キャンセルしない、または
  • 同期的に取り消す

DxgkDdiCancelFlips は、デバイス割り込みレベル (DIRQL) で呼び出され、 DxgkDdiSetVidPnSourceAddress および VSync 割り込みと同期されます。

キューに配置されたフリップの現在の統計情報の取得

ハードウェア フリップ キューのアプローチは、各 VSync で CPU を起動しないようにするため、最後のいくつかのキューに置かれたフリップのフレーム表示時間を保持するメカニズムが必要です。

ハードウェア フリップ キューをサポートするグラフィックス ドライバーは、各アクティブな VidPnSource の特定の MPO プレーンごとに完了または取り消された各フリップの情報を、OS によって提供されるフリップ キュー ログ バッファーに書き込む必要があります。

OS は、アクティブな各 VidPnSource の特定の MPO プレーンに対する最初のDxgkDdiSetVidPnSourceAddress 呼び出しの前に、フリップ キュー ログ ポインター ( DxgkDdiSetFlipQueueLogBufferの呼び出し) を 提供する ことを保証します。 フリップ キューに未処理の要求がない場合、OS はフリップ キュー ログ バッファーを破棄できます。 この場合、次の DxgkDdiSetVidPnSourceAddress 呼び出しの前に新しいログ ポインターが提供されます。 フリップ キュー ログは循環です。 [NumberOfEntries-1] エントリが書き込まれると、次のログ エントリは [0] になります。

キューに入ったフリップのバッチが完了したら、KMD は、完了したフリップのフリップ キュー ログが、次の 2 つの時点の早い時点で更新されることを保証する必要があります。

  • 割り込みを発生させる必要があるフリップの VSync 割り込みハンドラー。
  • OS からの明示的な DxgkDdiUpdateFlipQueueLog 要求への応答。

キュー ログの DDI を反転する

次のフリップ キュー ログ関連のコールバックと関連する構造体が追加されました。

KMD は、 DRIVER_INITIALIZATION_DATA内の関数へのポインターを提供します。

VSync 割り込み構造の更新

ハードウェア フリップ キュー モデルのVSync 割り込みを実装するために、 DXGKARGCB_NOTIFY_INTERRUPT_DATA 構造体に次の変更が加えられました。

  • DXGK_INTERRUPT_CRTC_VSYNC_WITH_MULTIPLANE_OVERLAY3 列挙型の値が InterruptTypeとして追加されました。
  • CrtcVSyncWithMultiPlaneOverlay3 構造体が共用体に追加されました。 CrtcVSyncWithMultiPlaneOverlay3のセマンティクスは、既存の CrtcVSyncWithMultiPlaneOverlay2 構造体に似ていますが、各プレーンで最後に完了した PresentId の代わりに、 CrtcVSyncWithMultiPlaneOverlay3.pMultiPlaneOverlayVSyncInfo は、フリップ キュー ログから以前に報告されなかった PresentId の範囲を指します。
  • crtcVSyncWithMultiPlaneOverlay3 の MultiPlaneOverlayVSyncInfo メンバー として、DXGK_MULTIPLANE_OVERLAY_VSYNC_INFO3 構造体が 追加されました。

もう一度 基本的なハードウェア フリップ キュー の例の図を使用します。

Diagram demonstrating the basic hardware flip queue mechanism.

FirstFreeFlipQueueLogEntryIndex が 40 に設定され、フリップ N が送信される時点で、 NN+1N+2 のプレゼンテーションが完了したとします。

1 つのプレーン構成で、それぞれの時刻 v2、v3、v4 で 3 つの PresentId NN+1、および N+2 が完了すると、KMD は、インデックス 40、41、および 42 を持つ 3 つの新しいエントリをフリップ キュー ログ バッファーに書き込みます。 KMD は、 CrtcVSyncWithMultiPlaneOverlay3 構造体の FirstFreeFlipQueueLogEntryIndex 値 43 を報告します。 OS では、 FirstFreeFlipQueueLogEntryIndex が40 から 43 に変更され、ログ エントリ 40、41、および 42 から読み取られます。 KMD では、次のように次のフリップ キュー ログ バッファー値を設定する必要があります。

  • VidPnTargetId: CrtcVSyncWithMultiPlaneOverlay2 と 同じ意味

  • PhysicalAdapterMask: CrtcVSyncWithMultiPlaneOverlay2 と 同じ意味

  • MultiPlaneOverlayVSyncInfoCount = 1

  • pMultiPlaneOverlayVSyncInfo[0]。LayerIndex = 0

  • pMultiPlaneOverlayVSyncInfo[0]。FirstFreeFlipQueueLogEntryIndex = 43

  • LogBufferAddressForPlane0[40]。PresentId = N

  • LogBufferAddressForPlane0[40]。PresentTimestamp = v2

  • LogBufferAddressForPlane0[41]。PresentId = N+1

  • LogBufferAddressForPlane0[41]。PresentTimestamp = v3

  • LogBufferAddressForPlane0[42]。PresentId = N+2

  • LogBufferAddressForPlane0[42]。PresentTimestamp = v4

明示的なフリップ キュー ログ更新要求

VSync 割り込みを待たずに、最後に完了したフリップ バッチに関する情報を OS が取得する必要がある場合があります。 このような場合、OS は DxgkDdiUpdateFlipQueueLog を明示的に呼び出して、KMD が独自の表示ハードウェア データ構造から読み取り、過去のフリップ情報をフリップ キュー ログに書き込むよう要求します。 ログのセマンティクスは、前に説明したのと同じです。唯一の変更は、 FirstFreeFlipQueueLogEntryIndex が VSync 割り込みの外部の OS に返されるということです。

DxgkDdiUpdateFlipQueueLog はデバイス割り込みレベル (DIRQL) で呼び出され、 DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 DDI と同じ同期クラスにあります。

ハードウェア フリップ キューでキューに配置されたフリップがある場合の表示モードの変更と電源の切り替え

Dxgkrnl は、モードの変更を開始またはモニターの電源を切る前に、ハードウェア フリップ キュー内の既にキューに置かれたフリップが完了または取り消されることを確認します。

現在の要求をハードウェア フリップ キューのタイムスタンプにマッピングする

特定のアダプターでハードウェア フリップ キューが有効になっている場合、すべてのフリップ呼び出しにタイムスタンプが伴います。 言い換えると、KMD では、古いセマンティクスと新しい DxgkDdiSetVidPnSourceAddress セマンティクスの組み合わせを処理する必要はありません。

OS は、既存の間隔ベースの Present API 要求を KMD へのタイムスタンプベースのフリップ呼び出しに自動的に変換します。 次のセクションでは、さまざまなケースと、KMD で受信したフラグ、 期間、ならびにタイムスタンプの組み合わせにどのようにマップされるかについて説明します。

ティアリングと非ティアリングフリップセマンティクス

ティアリング フリップのセマンティクスは、ハードウェア フリップ キューが有効になっている場合の概念的には同じです。 TargetFlipTime に達すると、KMD は FlipImmediateFlipImmediateNoTearing、および FlipOnNextVSyncなどのフラグを受け入れながら、表示するフリップを送信する必要があります。 言い換えると、KMD は、OS が同じフリップ フラグとパラメーターを持つ TargetFlipTime でフリップを正確に送信したかのように動作する必要があります。

たとえば、 FlipOnNextVSync が 1 に設定されていて TargetFlipTime がフレームの中央にある場合、このフリップは次の VSync にのみ表示されます。

FlipOverwrite のサポートとハードウェア フリップ キュー

ハードウェア フリップ キューは、DXGK_DRIVERCAPSの MaxQueuedMultiPlaneOverlayFlipVSync 値によって 御されるフリップ上書き機能の厳密なスーパーセットです

したがって、ドライバーが MaxHwQueuedFlips を 1 より大きい値に設定してハードウェア フリップ キューにオプトインした場合、OS は MaxQueuedMultiPlaneOverlayFlipVSync 値を無視します。

TargetFlipTime が期限切れになった複数のフリップ

特定の MPO プレーンに対して期限切れの TargetFlipTime を持つ複数のキューに入れられているフリップがある場合、ハードウェアディスプレイキューは、最後にキューに登録された期限切れのフリップを選択し、それを送信して表示する必要があります。 期限切れの残りのフリップは取り消し済みとして扱う必要があり、対応するフリップ キュー ログ エントリには PresentTimestamp 値として DXGK_HWFLIPQUEUE_TIMESTAMP_CANCELLED が含まれている必要があります。

Duration と TargetFlipTime の間の相互作用

DXGKARG_SETVIDPNSOURCEADDRESSWITHMULTIPLANEOVERLAY3 構造体の Duration パラメーター は、この構造体で指定されたフリップが画面に表示されるときに有効になります。 これは、すべてのプレーンにわたって VidPnSourceId で指定された出力の新しい必要な表示リフレッシュ レートの動作を指定します。 WDDM 3.1 および Windows 2022 リリースでは、キューに登録されたカスタム Duration の変更をサポートしていないハードウェアのドライバー実装を簡略化するために、OS は、以前のフリップ要求が完了した後にのみ、新しい Duration パラメーターを使用してフリップ要求を送信します。

現在の間隔を TargetFlipTime にマッピングする

更新レートが固定されている場合のマッピング間隔

既存の現在の間隔セマンティクスを保持するには、OS は現在の間隔と更新レートを使用してターゲットフリップ時間を計算する必要があります。 ただし、ターゲット フリップ時間を目的の VSync 時間に正確に設定すると、実際の VSync のタイミングが少しずれた場合に、VSync が見落とされ、頻繁にグリッチが発生します。 障害から保護するために、OS は計算されたターゲット フリップ時間から VSync 間隔の半分を減算します。

現在の間隔をターゲットフリップ時間にマッピングするための簡略化された数式を次に示します。

TargetFlipTime = PreviousFlipStartVSyncTime + (PreviousFlipPresentInterval * FixedRefreshRate) - (FixedRefreshRate / 2)

仮想リフレッシュ レート WDDM 2.9 機能が存在する場合のマッピング間隔

仮想リフレッシュ レート機能は、表示リフレッシュ レートを現在のリフレッシュ レートの整数倍数に一時的にブーストする場合があります (つまり、24 Hz を 144 Hz または 192 Hz にブーストできます)。 このブーストをサポートできるデバイスの場合、前のセクションの数式は、現在の更新レートの最速の倍数を使用するように変更されます。

TargetFlipTime = PreviousFlipStartVSyncTime + (PreviousFlipPresentInterval * FixedRefreshRate) - (FastestRefreshRate / 2)

更新レートが非倍数に変更されたときのマッピング間隔

更新レートが現在のリフレッシュ レートの非倍数 (たとえば、24 Hz から 60 Hz) に変更された場合、OS はキューの反転を調べて、計算されたターゲット時間が新しいリフレッシュ レートで有効かどうかを確認する必要があります。 ターゲット フリップ時間を変更する必要がある場合、OS はキューに置かれたフリップを取り消し、新しく計算されたターゲット フリップ時間で再キューに入れます。