Direct3D® 12 フリップモデルのスワップチェーンのサンプル・アプリケーション

この記事は、インテル® デベロッパー・ゾーンに公開されている「Sample Application for Direct3D 12 Flip Model Swap Chains」の日本語参考訳です。


この記事の PDF 版はこちらからご利用になれます。

サンプルコード

D3D12 のほうが D3D11 よりもスワップチェーンを使用する方法が複雑になっています。D3D12 では、フリップモデル [1] のスワップチェーンのみ使用できます。バッファーの数、インフライト・フレームの数、現在の SyncInterval、WaitableObject 使用の有無など、多数の引数を選択する必要があります。このサンプル・アプリケーションは、異なる引数の相互作用を理解し、最適な引数の組み合わせを見つけられるように作成されました。

レンダリングされたフレームが CPU から GPU へ移行する様子をインタラクティブに視覚化し、現在のキューの状態を表示します。すべての引数はリアルタイムに変更できます。フレームレートとレイテンシーへの影響は、オンスクリーンの統計から確認できます。

Direct3D® サンプル・アプリケーション

図 1: 注釈付きのサンプル・アプリケーションのスクリーンショット

スワップチェーンの引数

以下は、D3D12 スワップチェーンの検証に使用した引数です。

引数 説明
Fullscreen (フルスクリーン) ウィンドウがスクリーンを覆う場合 (つまり、ボーダーレス・ウィンドウ・モードの場合) は True です。注: 排他モードの SetFullscreenState とは異なります。
vsync (垂直同期) Present() 関数の SyncInterval 引数を制御します。
Use Waitable Object (待機可能オブジェクトの使用) スワップチェーンが DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT を利用して作成されたかどうかを示します。
Maximum Frame Latency (最大フレーム・レイテンシー) SetMaximumFrameLatency に渡される値です。“Use Waitable Object” が有効でない場合は無視されます。待機可能オブジェクトがない場合、有効な最大フレーム・レイテンシー は 3 です。
BufferCount (バッファーカウント) DXGI_SWAP_CHAIN_DESC1::BufferCount で指定される値です。
FrameCount (フレームカウント) 最初のゲームフレームの完了を待機する前に CPU で生成される “ゲームフレーム” の最大数です。ゲームフレームは、ユーザーデータ構造で、GPU での完了は D3D12 フェンスによって追跡されます。複数のゲームフレームが同じスワップ・チェーン・バッファーを指すことができます。

その他の引数

以下は、スワップチェーンの検証に使用した固定値の引数です。各引数が固定値である理由を示します。

引数 説明
Exclusive mode (排他モード) 現在の統計メカニズムは排他モードで動作しないため、SetFullscreenState がサンプル・アプリケーションで呼び出さることはありません。
SwapEffect (スワップエフェクト) DXGI_SWAP_CHAIN_DESC1::SwapEffect で指定される値です。常に DXGI_SWAP_EFFECT_FLIP_DISCARD に設定されます。DISCARD は、指定されることが最も少ない動作です。そのため、OS の柔軟性が高まり、表示が最適化されます。もう 1 つの選択肢 DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL は、以前の画像領域を再利用する操作 (例: 矩形のスクロール) でのみ有効です。

バッファーカウントとフレームカウントを理解する

バッファーカウントは、スワップチェーンに含まれるバッファーの数です。フリップモデルのスワップチェーンでは、表示中、オペレーティング・システムが vsync の期間全体にわたって 1 つのバッファーをロックすることがあります。そのため、アプリケーションが書き込み可能なバッファーの数は、実際には BufferCount-1 です。BufferCount = 2 の場合、OS が次の vsync でバッファーを解放するまで、書き込み可能なバッファーは 1 つのみです。そのため、フレームレートがリフレッシュ・レート未満に制限されます。

BufferCount >= 3 の場合、アプリケーションは少なくとも 2 つのバッファーを交互に利用できます (SyncInterval=0 と仮定)。そのため、フレームレートは無制限になります。

フレームカウントは、インフライトの “レンダーフレーム” の最大数です。レンダーフレームとは、GPU がレンダリングを実行する必要があるリソースとバッファーのセットです。FrameCount = 1 の場合、CPU は前のレンダーフレームが処理を完了するまで、次のレンダーフレームを構築しません。つまり、CPU と GPU が並列に実行するためには、FrameCount >= 2 でなければなりません。

最大フレーム・レイテンシーと “待機可能オブジェクト” によるレイテンシーの軽減方法

レイテンシーとは、フレームが生成されてから画面に表示されるまでの遅延時間です。そのため、一定間隔 (vsync) のディスプレイ・システムでレイテンシーを最大化するには、フレーム生成をできるだけ遅らせる必要があります。

キューにある操作の最大数を最大フレーム・レイテンシーと呼びます。この制限に達した後にアプリケーションがキューに操作を追加しようとすると、Present() はキュー内のフレームの 1 つが表示されるまでキューへの追加をブロックします。

