GPU 仮想アドレス

この記事では、GPU 仮想アドレス (GPUVA) の概念と、WDDM 2.0 (Windows 10) 以降での管理方法について説明します。

GPUVA は、デバイス ドライバー インターフェイス (DDI) レベルで 4 KB または 64 KB の論理ページで管理されます。 これらのページ サイズを使用すると、GPUVA で次のいずれかを参照できます。

  • システム メモリ。常に 4 KB の細分性で割り当てられます。
  • メモリ セグメント ページ。4 KB または 64 KB で管理できます。

ビデオ メモリ マネージャー (VidMm) は、複数のレベルのページ テーブルを使用して仮想アドレスを変換するマルチレベル仮想アドレス変換スキームをサポートしています。

  • レベルには 0 から番号が付けられます。 レベル 0 はリーフ レベルに割り当てられます。
  • 翻訳は、ルート レベルのページ テーブルから開始されます。

ページ テーブル レベルの数が 2 の場合、ルート レベルのページ テーブルのサイズを変更して、GPUVA 領域の可変サイズのプロセスに対応できます。 すべてのレベルは、DxgkDdiQueryAdapterInfo 呼び出し中にカーネル モード ディスプレイ ドライバー (KMD) が入力するDXGK_PAGE_TABLE_LEVEL_DESC構造体によって記述されます。 KMD は、GPUVA のサポートを説明するために DXGK_GPUMMUCAPS caps 構造体にも記入します。

各プロセスには、独自の GPUVA 領域があります。 プロセスのグラフィックス コンテキストを実行用に設定する前に、KMD の DxgkDdiSetRootPageTable 関数を呼び出して、ルート ページ テーブルのアドレスを設定します。

2 つのページ テーブル レベルの場合の仮想アドレス変換を次の図に示します。

2 つのページ テーブル レベルの仮想アドレス変換を示す図。

  • GPUVA には 、DXGK_GPUMMUCAPS::VirtualAddressBitCount ビットがあります。

  • 下位ビット [0 - 11] は、ページ内のオフセットをバイト単位で表します。

  • のDXGK_PAGE_TABLE_LEVEL_DESC::PageTableIndexBitCount ビットは、リーフ レベルのページ テーブル内のページ テーブル エントリのインデックスを表します。

  • ページ テーブル内のエントリの数は 2DXGK_PAGE_TABLE_LEVEL_DESC::P ageTableIndexBitCount で、ページ テーブルのサイズは DXGK_PAGE_TABLE_LEVEL_DESC::PageTableSizeInBytes バイトです。

  • 残りのビットは、ルート ページ テーブル内のページ テーブル エントリへのインデックスを表します。 ルート ページ テーブルは、2 レベルの変換スキームのサイズ変更が可能です。 DxgkDdiGetRootPageTableSize DDI は、そのサイズを取得します。

DXGK_PTE構造体は、ページ テーブルエントリを表すために DDI を介して使用されます。 この構造体は、DirectX グラフィックス カーネル (Dxgkrnl) が管理する各エントリに関する情報を表します。 ドライバーは、この情報を使用して、ハードウェア固有のページ テーブル エントリを作成します。

ページ テーブルの割り当ての作成

ページ テーブルは暗黙的な割り当てとして作成され、ユーザー モード ドライバー (UMD) または KMD ハンドルがありません。

ページ テーブルを割り当てるために、VidMm、DXGK_PAGE_TABLE_LEVEL_DESC::PageTableSegmentId で指定されたセグメントからサイズ DXGK_PAGE_TABLE_LEVEL_DESC::PageTableSizeInBytes の割り当てを割り当てます。 作成後、 VidMm はページ テーブル内のすべてのエントリを 無効に初期化します。 2 レベルの変換スキームのルート ページ テーブルを除き、ページ テーブルのサイズは変更されません。

