コマンド リストのサポート

このセクションは、Windows 7 以降、および Windows Server 2008 R2 以降のバージョンの Windows オペレーティング システムのみを対象としています。

Direct3D ランタイムは、コマンド リストに次の Direct3D 11 DDI を使用します。

  • CalcPrivateCommandListSize 関数は、コマンド リストのユーザー モード ディスプレイ ドライバーのメモリのプライベート領域のサイズを決定します。

  • CreateCommandList 関数は、コマンド リストを作成します。

  • RecycleCommandList 関数は、コマンド リストをリサイクルします。

  • RecycleCreateCommandList 関数は、コマンド リストを作成し、以前に使用されていない DDI ハンドルをもう一度完全に有効にします。

  • DestroyCommandList 関数は、コマンド リストを破棄します。

  • RecycleDestroyCommandList 関数は、コマンド リストの軽量な破棄が必要であることをドライバーに通知します。

  • CommandListExecute 関数は、コマンド リストを実行します。

ドライバーの CommandListExecuteCalcPrivateCommandListSizeCreateCommandListDestroyCommandList 関数のセマンティクスは、他の同様の DDI 関数と、対応する DDI の API ドキュメントに基づき、ほとんどは自明です。

Direct3D ランタイムは、pCreateCommandList パラメーターが指す D3D11DDIARG_CREATECOMMANDLIST 構造体の hDeferredContext メンバーで指定されている遅延コンテキストでドライバーの CreateCommandList または RecycleCreateCommandList 関数を正常に呼び出した後、Direct3D ランタイムは遅延コンテキストに対して次の破棄シーケンスを実行します。

  1. Direct3D ランタイムは、開いているすべての遅延オブジェクト ハンドルを "閉じます" 。 これらのハンドルは引き続き遅延コンテキストにバインドされている可能性があることに注意してください。

  2. ランタイムは遅延コンテキストを破棄します。

CreateCommandList または RecycleCreateCommandList の呼び出し中に、ドライバーが状態更新 DDI コールバック関数に対して行うすべての呼び出しは、遅延コンテキストの現在の状態を引き続き漏えいします。 ただし、遅延コンテキストの "終了中" および破棄中に、状態更新 DDI の呼び出しには、何もバインドされていないことが反映されます (つまり、CreateCommandList または RecycleCreateCommandList の呼び出しの直後に、すべてが暗黙的にバインド解除されます)。

遅延コンテキストは、アプリケーションによって明示的に破棄することも、API またはドライバーによるエラー状態が原因で破棄することもできます。 このような場合、Direct3D ランタイムは次のシーケンスを実行します。

  1. Direct3D ランタイムは、ドライバーの AbandonCommandList 関数を呼び出します。

  2. ランタイムは、遅延コンテキストからハンドルを 1 つずつバインド解除します。

  3. ランタイムは、開いているすべての遅延オブジェクト ハンドルを "閉じます" 。

  4. ランタイムは遅延コンテキストをリサイクルまたは破棄します。

上記のシーケンスは、即時コンテキストの破棄シーケンスに似ています。 ドライバーの AbandonCommandList 関数の呼び出しは、ドライバーが好むものに状態を適用する機会を提供します。

ドライバーの CommandListExecute 関数の呼び出し中に、ドライバーは、デバイスが作成されたときの状態と同等になるように遅延コンテキストの状態を遷移する必要があります。 この操作は、状態クリア操作とも呼ばれます。 ただし、ドライバーの CommandListExecute 関数の呼び出し中に、ドライバーが状態更新 DDI コールバック関数に対して行った呼び出しには、ドライバー関数への最後の DDI 呼び出し中にバインドされたものの状態が反映されます。 ドライバー関数への次の DDI 呼び出し中に、ドライバーが状態更新 DDI コールバック関数に対して行う呼び出しでは、現在の状態が完全に空として表示されます。これは、CommandListExecute からの暗黙的な状態遷移を反映します。 これは、状態更新 DDI コールバック関数の一般的なセマンティクスと動作とは若干異なります。 ドライバーの SetShader 関数の 1 つへの呼び出し中に、ドライバーが状態更新 DDI コールバック関数を呼び出した場合、状態更新 DDI コールバック関数は、バインドされている新しいシェーダーが既にバインドされていると表示されます。 この状態更新 DDI コールバック動作の相違により、CommandListExecute 中に古い状態を反映するドライバーの柔軟性が向上します。

Direct3D バージョン 11 API を使用すると、コマンド リストによってクエリの両方が操作され (QueryBegin または QueryEnd が呼び出された)、コマンド リストの実行を試みるコンテキストによってのみ "開始" されます。 また、API は、動的リソースのマップを記録したコマンド リストが、現在マップされている同じリソースを持つコンテキストで実行されないようにします。 アプリケーションが FinishCommandList 関数を呼び出す前に、Direct3D ランタイムは、開始されたクエリまたはマップされたリソースを開いたままのクエリまたは動的リソースに対してドライバーの QueryEnd および ResourceUnmap DDI 関数を呼び出します。それは、FinishCommandList がクエリ範囲を暗黙的に終了し、マップされたリソースのマップを解除するためです。

小さなコマンド リストの最適化

