Direct3D 12 でグラフィックス パイプラインの状態を管理する

このトピックでは、Direct3D 12 でグラフィックス パイプラインの状態を設定する方法について説明します。

パイプラインの状態の概要

ジオメトリを GPU (グラフィックス処理装置) に提出して描画するときに、入力データをどのように解釈してレンダリングするかを決定するための、さまざまなハードウェア設定があります。 これらの設定は "グラフィックス パイプラインの状態" と総称され、これに含まれるものとしては共通の設定 (ラスタライザーの状態、ブレンドの状態、深度ステンシルの状態など) に加えて、提出されたジオメトリのプリミティブ トポロジの種類や、レンダリングに使用されるシェーダーがあります。 Microsoft Direct3D 12 では、グラフィックス パイプラインの状態のほとんどはパイプライン状態オブジェクト (PSO) を使用して設定されます。 1 つのアプリで作成できるこのオブジェクトの数に制限はありません。オブジェクトは ID3D12PipelineState インターフェイスで表現され、一般的には初期化時に作成されます。 レンダリング時に、コマンド リストの中でパイプラインの状態の複数の設定をすばやく切り替えることができます。このようにするには、直接コマンド リストまたはバンドルの中で ID3D12GraphicsCommandList::SetPipelineState を呼び出してアクティブな PSO を設定します。

Direct3D 11 では、グラフィックス パイプラインの状態は ID3D11BlendState などの大きく、粗粒度の状態オブジェクトとしてまとめられていました。このオブジェクトはイミディエイト コンテキストでのレンダリング時に ID3D11DeviceContext::OMSetBlendState などのメソッドを使用して作成され、設定されていました。 この背景にあったのは、関連する設定 (たとえばブレンド状態の設定) を一度にまとめて設定すれば GPU の効率が向上するという考えです。 ただし、今日のグラフィックス ハードウェアでは、さまざまなハードウェア ユニット間に依存関係があります。 たとえば、ハードウェアのブレンドの状態は、ブレンドの状態だけでなくラスターの状態にも依存します。 Direct3D 12 の PSO は、GPU が各パイプライン状態の中のすべての従属設定を前処理できる (一般的には初期化時に) ように設定されています。これは、レンダリング時の状態の切り替えをできる限り効率的に実行できるようにするためです。

パイプラインの状態の設定のほとんどは PSO を使用して設定されますが、独立して設定される状態設定もあり、そのための API が ID3D12GraphicsCommandList として用意されています。 これらの設定と関連する API については、後で詳しく説明します。 また、グラフィックス パイプラインの状態がどのように継承され、永続化されるかについて、直接コマンド リストとバンドルでは違いがあります。 このトピックでは、これらの両方について詳しく説明します。

パイプライン状態オブジェクトを使用して設定されるグラフィックス パイプラインの状態

パイプライン状態オブジェクトを使用して設定できるさまざまなパイプライン状態をすべて表示する最も簡単な方法は、オブジェクトを初期化するときに ID3D12Device::CreateGraphicsPipelineState に渡すD3D12_GRAPHICS_PIPELINE_STATE_DESCのリファレンス トピックを参照することです。 設定できる状態を簡単にまとめると、次のようになります。

  • すべてのシェーダー (頂点、ピクセル、ドメイン、ハル、およびジオメトリの各シェーダーを含む) のバイトコード。
  • 入力頂点の形式。
  • プリミティブ トポロジの種類。 入力アセンブラープリミティブトポロジタイプ(ポイント、ライン、三角形、パッチ)は、 D3D12_PRIMITIVE_TOPOLOGY_TYPE 列挙を使用してPSO内で設定されることに注意してください。 プリミティブの隣接性と順序 (線リスト、線ストリップ、隣接データ付き線ストリップなど) は、コマンド リストの中で ID3D12GraphicsCommandList::IASetPrimitiveTopology メソッドを使用して設定されます。
  • ブレンドの状態、ラスタライザーの状態、深度ステンシルの状態。
  • 深度ステンシルとレンダー ターゲットの形式、およびレンダー ターゲットの数。
  • マルチサンプリング パラメーター。
  • ストリーミング出力バッファー。
  • ルート署名。 詳細については、「ルート署名」を参照してください。

パイプライン状態オブジェクトを使用せずに設定されるグラフィックス パイプラインの状態

グラフィックス パイプラインの状態のほとんどは PSO を使用して設定されます。 ただし、パイプラインの状態のパラメーターには、コマンド リストの中から ID3D12GraphicsCommandList インターフェイスのメソッドを呼び出して設定されるものもあります。 次の表は、この方法で設定される状態とそれに対応するメソッドをまとめたものです。

状態 メソッド
リソース バインディング IASetIndexBuffer
IASetVertexBuffers
SOSetTargets
OMSetRenderTargets
SetDescriptorHeaps
すべての SetGraphicsRoot... メソッド
すべての SetComputeRoot... メソッド
ビューポート RSSetViewports
シザリング四角形 RSSetScissorRects
ブレンド係数 OMSetBlendFactor
深度ステンシル参照値 OMSetStencilRef
入力アセンブラー プリミティブ トポロジの順序と隣接性の種類 IASetPrimitiveTopology

グラフィックス パイプラインの状態の継承

直接コマンド リストは一般的に一度に 1 回使用することを意図しており、バンドルは同時に複数回使用することを意図しているため、前のコマンド リストまたはバンドルで設定されたグラフィックス パイプラインの状態を継承する方法の規則についても、この 2 つの間に違いがあります。

PSO を使用して設定されるグラフィックス パイプラインの状態については、直接コマンド リストとバンドルのどちらも、状態を継承することはありません。 最初のグラフィックス パイプラインの状態は、直接コマンド リストとバンドルのどちらの場合も、作成時に ID3D12Device::CreateCommandListID3D12PipelineState パラメーターで設定されます。 この呼び出しで PSO が指定されていない場合は、既定の初期状態が使用されます。 コマンド リストの中で現在の PSO を変更するには、ID3D12GraphicsCommandList::SetPipelineState を呼び出します。

直接コマンド リストでは、RSSetViewports のようなコマンド リストのメソッドを使用して設定された状態も継承されません。 PSO ではない状態の既定の初期値の詳細については、ID3D12GraphicsCommandList::ClearState を参照してください。

バンドルでは、PSO を使用せずに設定されるすべてのグラフィックス パイプラインの状態が継承されます。ただし、プリミティブ トポロジの種類を除きます。 プリミティブ トポロジは、バンドルの実行が開始されたときに常に D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED に設定されます。 バンドルの中で設定されている状態 (PSO 自体、PSO に基づくものではない状態、およびリソース バインディング) は、その親である直接コマンド リストの状態に影響します。 たとえば、バンドル内から RSSetViewports が呼び出された場合、指定されたビューポートは、ビューポートを設定する ExecuteBundle 呼び出しの後の呼び出しに対して親直接コマンド リストに設定され続けます。

コマンド リストまたはバンドルの中で設定されるリソース バインディングは永続的です。 したがって、直接コマンド リストの中でリソース バインディングに変更を加えると、その設定は後続の子バンドルの実行の中でも引き続き存在します。 また、バンドルの中でリソース バインディングに変更を加えると、その設定は親である直接コマンド リスト内の後続の呼び出しに対しても引き続き存在します。

バインドの詳細については、「ルート署名の使用」の「バンドルのセマンティクス」のセクションを参照してください。