Present 関数でのブロックは、フレーム生成とフレーム表示の間に発生するため、レンダースレッドがブロックされた分だけフレームのレイテンシーが増えます。このレイテンシーは、“待機可能オブジェクト” を使用することで排除できます。

概念上、待機可能オブジェクトは、最大フレーム・レイテンシーに初期化され、現在のキューから操作が削除されると通知を受け取るセマフォーと考えることができます。アプリケーションがレンダリングする前にセマフォーへの通知を待機する場合、キューは一杯ではなく (Present はブロックしないため)、レイテンシーは発生しません。

最適な引数の組み合わせ

検証の結果、要件に応じて 3 つの最適な値が分かりました。以下がゲームに最適な引数の組み合わせです。


Direct3D® ゲームモード

ゲームモード

  • vsync 有効
  • 3 バッファー、2 フレーム
  • 待機可能オブジェクトを使用、最大フレーム・レイテンシー 2

ゲームモードは、レイテンシーとスループットのバランスが良いモードです。


Direct3D® クラシックモード

クラシック・ゲーム・モード

  • vsync 有効
  • 3 バッファー、3 フレーム
  • 待機可能オブジェクトは使用しない

これは、D3D11 ではトリプルバッファーにより暗黙に行われていたため “クラシック” と呼びます。クラシック・ゲーム・モードはスループットを優先します。追加のフレームをキューに保持することで、変動に効率良く対応できますが、レイテンシーが増えます。


Direct3D® 最小レイテンシー

最小レイテンシー

  • vsync 有効
  • 2 バッファー、1 フレーム
  • 待機可能オブジェクトを使用、最大フレーム・レイテンシー 1

VR スタイルの vsync 高速化手法を使用しない、最小レイテンシーを提供します。アプリケーションが vsync をミスすると、フレームレートはすぐにリフレッシュの ½ に低下します。CPU と GPU は並列ではなく、シリアルに動作します。


アプリケーション・バージョン

ソースコードには、Windows® 10 ユニバーサル・アプリとしてサンプルをビルドするためのプロジェクト・ファイルが含まれています。Direct3D® コードとの違いは、CreateSwapChainForHWND の代わりに CreateSwapChainForCoreWindow を呼び出していることです。

参考文献

1 – “DXGI Flip Model”: https://msdn.microsoft.com/en-us/library/windows/desktop/hh706346%28v=vs.85%29.aspx (英語)

2 – ”DXGI 1.3 スワップ チェーンによる遅延の減少”: https://msdn.microsoft.com/ja-jp/library/windows/apps/dn448914.aspx

3 – DirectX 12: Presentation modes in Windows 10: https://www.youtube.com/watch?v=E3wTajGZOsA (英語)

4 – DirectX 12: Unthrottled Framerate: https://www.youtube.com/watch?v=wn02zCXa9IU (英語)

Microsoft、Direct3D、DirectX、および Windows は、米国 Microsoft Corporation の、米国およびその他の国における登録商標または商標です。

関連記事

  • Direct3D 12 概要 パート 6: コマンドリストDirect3D 12 概要 パート 6: コマンドリスト この記事は、インテル® デベロッパー・ゾーンに公開されている「Direct3D 12 Overview Part 6: Command Lists」の日本語参考訳です。 これまで、バンドル、PSO、記述子ヒープ&テーブルを通して、D3D 12 がどのように CPU […]
  • Direct3D 12 概要 パート 3: リソースバインドDirect3D 12 概要 パート 3: リソースバインド この記事は、インテル® デベロッパー・ゾーンに掲載されている「Direct3D 12 Overview Part 3: Resource Binding」の日本語参考訳です。 本シリーズの パート 2 では、パイプライン状態オブジェクトや PSO […]
  • ゲーム開発 – 第 6 世代インテル® Core™ プロセッサー向けグラフィックス API 開発者ガイドゲーム開発 – 第 6 世代インテル® Core™ プロセッサー向けグラフィックス API 開発者ガイド この記事は、インテル® デベロッパー・ゾーンに公開されている「Graphics API Developer’s Guide For 6th Generation Intel® Core™ Processors」の日本語参考訳です。 PDF (英語) のダウンロード [PDF: 2.3MB] 第 6 世代インテル® […]
  • Direct3D 12 概要 パート 2: パイプライン状態オブジェクトDirect3D 12 概要 パート 2: パイプライン状態オブジェクト この記事は、インテル® デベロッパー・ゾーンに掲載されている「Direct3D 12 Overview Part 2: Pipeline State Object 」の日本語参考訳です。 このシリーズの パート 1 で述べたように、D3D12 の主な目的は CPU のオーバーヘッドを軽減することでした。それは、CPU […]
  • Direct3D 12 概要 パート 5: バンドルDirect3D 12 概要 パート 5: バンドル この記事は、インテル® デベロッパー・ゾーンに公開されている「Direct3D 12 Overview Part 5: Bundles」の日本語参考訳です。 D3D 12 における新たしい描画コンテキストについては、説明を終えたと思います。これまで、D3D 12 がどのように 'ハードウェアに近い' […]