VidMm では、2 レベルの変換スキームでのルート ページ テーブルのサイズ変更がサポートされています。 指定した量のアドレス空間をカバーするルート ページ テーブルが作成されると、 VidMmDxgkDdiGetRootPageTableSize を呼び出して、それに必要な割り当てサイズを決定します。 VidMm は次に、ルート レベルで DXGK_PAGE_TABLE_LEVEL_DESC::PageTableSegmentId で指定されたセグメント内に、そのサイズのアロケーションを行います。 作成後、 VidMm は、新しい UpdatePageTable ページング操作を使用して、ページ テーブル内のすべてのエントリを無効に初期化します。 ルート ページ テーブルは、プロセスで必要なビデオ アドレス空間の量が増減するにつれて拡大または縮小できます。 ルート ページ テーブルが作成されると、 VidMmDxgkDdiSetRootPageTable を呼び出して、新しく作成されたルート ページ テーブルを、内部で実行されるさまざまなコンテキストに関連付けます。

リンク表示アダプター構成では、ルート ページ テーブルは LinkMirrored 割り当てとして作成されます。 これらの割り当てには同じコンテンツがあり、リンク内の各 GPU 上の同じ物理アドレスに配置されます。 下位レベルのページ テーブルは LinkInstanced 割り当てとして割り当てられ、通常はピア マッピングが異なるため、GPU 間でコンテンツが異なる可能性があることを反映します。 ページ テーブルの内容は、すべての GPU で個別に更新されます。

ルート ページ テーブルの拡大と縮小

このセクションは、2 レベルのページ テーブルを持つシステムにのみ適用されます。 ページ テーブル レベルの数が 2 より大きい場合、各レベルのページ テーブル サイズは仮想アドレス指定キャップによって定義され、固定されます。

UMD が GPUVA を要求すると、 VidMm は要求に対応するためにプロセスのアドレス空間のサイズを拡大します。 これを行うには、現在のルート ページ テーブルのサイズを増やし (必要な場合)、新しい範囲に新しいページ テーブルを割り当てる必要があります。

ルート ページ テーブルを拡張するために 、VidMm は別のルート ページ テーブルの割り当てを作成し、常駐させ、エントリを初期化し、古い割り当てを破棄します。 DxgkDdiGetRootPageTableSize 関数は、新しいページ テーブルのサイズをバイト単位で取得するために使用されます。

ルート ページ テーブルを圧縮するために、 VidMm は新しいページ テーブルの割り当てを作成し、常駐させ、古いページ テーブルの一部を新しいページ テーブルにコピーし、古い割り当てを破棄します。

サイズ変更操作が完了すると、 VidMmは DxgkDdiSetRootPageTable を呼び出して、影響を受けるコンテキストを新しいルート ページ テーブルに関連付けます。

ページ テーブルの更新

サーフェスがメモリ内を移動すると、 VidMm はページ テーブルの内容を更新して、サーフェスの新しい位置を反映します。

ページ テーブルの移動

* VidMm は、デバイスがアイドル状態または中断状態のときに、ページ テーブルを再配置または削除できます。 VidMm は、ページ テーブルを移動すると、ページ テーブルの新しい場所を参照するように上位レベルのページ テーブルを更新します。

ルート ページ テーブル自体が再配置されると、 VidMmDxgkDdiSetRootPageTable を呼び出して、影響を受けるコンテキストにページ ディレクトリの新しい場所を通知します。

物理ページサイズ

既に説明したように、 VidMm では 2 つのページ サイズがサポートされています。 システム メモリは常に 4 KB ページで管理されますが、メモリ セグメントは KMD によって決定される 4 KB または 64 KB の粒度で管理できます。

仮想メモリを 64 KB ページで管理することを選択すると、すべての割り当てが自動的に調整され、64 KB の倍数にサイズ設定されます。

すべての割り当てを 64 KB に拡張すると、メモリに大きな影響を与える可能性があります。 UMD は、メモリの無駄を回避するために、小さな割り当てを大きな割り当てにパックする役割を担います。

VidMm は、GPUVA を 64 KB の大きなメモリ セグメント ページにマップすると、4 KB のページ テーブル エントリをメモリ セグメント内の 16 ページの連続した 4 KB にマップします。 仮想アドレスと物理アドレスの両方が、同じ 64 KB のアラインメントを共有することが保証されます。 つまり、仮想アドレスの下位 16 ビットと物理アドレスが一致することが保証されます。