Von Bedeutung
一部の情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft は、ここで提供される情報に関して明示的または黙示的な保証を行いません。
この記事では、Windows 11 バージョン 24H2 (WDDM 3.2) の時点でまだ開発中のユーザー モード (UM) 作業送信機能について説明します。 UM の作業の送信により、アプリケーションは非常に短い待機時間でユーザー モードから直接 GPU に作業を送信できます。 目標は、GPU に小さなワークロードを頻繁に送信するアプリケーションのパフォーマンスを向上することです。 さらに、ユーザー モードの送信は、コンテナーまたは仮想マシン (VM) 内で実行されている場合、このようなアプリケーションに大きなメリットが期待されます。 この利点は、VM で実行されているユーザー モード ドライバー (UMD) が、ホストにメッセージを送信しなくても GPU に作業を直接送信できるためです。
UM 作業の提出をサポートする IHV ドライバーとハードウェアは、従来のカーネル モードの作業提出モデルを同時にサポートし続ける必要があります。 このサポートは、最新のホストで実行されている従来の KM キューのみをサポートする古いゲストなどのシナリオに必要です。
この記事では、Flip/FlipEx との UM 提出の相互運用性については説明しません。 この記事で説明する UM 提出は、シナリオのレンダリングのみ/コンピューティング クラスに限定されます。 現在のところ、プレゼンテーション パイプラインは、監視対象のネイティブ フェンスに依存しているため、カーネル モードの送信に基づいています。 UM 提出ベースのプレゼンテーションの設計と実装は、コンピューティング/レンダリング用のネイティブ監視フェンスと UM 提出が完全に実装された後でのみ考慮できます。 そのため、ドライバーは、キューごとにユーザー モードの送信をサポートする必要があります。
ドアベル
ハードウェア スケジューリングをサポートする GPU の最新世代または今後の世代でも、GPU ドアベルの概念がサポートされます。 ドアベルは、新しい作業が作業キューに入っていることを GPU エンジンに示すためのメカニズムです。 ドアベルは通常、PCIe BAR (ベース アドレス バー) またはシステム メモリに登録されます。 各 GPU IHV には、ドアベルの数、システム内の配置場所などを決定する独自のアーキテクチャがあります。 Windows OS では、デザインの一部としてドアベルを使用して UM 作業の申請を実装します。
大まかに言えば、異なる IHV と GPU によって実装されるドアベルの 2 つの異なるモデルがあります。
グローバル ドアベル
Global Doorbells モデルでは、コンテキストとプロセス全体のすべてのハードウェア キューが 1 つのグローバル ドアベルを共有します。 ドアベルに書き込まれた値は、どの特定のハードウェア キューとエンジンに新しい作業が含まれているかについて GPU スケジューラに通知します。 GPU ハードウェアは、複数のハードウェアキューがアクティブに作業を送信し同じグローバルドアベルを鳴らしている場合、作業を取得するためにポーリングメカニズム形式を使用します。
専用ドアベル
専用のドアベルモデルでは、各ハードウェアキューに独自のドアベルが割り当てられており、新しい作業がGPUに送信されるたびにそのドアベルが鳴らされます。 ドアベルが鳴らされると、GPU スケジューラは、新しい作業を送信したハードウェア キューを正確に認識します。 GPU で作成されたすべてのハードウェア キュー間で共有されるドアベルは限られています。 作成されたハードウェア キューの数が使用可能なドアベルの数を超える場合、ドライバーは、以前または最近使用したハードウェア キューのドアベルを切断し、新しく作成されたキューにドアベルを割り当て、実質的にドアベルを "仮想化" する必要があります。
ユーザーモードでの作業提出機能の検出
DXGK_NODEMETADATA_FLAGS::UserModeSubmissionSupported
UM 作業送信機能をサポートする GPU ノードの場合、KMD の DxgkDdiGetNodeMetadata は、DXGK_NODEMETADATA_FLAGSに追加される UserModeSubmissionSupported ノード メタデータ フラグを設定します。 その後、OS は、このフラグが設定されたノードでのみ、UMD がユーザーモード送信用のHWQueuesとdoorbellsを作成できるようにします。
DXGK_QUERYADAPTERINFOTYPE::DXGKQAITYPE_USERMODESUBMISSION_CAPS
ドアベル固有の情報を照会するために、OS は KMD の DxgkDdiQueryAdapterInfo 関数を DXGKQAITYPE_USERMODESUBMISSION_CAPS クエリ アダプター情報の種類で呼び出します。 KMD は、ユーザー モードの作業送信のサポートの詳細を DXGK_USERMODESUBMISSION_CAPS 構造体に設定することで応答します。
現時点で必要な上限は、ドアベルのメモリ サイズ (バイト単位) のみです。 Dxgkrnl には、いくつかの理由でドアベル メモリ サイズが必要です。
- ドアベルの作成時 (D3DKMTCreateDoorbell) に、Dxgkrnl は DoorbellCpuVirtualAddress を UMD に返します。 これを行う前に、ドアベルがまだ割り当てられ、接続されていないため、 Dxgkrnl は最初にダミー ページに内部的にマップする必要があります。 ダミー ページを割り当てるには、ドアベルのサイズが必要です。
- Doorbell Connect (D3DKMTConnectDoorbell) 中に 、Dxgkrnl はDoorbellCpuVirtualAddress を KMD によって提供される DoorbellPhysicalAddress に回転させる必要があります。 ここでも、 Dxgkrnl は ドアベルのサイズを知っている必要があります。
D3DKMTCreateHwQueue の D3DDDI_CREATEHWQUEUEFLAGS::UserModeSubmission
UMD は、ユーザーモードのサブミッションモデルを使用する HWキューを作成するために追加された UserModeSubmission フラグを D3DDDI_CREATEHWQUEUEFLAGS に設定します。 このフラグを使用して作成された HWQueues は、通常のカーネル モードの作業送信パスを使用できないため、キューでの作業の送信にドアベル メカニズムに依存する必要があります。
ユーザーモード作業送信API
ユーザー モードの作業の送信をサポートするために、次のユーザー モード API が追加されます。
D3DKMTCreateDoorbell は、ユーザー モードの作業送信用に D3D HWQueue のドアベルを作成します。
D3DKMTConnectDoorbell は、以前に作成したドアベルを D3D HWQueue に接続して、ユーザー モードの作業を送信します。
D3DKMTDestroyDoorbell は、以前に作成したドアベルを破棄します。
D3DKMTNotifyWorkSubmission は、HWQueue で新しい作業が送信されたことを KMD に通知します。 この機能のポイントは、作業の送信時に KMD が関与したり認識されたりしない、待ち時間の短い作業の提出パスです。 この API は、HWQueue で作業が送信されるたびに KMD に通知する必要があるシナリオで役立ちます。 ドライバーは、特定のシナリオや頻度の低いシナリオでこのメカニズムを使用する必要があります。これは、すべての作業の提出に UMD から KMD へのラウンド トリップが含まれるため、待機時間の短いユーザー モード送信モデルの目的を打ち負かすためです。
ドアベルメモリおよびリングバッファー割り当ての常駐モデル
- UMD は、ドアベルを作成する前に、リング バッファーとリング バッファーコントロールの割り当てを常駐させる役割を担います。
- UMD は、リング バッファーとリング バッファー制御の割り当ての有効期間を管理します。 Dxgkrnl は、対応するドアベルが破棄された場合でも、これらの割り当てを暗黙的に破棄しません。 UMD は、これらのリソースの割り当てと破棄を担当します。 ただし、ドアベルが生きている間に悪意のあるユーザー モード プログラムがこれらの割り当てを破棄するのを防ぐために、 Dxgkrnl はドアベルの有効期間中にそれらの割り当てを参照します。
- Dxgkrnl がリング バッファーの割り当てを破棄する唯一のシナリオは、デバイスの終了中です。 Dxgkrnl は、デバイスに関連付けられているすべての HWQueue、ドアベル、およびリングバッファーの割り当てを破棄します。
- リング バッファーの割り当てが有効である限り、リング バッファー CPUVA は常に有効であり、ドアベル接続の状態に関係なく UMD がアクセスできます。 つまり、リング バッファーの常駐はドアベルに関連付けられません。
- KMD が DXG コールバックを作成してドアベルを切断すると (つまり、状態が D3DDDI_DOORBELL_STATUS_DISCONNECTED_RETRY の DxgkCbDisconnectDoorbell を呼び出します)、 Dxgkrnl は ドアベル CPUVA をダミー ページに回転させます。 リング バッファーの割り当てを削除またはアンマップしません。
- デバイスが失われたシナリオ (TDR/GPU Stop/Page など) が発生した場合、 Dxgkrnl は ドアベルを切断し、状態をD3DDDI_DOORBELL_STATUS_DISCONNECTED_ABORTとしてマークします。 ユーザー モードは、HWQueue、doorbell、リング バッファーを破棄し、再作成する役割を担います。 この要件は、このシナリオで他のデバイス リソースを破棄して再作成する方法と似ています。
ハードウェア コンテキストの一時停止
OS がハードウェア コンテキストを中断すると、 Dxgkrnl は ドアベル接続をアクティブにし、リング バッファー (作業キュー) 割り当てを常駐させます。 この方法では、UMD はコンテキストに対するキュー処理を続行できます。コンテキストが中断されている間、この作業はスケジュールされません。 コンテキストが再開され、スケジュールされると、GPU のコンテキスト管理プロセッサ (CMP) は、新しい書き込みポインターと作業の送信を監視します。
このロジックは、UMD が中断されたコンテキストで D3DKMTSubmitCommand を 呼び出すことができる現在のカーネル モード送信ロジックに似ています。 Dxgkrnl はこの新しいコマンドを HwQueue にエンキューしますが、それが実行されるのは後のタイミングになります。
ハードウェア コンテキストの中断と再開中に、次の一連のイベントが発生します。
ハードウェア・コンテキストを中断すること
- Dxgkrnl は DxgkddiSuspendContext を呼び出します。
- KMD は、コンテキストのすべての HWQueue を HW スケジューラの一覧から削除します。
- Doorbell は依然として接続されており、リングバッファ/リングバッファ制御の割り当てはまだ残存しています。 UMD は、このコンテキストの HWQueue に新しいコマンドを書き込むことができますが、GPU はそれらを処理しません。これは、中断されたコンテキストへの現在のカーネル モード コマンドの送信に似ています。
- KMD が中断された HWQueue のドアベルを犠牲にすることを選択した場合、UMD は接続を失います。 UMD はドアベルの再接続を試みることができ、KMD はこのキューに新しいドアベルを割り当てます。 目的は、UMD をストールするのではなく、コンテキストが再開された後に HW エンジンが最終的に処理できる作業の送信を続行できるようにすることです。
ハードウェア コンテキストの再開:
- Dxgkrnl は DxgkddiResumeContext を呼び出します。
- KMD は、コンテキストのすべての HWQueue を HW スケジューラのリストに追加します。
エンジンの F 状態遷移
従来のカーネル モードの作業送信では、 Dxgkrnl が HWQueue に新しいコマンドを送信し、KMD からの完了割り込みを監視します。 このため、 Dxgkrnl には、エンジンがアクティブでアイドル状態の状態が完全に表示されます。
ユーザー モードの作業送信では、 Dxgkrnl は、GPU エンジンが TDR タイムアウトの周期を使用して進行しているかどうかを監視するため、2 秒の TDR タイムアウトよりも早く F1 状態への移行を開始する価値がある場合、KMD は OS にこれを要求できます。
このアプローチを容易にするために、次の変更が行われました。
DXGK_INTERRUPT_GPU_ENGINE_STATE_CHANGE割り込みの種類がDXGK_INTERRUPT_TYPEに追加されます。 KMD は、この割り込みを使用して、Dxgkrnl に、Active -> TransitionToF1 および Active -> Hung のような、GPU 電源アクションまたはタイムアウト回復を必要とするエンジン状態遷移を通知します。
EngineStateChange 割り込みデータ構造がDXGKARGCB_NOTIFY_INTERRUPT_DATAに追加されます。
DXGK_ENGINE_STATE列挙型は、EngineStateChange のエンジン状態遷移を表すために追加されます。
KMD が DXGK_INTERRUPT_GPU_ENGINE_STATE_CHANGE 割り込みを発生させ、EngineStateChange.NewState を DXGK_ENGINE_STATE_TRANSITION_TO_F1 に設定すると、Dxgkrnl はこのエンジンの HWQueue にあるすべてのドアベルを切断し、その後、F0 から F1 への電源コンポーネントの切り替えを開始します。
UMD が F1 状態の GPU エンジンに新しい作業を送信しようとすると、ドアベルを再接続する必要があります。これにより、 Dxgkrnl は F0 電源状態への遷移を開始します。
エンジンの D 状態遷移
D0 から D3 へのデバイスの電源状態遷移中、 Dxgkrnl は HWQueue を中断し、ドアベルを切断し (ドアベル CPUVA をダミー ページに回転させる) 、DoorbellStatusCpuVirtualAddress ドアベルの状態をD3DDDI_DOORBELL_STATUS_DISCONNECTED_RETRYに更新します。
GPU が D3 にあるときに UMD が D3DKMTConnectDoorbell を呼び出すと、 Dxgkrnl は GPU を D0 に強制的にウェイクアップします。 Dxgkrnl は、HWQueue を再開し、ドアベル CPUVA を物理的なドアベル位置に回転させる役割も担います。
次の一連のイベントが発生します。
D0 ~ D3 GPU の電源ダウンが発生します。
- Dxgkrnl は、GPU 上のすべての HW コンテキストに対して DxgkddiSuspendContext を呼び出します。 KMD は、HW スケジューラリストからこれらのコンテキストを削除します。
- Dxgkrnl は、すべてのドアベルを切断します。
- Dxgkrnl は、必要に応じて、VRAM からすべてのリング バッファー/リング バッファー制御割り当てを削除する可能性があります。 すべてのコンテキストが中断され、ハードウェア スケジューラの一覧から削除されると、ハードウェアが削除されたメモリを参照しないようにします。
UMD は、GPU が D3 状態のときに HWQueue に新しいコマンドを書き込みます。
- UMD はドアベルが切断されていることを確認するため、 D3DKMTConnectDoorbell を呼び出します。
- Dxgkrnl は D0 遷移を開始します。
- Dxgkrnl は、追い出された場合、すべてのリング バッファーおよびリング バッファー制御の割り当てを常駐化します。
- Dxgkrnl は、KMD の DxgkddiCreateDoorbell 関数を呼び出して、KMD がこの HWQueue のドアベル接続を確立するように要求します。
- Dxgkrnl は、すべての HWContext に対して DxgkddiResumeContext を呼び出します。 KMD は、対応するキューを HW スケジューラの一覧に追加します。
ユーザーモード内作業送信用DDI
KMD によって実装されたDDI
ユーザー モードの作業送信のサポートを実装するために、KMD 用に次のカーネル モード DDI が追加されます。
DxgkDdiCreateDoorbell. UMD が D3DKMTCreateDoorbell を呼び出して HWQueue のドアベルを作成すると、 Dxgkrnl は、KMD がそのドアベル構造を初期化できるように、この関数に対応する呼び出しを行います。
DxgkDdiConnectDoorbell. UMD が D3DKMTConnectDoorbell を呼び出すと、 Dxgkrnl はこの関数に対応する呼び出しを行い、KMD が物理ドアベルの場所にマップされた CPUVA を提供し、HWQueue オブジェクト、ドアベル オブジェクト、ドアベル物理アドレス、GPU スケジューラなどの間で必要な接続を行うことができます。
DxgkDdiDisconnectDoorbell. OS は、特定のドアベルを切断する場合、この DDI で KMD を呼び出します。
DxgkDdiDestroyDoorbell. UMD が D3DKMTDestroyDoorbell を呼び出すと、 Dxgkrnl は、KMD がそのドアベル構造を破棄できるように、この関数に対応する呼び出しを行います。
DxgkDdiNotifyWorkSubmission。 UMD が D3DKMTNotifyWorkSubmission を呼び出すと、 Dxgkrnl はこの関数に対応する呼び出しを行い、新しい作業の申請を KMD に通知できるようにします。
Dxgkrnl DDI 実装
DxgkCbDisconnectDoorbell コールバックは Dxgkrnl によって実装されます。 KMD はこの関数を呼び出して、KMD が特定のドアベルを切断する必要があることを Dxgkrnl に通知できます。
HW キューの進行状況フェンスの変更
UM 作業申請モデルで実行されているハードウェア キューには、コマンド バッファーが完了したときに UMD によって生成および書き込まれる、単調に増加する進行状況フェンス値の概念があります。 Dxgkrnl が特定のハードウェア キューに保留中の作業があるかどうかを認識するには、UMD は、リング バッファーに新しいコマンド バッファーを追加して GPU に表示する直前に、キューに登録された進行状況のフェンス値を更新する必要があります。 CreateDoorbell.HwQueueProgressFenceLastQueuedValueCPUVirtualAddress は、ユーザーモードで最新のキューに登録された値の読み取り/書き込みを行うプロセスマッピングです。
UMD では、新しい送信が GPU に表示される直前にキューに登録された値が確実に更新されるようにすることが不可欠です。 次の手順は、推奨される一連の操作です。 HW キューがアイドル状態であり、最後に終了したバッファーの進行状況フェンス値が N であると想定しています。
- 新しい進行状況フェンス値 N+1 を生成します。
- コマンド バッファーを埋めます。 コマンド バッファーの最後の命令は、 N+1 への進行状況フェンス値の書き込みです。
- *(HwQueueProgressFenceLastQueuedValueCPUVirtualAddress) を N+1 に設定して、新しくキューに入れた値を OS に通知します。
- コマンド バッファーをリング バッファーに追加して、GPU に表示されるようにします。
- ドアベルを鳴らします。
通常および異常なプロセス終了
次の一連のイベントは、通常のプロセスの終了時に発生します。
デバイス/コンテキストの HWQueue ごとに、次の手順を実行します。
- Dxgkrnlは DxgkDdiDisconnectDoorbell を呼び出してドアベルを切断します。
- Dxgkrnl は、最後にキューに入れた HwQueueProgressFenceLastQueuedValueCPUVirtualAddress が GPU で完了するのを待機します。 リング バッファー/リング バッファー制御の割り当ては常駐状態のままです。
- Dxgkrnl の待機要件が満たされ、これでリング バッファーとリング バッファー制御の割り当て、およびドアベルと HWQueue のオブジェクトを破棄できるようになりました。
次の一連のイベントは、異常なプロセスの終了時に発生します。
Dxgkrnl は デバイスをエラーとしてマークします。
Dxgkrnl は、デバイス コンテキストごとに DxgkddiSuspendContext を呼び出してコンテキストを中断します。 リングバッファーやリングバッファー制御の割り当ては、まだメモリに常駐しています。 KMD はコンテキストをプリエンプションし、その HW 実行リストから削除します。
コンテキストごとの HWQueue に対して、Dxglrnl:
a. DxgkDdiDisconnectDoorbell を呼び出してドアベルを切断します。
b。 リング バッファー/リング バッファーコントロールの割り当て、ドアベルオブジェクト、およびHWQueueオブジェクトを破棄します。
擬似コードの例
UMD での作業送信擬似コード
次の擬似コードは、UMD が doorbell API を使用して HWQueues に作業を作成して送信するために使用するモデルの基本的な例です。
hHWqueue1は、既存の D3DKMTCreateHwQueue API を使用してUserModeSubmission フラグを使用して作成された HWQueue へのハンドルであると考えてください。
// Create a doorbell for the HWQueue
D3DKMT_CREATE_DOORBELL CreateDoorbell = {};
CreateDoorbell.hHwQueue = hHwQueue1;
CreateDoorbell.hRingBuffer = hRingBufferAlloc;
CreateDoorbell.hRingBufferControl = hRingBufferControlAlloc;
CreateDoorbell.Flags.Value = 0;
NTSTATUS ApiStatus = D3DKMTCreateDoorbell(&CreateDoorbell);
if(!NT_SUCCESS(ApiStatus))
goto cleanup;
assert(CreateDoorbell.DoorbellCPUVirtualAddress!=NULL &&
CreateDoorbell.DoorbellStatusCPUVirtualAddress!=NULL);
// Get a CPUVA of Ring buffer control alloc to obtain write pointer.
// Assume the write pointer is at offset 0 in this alloc
D3DKMT_LOCK2 Lock = {};
Lock.hAllocation = hRingBufferControlAlloc;
ApiStatus = D3DKMTLock2(&Lock);
if(!NT_SUCCESS(ApiStatus))
goto cleanup;
UINT64* WritePointerCPUVirtualAddress = (UINT64*)Lock.pData;
// Doorbell created successfully. Submit command to this HWQueue
UINT64 DoorbellStatus = 0;
do
{
// first connect the doorbell and read status
ApiStatus = D3DKMTConnectDoorbell(hHwQueue1);
D3DDDI_DOORBELL_STATUS DoorbellStatus = *(UINT64*(CreateDoorbell.DoorbellStatusCPUVirtualAddress));
if(!NT_SUCCESS(ApiStatus) || DoorbellStatus == D3DDDI_DOORBELL_STATUS_DISCONNECTED_ABORT)
{
// fatal error in connecting doorbell, destroy this HWQueue and re-create using traditional kernel mode submission.
goto cleanup_fallback;
}
// update the last queue progress fence value
*(CreateDoorbell.HwQueueProgressFenceLastQueuedValueCPUVirtualAddress) = new_command_buffer_progress_fence_value;
// write command to ring buffer of this HWQueue
*(WritePointerCPUVirtualAddress) = address_location_of_command_buffer;
// Ring doorbell by writing the write pointer value into doorbell address.
*(CreateDoorbell.DoorbellCPUVirtualAddress) = *WritePointerCPUVirtualAddress;
// Check if submission succeeded by reading doorbell status
DoorbellStatus = *(UINT64*(CreateDoorbell.DoorbellStatusCPUVirtualAddress));
if(DoorbellStatus == D3DDDI_DOORBELL_STATUS_CONNECTED_NOTIFY)
{
D3DKMTNotifyWorkSubmission(CreateDoorbell.hDoorbell);
}
} while (DoorbellStatus == D3DDDI_DOORBELL_STATUS_DISCONNECTED_RETRY);
KMDにおけるドアベル擬似コードの脆弱性への対処
次の例は、KMD が専用のドアベルを使用する GPU 上の HWQueues 間で使用可能なドアベルを "仮想化" して共有する必要がある方法を示しています。
KMD の VictimizeDoorbell() 関数の擬似コード:
- KMD は、
PhysicalDoorbell1に接続hDoorbell1論理的なドアベルを犠牲にして切断する必要があると判断します。 - KMD は Dxgkrnl の
DxgkCbDisconnectDoorbellCB(hDoorbell1->hHwQueue)を呼び出します。- Dxgkrnl は、このドアベルの UMD に表示される CPUVA をダミー ページに回転させ、状態値をD3DDDI_DOORBELL_STATUS_DISCONNECTED_RETRYに更新します。
- KMD は制御を取り戻し、実際の加害行為/切断操作を実行します。
- KMD は
hDoorbell1を犠牲にし、PhysicalDoorbell1から切断します。 -
PhysicalDoorbell1使用できる
- KMD は
次に、次のシナリオを考えてみましょう。
PCI BAR には、
0xfeedfeeeと同じカーネル モードの CPUVA を持つ 1 つの物理ドアベルがあります。 HWQueue 用に作成されたドアベル オブジェクトには、この物理的なドアベル値が割り当てられます。HWQueue KMD Handle: hHwQueue1 Doorbell KMD Handle: hDoorbell1 Doorbell CPU Virtual Address: CpuVirtualAddressDoorbell1 => 0xfeedfeee // hDoorbell1 is mapped to 0xfeedfeee Doorbell Status CPU Virtual Address: StatusCpuVirtualAddressDoorbell1 => D3DDDI_DOORBELL_STATUS_CONNECTEDOS は、別の
HWQueue2に対してDxgkDdiCreateDoorbellを呼び出します。HWQueue KMD Handle: hHwQueue2 Doorbell KMD Handle: hDoorbell2 Doorbell CPU Virtual Address: CpuVirtualAddressDoorbell2 => 0 // this doorbell object isn't yet assigned to a physical doorbell Doorbell Status CPU Virtual Address: StatusCpuVirtualAddressDoorbell2 => D3DDDI_DOORBELL_STATUS_DISCONNECTED_RETRY // In the create doorbell DDI, KMD doesn't need to assign a physical doorbell yet, // so the 0xfeedfeee doorbell is still connected to hDoorbell1OS は、
hDoorbell2でDxgkDdiConnectDoorbellを呼び出します。// KMD needs to victimize hDoorbell1 and assign 0xfeedfeee to hDoorbell2. VictimizeDoorbell(hDoorbell1); // Physical doorbell 0xfeedfeee is now free and can be used vfor hDoorbell2. // KMD makes required connections for hDoorbell2 with HW ConnectPhysicalDoorbell(hDoorbell2, 0xfeedfeee) return 0xfeedfeee // On return from this DDI, *Dxgkrnl* maps 0xfeedfeee to process address space CPUVA i.e: // CpuVirtualAddressDoorbell2 => 0xfeedfeee // *Dxgkrnl* updates hDoorbell2 status to connected i.e: // StatusCpuVirtualAddressDoorbell2 => D3DDDI_DOORBELL_STATUS_CONNECTED ``
GPU がグローバル ドアベルを使用する場合、このメカニズムは必要ありません。 代わりに、この例では、 hDoorbell1 と hDoorbell2 の両方に、物理的なドアベルと同じ 0xfeedfeee が割り当てられます。