Windows 8 以降での TDR
Windows 8 以降では、GPU タイムアウトの検出と回復 (TDR) の動作により、アダプター全体のリセットを必要とするのではなく、個々の物理アダプターの一部をリセットできます。
詳細については、「タイムアウトの検出と回復 (TDR)」を参照してください。
要件
- WDDM の最小バージョン: 1.2
- Windows の最小バージョン: 8
- ドライバーの実装 — フル グラフィックスおよびレンダリング専用: 必須
- WHLK の要件とテスト: Device.Graphics...TDRResiliency
TDR デバイス ドライバー インターフェイス (DDI)
この動作の変更に対応するために、カーネル モード ディスプレイ ミニポート ドライバー (KMD) では以下の関数を実装できます。
KMD は、DXGK_DRIVERCAPS。SupportPerEngineTDR メンバーを設定することで、これらの関数をサポートすることを示し、この場合は一覧表示されている関数のすべてを実装する必要があります。
これらの関数をサポートするドライバーは、DxgkDdiCollectDbgInfo 関数のレベル 0 の同期もサポートする必要があります。 この要件により、リセット操作が影響を及ぼさない場合にレベル 0 の KMD 呼び出しを続行できます。 「DxgkDdiCollectDbgInfo」の備考を参照してください。
上記の関数には、次の構造体が関連付けられています。
- DXGK_DRIVERCAPS
- DXGK_ENGINESTATUS
- DXGKARG_QUERYDEPENDENTENGINEGROUP
- DXGKARG_QUERYENGINESTATUS
- DXGKARG_RESETENGINE
Nodes
一覧表示されている TDR 機能で使用されているように、 ノード は、個別にスケジュールできる 1 つの物理アダプターの複数部分のうちの 1 つです。 たとえば、3-D ノード、ビデオ デコーディング ノード、コピー ノードはすべて同じ物理アダプターに存在でき、それぞれに個別のノード序数を割り当てることができます。 この割り当ては、DxgkDdiQueryDependentEngineGroup 呼び出しへの DXGKARG_QUERYDEPENDENTENGINEGROUP.NodeOrdinal メンバーに保存されます。
物理アダプター内のノードの数は、NbAsymetricProcessingNodes メンバー (DXGK_DRIVERCAPS.GpuEngineTopology のメンバー)で ミニポート ドライバーによって報告されます。
ノード序数値は、コンテキストの作成時に NodeOrdinal メンバー (DXGKARG_CREATECONTEXT 構造体のメンバー) で渡されます。
エンジン
TDR DDI 機能で使用されているように、エンジン は 1 つの論理アダプターとして機能する複数の物理アダプター (または GPU) の 1 つです。 Dxgkrnl ではこのような構成をサポートしていますが、各エンジンに同じ数のノードが必要です。
たとえば、GPU スケジューラでは、エンジン 0 が物理アダプター 0 に対応すると見なされます。 エンジン 0 には、アダプター 1 に対応するエンジン 1 と同じ数のノードが必要です。
コンテキスト作成時のエンジンまたは序数値
コンテキストが作成されると、エンジンの序数値に対応する 1 ビットが、EngineAffinity メンバー (DXGKARG_CREATECONTEXT 構造体のメンバー) に設定されます。 これと他のスケジューラ関連構造体の EngineOrdinal メンバーは、0 から始まるインデックスです。 EngineAffinity の値は 1 <<EngineOrdinal であり、EngineOrdinal は EngineAffinity の最上位ビット位置です。
エンジンのリセットの影響を受けないパケット
ドライバーは、エンジンのリセットが完了する前に完全に処理するには、エンジン ハードウェア キューに送信されたパケットを再送信するように GPU スケジューラから求められる場合があります。 ドライバーは、このようなパケットを再送信するには、次のガイドラインに従う必要があります。
- ページング パケット: ドライバーは、元のフェンス ID を使用して、最初に送信されたのと同じ順序でページング パケットを再送信するように GPU スケジューラから要求されます。 このようなパケットは、新しいパケットがハードウェア キューに追加される前に再送信されます。
- レンダリング パケット: GPU スケジューラは、レンダリング パケットに新しいフェンス ID を割り当ててから再送信します。
エンジンをリセットするための呼び出しシーケンス
DxgkDdiResetEngine が成功すると、GPU スケジューラーでは、エンジン リセット呼び出しから返された LastAbortedFenceId の値が次のいずれかに対応していることを確認します。
- ハードウェア キュー内の既存のフェンス ID。
- GPU で最後に完了したフェンス ID。 この状況は、GPU タイムアウトが検出された後、エンジン リセット コールバックが呼び出される前にハードウェア キューが空になったときに発生する可能性があります。
GPU 上で最後に完了したフェンス ID 値は、DmaPreempted.LastCompletedFenceId メンバー (DXGKARGCB_NOTIFY_INTERRUPT_DATA プリエンプション割り込み通知構造のメンバー) を設定するためにフェンス ID が必要であるためで、常にドライバーによって維持されている必要があります。 最後に完了したフェンス ID は、次の状況でのみ進める必要があります。
- パケットが (割り込まれていない) 完了したら、最後に完了したフェンス ID を完了したパケットのフェンス ID に設定する必要があります。
- DxgkDdiResetEngine が成功したら、最後に完了したフェンス ID を、エンジン リセット呼び出しによって返される LastCompletedFenceId メンバーの値に設定する必要があります。
- アダプター全体のリセットでは、すべてのノードで最後に完了したフェンス ID を、リセット時に最後に送信されたフェンス ID に進める必要があります。
GPU スケジューラで見られるように、エンジンのリセットが成功した時系列シーケンスを次に示します。
プリエンプション試行が発行されます。
GPU タイムアウトが検出されました。
最後に送信され、完了したフェンス ID のスナップショットは GPU スケジューラによって取得され、タイムアウト したエンジンからの割り込みは無視されます。 この組み合わせは、デバイス割り込みレベルでの 1 つのアトミック操作です。
この時点でハードウェア キューにパケットがない場合は、終了します。 この状況は、手順 2 から 3 の時間枠でパケットが完了した場合に発生する可能性があります。
キューに登録されているすべての DPC がフラッシュされます。
エンジンのリセットを準備します。
DxgkDdiResetEngine を呼び出します。
LastAbortedFenceId メンバーが最後に完了したフェンス ID より小さいか、最後に送信されたフェンス ID より大きい場合、Dxgkrnl によってシステム バグ チェックが発生します。 クラッシュ ダンプ ファイルでは、エラーは、次の 4 つのパラメーターを持つ BugCheck 0x119 メッセージによって示されます。
- ドライバーが無効な中止されたフェンス ID を報告したことを意味する 0xA
- ドライバーによって返される LastAbortedFenceId 値
- 最後に完了したフェンス ID
- 内部オペレーティング システム パラメーター
LastAbortedFenceId の値が有効な場合は、次のようにエンジンのリセット回復に進みます。 ページング パケットがエンジンのリセットの影響を受けた場合、GPU スケジューラは、アダプター全体のリセットでエンジンのリセットに従います。 そのページング パケットによって参照される割り当てを所有するすべてのデバイスも、エラー状態になります。 システム デバイス自体はエラー状態にならず、リセットが完了した後に実行を再開します。
特殊なケース
ステップ 3~7 の間に GPU でパケットが完了すると、特別な状況が発生する可能性があります。 この場合、ドライバーの観点からハードウェア キューにパケットがない場合は、 最後に完了したパケットのフェンス ID にドライバーがLastAbortedFenceId を設定する必要があります。 スケジューラーの観点からは、このようなパケットが中止されたように見えます。 そのため、スケジューラーは、パケットが最終的に完了した場合でも、対応するデバイスをエラー状態にします。
ドライバーは、次のいずれかの理由でリセット操作を実行できない場合は、エラー ステータス コードを返す必要があります。
- ハードウェアの状態が無効です。
- ハードウェアはノードをリセットできません。
GPU スケジューラは、障害状態コードを受け取った場合、Windows 8 よりも前の TDR 動作に従ってアダプター全体のリセットおよび再起動操作を実行します。
ドライバーが Windows 8 以降の TDR 動作を選択した場合でも、GPU スケジューラが論理アダプター全体のリセットと再起動を要求する場合があります。 そのため、ドライバーは引き続き DxgkDdiResetFromTimeout 関数と DxgkDdiRestartFromTimeout 関数を実装する必要があり、そのセマンティクスは Windows 8 よりも前と同じです。 DxgkDdiResetEngine を使用して物理アダプターをリセットしようとすると、論理アダプターがリセットされると、Windows デバッガーの !analyze コマンドは、TDR 回復コンテキストの TdrReason 値が TdrEngineTimeoutPromotedToAdapterReset = 9 の新しい値に設定されていることを示します。