コマンド リスト DDI 関数呼び出し間の競合を減らし、コマンド リストに必要な呼び出し処理のオーバーヘッドを減らすには、メモリ使用量の少ないコマンド リストのメモリリサイクルの最適化が重要な場合があります。 各コマンド リストで一貫性を持たない処理オーバーヘッドは重要です。 この最適化は、コマンド リストに必要な処理オーバーヘッドが、コマンド リストに必要な CPU 時間とメモリ領域を占めるコマンド リストを対象としています。 メモリ使用量の少ないコマンド リストは、たとえば、CopyResource などの 1 つのグラフィックス コマンドです。 CopyResource に必要なメモリ量は 2 つのポインターです。 ただし、CopyResource では、大量のコマンド リストと同じ量のコマンド リスト呼び出し処理が必要です。 メモリ使用量の少ないコマンド リストが高頻度で生成される場合、ランタイムがドライバーの CreateCommandListDestroyCommandListCreateDeferredContextDestroyDevice (D3D10) 関数を呼び出すために必要な処理オーバーヘッドがますます重要になります。 ここで参照するメモリは、DDI ハンドルのメモリを含むドライバー データ構造を保持するシステム メモリです。

ドライバーの RecycleCommandList 関数は、ドライバー ハンドルが使用されなくなったときに (まだ削除されていない)、これまで未使用だったドライバー ハンドルが再利用されたときに、ドライバーに通知する必要があります。 この通知は、コマンド リスト ハンドルと遅延コンテキスト ハンドルの両方に適用されます。 ドライバーがリサイクルする必要がある唯一のメモリは、DDI ハンドルが指すメモリです。 RecycleCommandList の目的はハンドルに関連付けられているメモリをリサイクルすることですが、効率を高めるために、ドライバーはリサイクルするメモリを選択できる完全な柔軟性を備えています。 ドライバーは、即時コンテキスト コマンド リストがポイントするメモリ領域のサイズを変更できません。 このサイズは、CalcPrivateCommandListSize の 戻り値です。 また、ドライバーは、コンテキスト コマンド リストのローカル ハンドルが指すメモリ領域のサイズを変更することもできません。このサイズは、CalcDeferredContextHandleSize の戻り値 です。

ドライバーの RecycleCreateCommandList 関数と RecycleCreateDeferredContext DDI 関数は、E_OUTOFMEMORY HRESULT 値メモリ不足エラー コードを返す必要があります。 これらの関数は、pfnSetErrorCb 関数の呼び出しを 通じてこのようなエラー コードを提供しません。 このドライバー要件により、ランタイムはデバイス全体の同期を使用して、これらの作成型ドライバー関数からの即時コンテキスト エラーを監視する必要がありません。 これらのエラーを監視することは、メモリ使用量の少ないコマンド リストに対する致命的な競合の原因になります。

ドライバーの RecycleDestroyCommandListRecycleCommandList、および RecycleCreateCommandList 関数の違いは重要です。 使用できる機能には、次のようなものがあります。

RecycleDestroyCommandList

ランタイムは、ドライバーの RecycleDestroyCommandList 関数を呼び出して、軽量の破棄が必要であることをドライバーに通知します。 したがって、ドライバーはまだ DDI コマンド リスト ハンドルのメモリを割り当て解除できません。 ドライバーの RecycleDestroyCommandList 関数は、ドライバーの DestroyCommandList 関数と同様にフリー スレッドです。

RecycleCommandList

ドライバーの RecycleCommandList 関数は、ランタイムが遅延コンテキスト キャッシュにコマンド リスト ハンドルを統合したことをドライバーに通知します。 次に、この関数は、コマンド リストに関連付けられているメモリを遅延コンテキスト キャッシュに統合する機会をドライバーに提供します。 ランタイムは、遅延コンテキスト スレッドからドライバーの RecycleCommandList 関数を呼び出します。 RecycleCommandList DDI 関数を使用すると、ドライバーが独自の同期を実行する必要性が減ります。

RecycleCreateCommandList

ランタイムは、ドライバーの RecycleCreateCommandList 関数を呼び出して、これまで未使用だった DDI ハンドルをもう一度完全に有効にします。

これらのリサイクル DDI 関数は、メモリ使用量の少ないコマンド リストのリソースをリサイクルするのに役立つ最適化の機会を提供します。 次の擬似コードは、API から DDI への関数呼び出しのフローを介したランタイムの実装を示しています。

::FinishCommandList()
{
  // Empty InterlockedSList, integrating into the cache
  Loop { DC::pfnRecycleCommandList }

  If (Previously Destroyed CommandList Available)
 { IC::pfnRecycleCreateCommandList }
 else
  {
    IC::pfnCalcPrivateCommandListSize
    IC::pfnCreateCommandList
    IC::pfnCalcDeferredContextHandleSize(D3D11DDI_HT_COMMANDLIST)
  }

  Loop { DC::pfnDestroy* (context-local handle destroy) }

  IC::pfnRecycleCreateDeferredContext
}
...
Sporadic: DC::pfnCreate* (context-local open during first-bind per CommandList)

CommandList::Destroy()
{
  // If DC still alive, almost always recycle:
  If (DC still alive)
 { IC::pfnRecycleDestroyCommandList }
  Else
 { IC::pfnDestroyCommandList }
  // Add to InterlockedSList
}

次の状態図は、即時コンテキスト DDI コマンド リスト ハンドルの有効性を示しています。 緑色の状態は、CommandListExecute で使用できるハンドルを表します。

即時コンテキスト DDI コマンド リスト ハンドルの有効性状態を示している図。