ルート署名の使用

ルート署名は、記述子テーブル (そのレイアウトを含む)、ルート定数、ルート記述子の任意に整理されたコレクションの定義です。 各エントリのコストには上限があるため、アプリケーションでは、ルート署名に含める各種エントリの数との間でバランスを取ることができます。

ルート署名は、API で手動の指定によって作成できるオブジェクトです。 PSO のすべてのシェーダーは、PSO で指定されたルート レイアウトと互換性を持つ必要があります。または、個々のシェーダーに、相互に一致する埋め込みルート レイアウトを含める必要があります。このようにしないと、PSO の作成は失敗します。 ルート署名の 1 つの特性は、ルート署名が作成された場合にそれについてシェーダーが知る必要がないことです。ただし、ルート署名は、必要に応じてシェーダーで直接作成することもできます。 ルート署名と互換性を持たせるために、既存のシェーダー資産を変更する必要はありません。 シェーダー モデル 5.1 が導入され、柔軟性 (シェーダー内からの記述子のインデックスの動的作成) が向上しました。このシェーダー モデルは、必要に応じて、既存のシェーダー資産から段階的に採用できます。

コマンド リストのセマンティクス

コマンド リストの先頭では、ルート署名は定義されません。 グラフィックス シェーダーには、計算シェーダーからの個別のルート署名があり、コマンド リストでそれぞれ独立して割り当てられます。 また、コマンド リストまたはバンドルで設定するルート署名は、描画/ディスパッチで現在設定されている PSO に一致させる必要があります。このようにしないと、動作が定義されません。 描画/ディスパッチが適正になるまで、一時的なルート署名は一致しません。たとえば、互換性のあるルート署名に切り替える前に非互換の PSO を設定する場合などです (描画/ディスパッチが呼び出されるまでこれらが互換性を持つ場合に限る)。 PSO を設定しても、ルート署名は変更されません。 アプリケーションでは、ルート署名を設定するために、専用の API を呼び出す必要があります。

コマンド リストにルート署名が設定されると、アプリケーションが提供する予定の一連のバインディングと、次の描画/ディスパッチの呼び出しで使用できる PSO (同じレイアウトでコンパイル済み) がレイアウトによって定義されます。 たとえば、アプリケーションで、次のエントリがあるルート署名を定義できます。 各エントリは "スロット" と呼ばれます。

  • [0] CBV 記述子インライン (ルート記述子)
  • [1] 2 つの SRV、1 つの CBV、および 1 つの UAV を含む記述子テーブル
  • [2] 1 つのサンプラーを含む記述子テーブル
  • [3] ルート定数の 4 x 32 ビット コレクション
  • [4] 指定されていない数の SRV を含む記述子テーブル

この場合、Draw/Dispatch を発行する前に、アプリケーションは、アプリケーションが現在のルート署名で定義した各スロット [0..4] に適切なバインドを設定する必要があります。 たとえば、スロット [1] では、記述子テーブルをバインドする必要があります。記述子テーブルは、2 つの SRV、1 つの CBV、1 つの UAV を含む (または実行時に含まれる) 記述子ヒープ内の連続した領域です。 同様に、記述子テーブルはスロット [2] と [4] で設定する必要があります。

アプリケーションで、一度に変更できるのはルート署名バインディングの一部です (残りの部分は変更されません)。 たとえば、描画の間で変更する必要があるのがスロット [2] の定数の 1 つである場合、アプリケーションで再バインドする必要があるのはすべてです。 前述のとおり、ドライバー/ハードウェア バージョンのすべてのルート署名のバインド状態は自動的に変更されます。 コマンド リストでルート署名が変更されると、前のすべてのルート署名バインディングが古くなり、描画/ディスパッチの前に、新しく予定されているすべてのバインディングを設定する必要があります。このようにしないと、動作が定義されません。 ルート署名が、現在の設定に重複して設定されている場合、既存のルート署名バインディングは古くなりません。

バンドルのセマンティクス

バンドルは、コマンド リストのルート署名バインディング (上記のコマンド リストの例では各種スロットへのバインディング) を継承します。 バンドルで継承された一部のルート署名バインディングを変更する必要がある場合、ルート署名が呼び出し元のコマンド リストと同じになるように最初に設定する必要があります (継承されたバインディングは古くなりません)。 バンドルで、呼び出し元のコマンド リストとは異なるルート署名を設定する場合、前述したコマンド リストでのルート署名の変更と同じ影響があります。つまり、前のすべてのルート署名バインディングは古くなり、描画/ディスパッチの前に新しく予定されているバインディングを設定する必要があります。このようにしないと、動作が定義されません。 バンドルでルート署名バインディングを変更する必要がない場合、ルート署名を設定する必要はありません。

次のコードは、バンドルの呼び出しフローの例です。

// Command List
...
pCmdList->SetGraphicsRootSignature(pRootSig); // new parameter space
MyEngine_SetTextures(); // bundle inherits descriptor table setting
MyEngine_SetAnimationFactor(fTime); // bundle inherits root constant
pCmdList->ExecuteBundle(...);
...
// Bundle
pBundle->SetGraphicsRootSignature(pRootSig); // same as caller, in order to inherits bindings
pBundle->SetPipelineState(pPS); 
pBundle->SetGraphicsRoot32BitConstant(drawConstantsSlot,0,drawIDOffset);
pBundle->Draw(...); // using inherited textures / animation factor
pBundle->SetGraphicsRoot32BitConstant(drawConstantsSlot,1,drawIDOffset);
pBundle->Draw(...);
...

バンドルから発生し、バンドルで行われるルート レイアウトの変更やバインディングの変更は、バンドルの実行終了時に呼び出し元のコマンド リストに再継承されます。

継承の詳細については、「Direct3D 12 でのグラフィックス パイプライン状態の管理」の「グラフィックス パイプライン状態の継承」セクションを参照してください。

ルート署名