コマンド リストの実行と同期

Microsoft Direct3D 12 には、前バージョンの即時モードがなくなりました。 代わりに、アプリではコマンド リストやバンドルを作成してから、一連の GPU コマンドを記録します。 実行されるコマンド一覧の送信にコマンド キューが使用されます。 このモデルでは、GPU (グラフィックス処理ユニット) と CPU の両方の効率的使用を開発者がさらに細かく制御できます。

コマンド キューの概要

Direct3D 12 のコマンド キューは、ランタイムとドライバーによるイミディエイト モード作業提出の同期に代わる機能です。これまでは開発者に公開されていませんでしたが、現在では API を使用して明示的に同時実行、並列、同期を管理できるようになりました。 コマンド キューは、開発者から見ると次の点が向上しています。

  • 予期しない同期が原因で起きる、偶発的な効率低下を回避できます。
  • 同期をより上のレベルで行うことができるので、必要な同期を効率的かつ正確に特定できます。 つまり、ランタイムとグラフィックス ドライバーが事後対応的に並列性を組み立てるための時間が少なくなります。
  • 高コストな操作をより明示的に行います。

これらの改善によって、次のようなシナリオが実現し、あるいはさらに強化されます。

  • さらなる並列化: アプリケーションのフォアグラウンド作業用にキューを用意し、それとは別の深いキューをバックグラウンドのワークロード (たとえば動画のデコード) に使用できます。
  • 非同期で低優先度の GPU 作業: コマンド キュー モデルでは、低優先度 GPU 作業の同時実行とアトミック操作が可能になります。したがって、ある GPU スレッドが別の非同期スレッドの結果を使用するときにブロッキングは不要になります。
  • 高優先度の計算作業: この設計では、3D レンダリングを中断して少量の高優先度計算作業を行うことが可能になります。結果を早く得て、それ以降の CPU での処理に使用できます。

コマンド キューの初期化

コマンド キューを作成するには、ID3D12Device::CreateCommandQueue を呼び出します。 このメソッド は、作成 する必要があるキューの種類と、そのキューに送信できるコマンドの種類を示すD3D12_COMMAND_LIST_TYPEを受け取ります。 既に説明したとおり、バンドルは直接コマンド リストからの呼び出しだけが可能であり、キューに直接送ることはできません。 サポートされているキューの種類は次のとおりです。

一般的に、DIRECT のキューとコマンド リストはどのようなコマンドも受け取り、COMPUTE のキューとコマンド リストは計算とコピーに関連するコマンドを受け取り、COPY のキューとコマンド リストはコピーのコマンドのみを受け取ります。

コマンド リストの実行

コマンド リストの記録が完了し、既定のコマンド キューを取得するか新規作成したら、ID3D12CommandQueue::ExecuteCommandLists を呼び出してコマンド リストを実行します。

アプリケーションでは、コマンド リストをどのコマンド キューにも、複数のスレッドから提出できます。 ランタイムは、これらの要求をシリアル化する作業を、提出された順に行います。

ランタイムは提出されたコマンド リストを評価し、なんらかの制限に違反している場合は ExecuteCommandLists の呼び出しを破棄します。 呼び出しが破棄される理由は、次のようなものがあります。

リソースに複数のコマンド キューからアクセスする

ランタイムから課せられるルールによって、リソースへの複数のコマンド キューからのアクセスが制限されています。 これらのルールを以下に示します。

  1. 1 つのリソースに複数のコマンド キューから同時に書き込むことはできません。 リソースがキューの書き込み可能な状態に移行した場合、そのリソースはそのキューによって排他的に所有されていると見なされ、別のキューからアクセスする前に読み取りまたは共通状態 ( D3D12_RESOURCE_STATESを参照) に移行する必要があります。

  2. 読み取り状態のときは、1 つのリソースを、その読み取り状態に基づいて複数のコマンド キューから同時に読み取ることができます。これらのキューがそれぞれ別のプロセスに属していてもかまいません。

リソース アクセスの制限の詳細と、リソース バリアを使用してリソースへのアクセスを同期する方法については、「リソース バリアを使用して、Direct3D 12 のリソースの状態を同期する」を参照してください。

コマンド キュー フェンスを使用してコマンド リストの実行を同期する

Direct3D 12 では複数の並列コマンド キューがサポートされているため、開発者が GPU での非同期作業の優先度をより柔軟かつ細かく制御できます。 この設計では、アプリが作業の同期を明示的に管理することも必要になります。特に、あるキュー内のコマンド リストが依存しているリソースが、別のコマンド キューでの操作の対象となっているときです。 たとえば、計算キューでの操作が完了するまで待ち、その後でその結果を 3D キューでのレンダリング操作に使用できるようにします。あるいは、3D 操作が完了するまで待ち、その後で計算キューでの操作でリソースに書き込みアクセスできるようにします。 キュー間の作業の同期を可能にするために、Direct3D 12 ではフェンスという概念が使用されています。API では、ID3D12Fence インターフェイスでこれを表しています。

フェンスは、現在どの作業単位が処理中かを表す整数です。 アプリで、フェンスを前進させるために ID3D12CommandQueue::Signal を呼び出すと、この整数が更新されます。 アプリでは、フェンスの値を調べると、ある作業単位が完了しているかどうかを判断できます。これに基づいて、後続の操作を開始できるかどうかを決定します。

コマンド キューによってアクセスされるリソースを同期する

Direct3D 12 では、リソースの状態を同期することはリソース バリアによって実装されます。 各リソース バリアの場所で、アプリはあるリソースの前と後の状態を宣言します。 典型的な例は、シェーダー リソース ビューとレンダー ターゲット ビューの間を遷移するリソースです。 ほとんどの場合、このようなリソース バリアはコマンド リストの中で管理されます。 デバッグ レイヤーが有効になっているときは、システムが強制的にすべてのリソースの前後の状態を一致させます。これによって、バリア遷移のときにリソースの状態が特定の操作に対して正しいことが保証されます。

リソース状態の同期については、「リソース バリアを使用して、Direct3D 12 のリソースの状態を同期する」を参照してください。

タイル リソースに対するコマンド キュー サポート

タイル リソースを管理するためのメソッドは、Direct3D 11 では ID3D11DeviceContext2 インターフェイスを通して公開されていましたが、Direct3D 12 では ID3D12CommandQueue インターフェイスにあります。 次のような方法を使用できます。

メソッド 説明
CopyTileMappings マッピングをコピー元のタイル リソースからコピー先のタイル リソースにコピーします。
UpdateTileMappings タイル リソース内のタイル位置からリソース ヒープ内のメモリ位置へのマッピングを更新します。

Direct3D 12 アプリでタイル リソースを使用する方法の詳細については、Direct3D11 のタイル リソースに関するページを参照してください。

Direct3D 12 での作業の送信