メモリ セグメントへの仮想アドレスのマッピング
ディスプレイ ミニポート ドライバーは、自己が定義するメモリ空間またはアパーチャ空間セグメント内の割り当て領域に CPU 仮想アドレスを直接マッピングできるかどうかを、それらの各セグメントに対して指定できます。この指定は、セグメントの DXGK_SEGMENTDESCRIPTOR 構造体の Flags メンバーに CpuVisible ビット フィールド フラグを設定することによって行います。
CPU 仮想アドレスをセグメントにマッピングするには、セグメントが PCI アパーチャを介して線形アクセスできる必要があります。 つまり、セグメント内の割り当て領域のオフセットが、PCI アパーチャ内のオフセットと同じである必要があります。 結果として、ビデオ メモリ マネージャーは、特定のセグメント内の割り当て領域のオフセットに基づいて、割り当てのバス相対物理アドレスを計算できます。
次の図は、仮想アドレスが線形メモリ空間セグメントにどのようにマップされるかを示しています。
次の図は、線形アパーチャ空間セグメントの基になるページに対して仮想アドレスがどのようにマッピングされるかを示しています。
割り当て領域はスウィズルされている可能性もありますが、仮想アドレスをセグメントの一部にマッピングする前に、ビデオ メモリ マネージャーはディスプレイ ミニポート ドライバーの DxgkDdiAcquireSwizzlingRange 関数を呼び出すことで、ドライバーがそのような割り当て領域のビットにアクセスするためのアパーチャを設定できます。 ドライバーは、割り当て領域がアクセスされる PCI アパーチャへのオフセットも、割り当て領域がアパーチャ内で占有する領域のサイズも変更できません。 これらの制約から、ドライバーが割り当て領域を CPU アクセス可能にできない場合 (ハードウェアがスウィズル解除アパーチャを使い果たした可能性がある場合など)、ビデオ メモリ マネージャーは割り当て領域をシステム メモリに追い出し、そこに存在するビットにアプリケーションがアクセスできるようにします。
ユーザーモード ディスプレイ ドライバーが pfnLockCb 関数を呼び出してメモリへの直接アクセスを要求するとき、以前に作成した割り当て領域の内容がシステム メモリ内にある場合、ビデオ メモリ マネージャーはシステム メモリ バッファーをユーザーモード ディスプレイ ドライバーに返し、ディスプレイ ミニポート ドライバーは割り当て領域へのアクセスには関与しません。 したがって、割り当て領域の内容はディスプレイ ミニポート ドライバーによって変更されず、非スウィズル形式のままになります。 これは、CPU アクセス可能な割り当て領域がビデオ メモリから追い出された場合、結果として得られるシステム メモリのビットにアプリケーションから直接アクセスできるよう、ディスプレイ ミニポート ドライバーが割り当て領域のスウィズルを解除する必要があることを意味します。
割り当て領域が、アプリケーションによる直接アクセスを目的として現在マッピングされているとき、そこに関連付けられている GPU リソースが追い出された場合でも、割り当て領域の内容がシステム メモリに転送されるため、アプリケーションは同じ仮想アドレスで異なる物理メディアのコンテンツに引き続きアクセスできます。 転送を設定するために、ビデオ メモリ マネージャーはディスプレイ ミニポート ドライバーの DxgkDdiBuildPagingBuffer 関数を呼び出してページング バッファーを作成し、GPU スケジューラはドライバーの DxgkDdiSubmitCommand 関数を呼び出して、GPU 実行ユニットのキューにページング バッファーを追加します。 ハードウェア固有の転送コマンドはページング バッファー内にあります。 詳細については、「コマンド バッファーの送信」を参照してください。 ビデオ メモリ マネージャーは、ビデオ メモリからシステム メモリへの切り替えがアプリケーションからは見えないようにします。 ただし、PCI アパーチャを介した割り当てのバイト順序と、その領域が追い出されたときの割り当てのバイト順序とが厳密に一致するよう、ドライバーが保証する必要があります。
アパーチャ空間セグメントの割り当て領域に存在するビットは既にシステム メモリにあるため、追い出しプロセス時のデータの転送 (スウィズル解除) は不要です。 したがって、アパーチャ空間セグメント内に配置された CPU アクセス可能な割り当て領域にアプリケーションから直接アクセスする場合、その領域をスウィズルすることはできません。
アプリケーションから CPU を介して直接アクセスできるものの、アパーチャ空間セグメントでスウィズルされるようなサーフェスについては、ディスプレイ ドライバーが、2 つの異なる割り当てとして実装する必要があります。 ユーザーモード ディスプレイ ドライバーでそのようなサーフェスを作成するときに、pfnAllocateCb 関数を呼び出し、D3DDDICB_ALLOCATE 構造体の NumAllocations メンバーを 2 に設定し、D3DDDICB_ALLOCATE の pAllocationInfo 配列内の D3DDDI_ALLOCATIONINFO 構造体の pPrivateDriverData メンバーを、割り当て領域に関するプライベート データ (スウィズル形式、非スウィズル形式など) を指すように設定できます。 GPU によって使用される割り当て領域にはスウィズル形式でビットが格納される一方、アプリケーションによってアクセスされる割り当て領域には非スウィズル形式でビットが格納されまれます。 ビデオ メモリ マネージャーは、ディスプレイ ミニポート ドライバーの DxgkDdiCreateAllocation 関数を呼び出して割り当てを作成します。 ユーザーモード ディスプレイ ドライバーから渡される (各割り当ての DXGK_ALLOCATIONINFO 構造体の pPrivateDriverData メンバー内の) プライベート データは、ディスプレイ ミニポート ドライバーによって解釈されます。 ビデオ メモリ マネージャーは、割り当ての形式を認識しません。特定のサイズとアラインメントのメモリ ブロックを領域に割り当てるだけです。 サーフェスをロックして処理するためにユーザーモード ディスプレイ ドライバーの Lock 関数を呼び出すと、次のアクションが発生します。
ユーザーモード ディスプレイ ドライバーが、pfnRenderCb 関数を呼び出して、コマンド バッファー内のスウィズル解除操作を Direct3D ランタイムに送信し、そこからさらにディスプレイ ミニポート ドライバーへと送信します。
ユーザーモード ディスプレイ ドライバーが pfnLockCb 関数を呼び出して、スウィズルされていない割り当て領域をロックします。 ユーザーモード ディスプレイ ドライバーで、D3DDDICB_LOCK 構造体の Flags メンバーに D3DDDILOCKCB_DONOTWAIT フラグを設定すべきではないことに注意してください。
pfnLockCb 関数は、割り当て領域間の転送 (スウィズリング解除) が実行されるまで待機します。
pfnLockCb 関数は、ディスプレイ ミニポート ドライバーに、スウィズルされていない割り当て領域の仮想アドレスを取得し、D3DDDICB_LOCK の pData メンバーでユーザーモード ディスプレイ ドライバーに仮想アドレスを返すように要求します。
ユーザーモード ディスプレイ ドライバーは、D3DDDIARG_LOCK の pSurfData メンバー内のアプリケーションに、スウィズルされていない割り当て領域の仮想アドレスを返します。