次の方法で共有


メモリ管理戦略

Direct3D 12 用のメモリ マネージャーを作成しようとすると、きわめて複雑なものになる可能性があります。サポートの階層は多岐にわたり、UMA と独立型 (ディスクリート) アダプターの両方への対応が必要であり、アーキテクチャは GPU アダプターごとに大きく異なるからです。

このセクションで説明されている Direct3D 12 メモリ管理に推奨される戦略は、"分類、予算、およびストリーム" です。

リソースの種類

"コミット済みリソース" という基本的な概念 (仮想と物理両方のアドレス空間を作成し、マネージドの物理メモリ内で初期化すること) は Direct3D 9 から存在していますが、Direct3D 12 では仮想アドレス指定 (VA) と物理アドレス指定を切り離すことが可能であり、アプリが物理メモリを慎重に管理できるようになっています。

コミット済みリソースに加えて、Direct3D 12 のヒープ構造では "配置済み" と "予約済み" の 2 つのリソースの種類を使用できます。 Direct3D 11 では、"予約済み" リソースは "タイル リソース" と呼ばれていました。

予約済みリソースと配置済みリソースの違いは、予約済みリソースには専用の一意の GPU 仮想アドレス空間があることです。 このことを利用すると、大きな VA 空間をあらかじめ割り当ててから、VA のページをヒープの特定のセクションにマッピングして、アプリケーションで配置を随時再構成することができます。 VA 空間は連続していますが、その空間へのマッピングは連続していなくてもかまいません。

予約済みリソースは、ヒープ内の領域を参照するように設定でき、それには UpdateTileMappings などの API 呼び出しを使用します。また、その領域を常駐にすることもでき、それにはアプリでページ テーブルを実行時に更新します。 ある範囲の VA のマッピング先が NULL または非常駐ヒープのときは、リソースのその部分は非常駐と見なされます。 ある範囲の VA のマッピング先が常駐ヒープのときは、リソースのその部分は常駐と見なされます。 ヒープは作成時に常駐となります。

配置済みリソースの設計ははるかに単純であり、ヒープの特定の領域 (たとえば 5 MB ヒープの中の、あるテクスチャ用の 1 MB の領域) へのポインターに過ぎません。 エイリアシング バリアを設定すると、複数の配置済みリソースで同じ領域を使用できるようになります (「CreatePlacedResource」および「ResourceBarrier」を参照してください)。

予約済みリソースはすべての Direct3D 12 ハードウェアで使用できるとは限りません。配置済みリソースは代替策として妥当ですが、配置済みリソースは連続している必要があり、部分的に常駐にすることはできません。

メモリのバジェット

Direct3D 12 では、アプリケーションがヒープを割り当てると、コミット済みリソースの物理メモリ部分が作成されることになります。 さらに明示的なメモリ セグメント選択も Direct3D 12 では可能です (ビデオ メモリかシステム メモリかを選択できます)。 UMA アダプターのメモリ セグメントはシステム メモリの 1 つだけです。

GPU ではページ フォールトがサポートされていないため、開発者はオーバー コミットしないように注意する必要があります (特に、システムのシステム メモリが 1 GB しかないような場合)。 アプリがオーバー コミットした場合は、OS は物理メモリに対する需要に応じてプロセスの粗粒度スケジューリングを行います。 スケジューラーがフォアグラウンド プロセスをフリーズさせ、実質的にその一部をページアウトするので、実行させたいバックグラウンド プロセスをページインできるようになります。 使用できる物理メモリの量は、ユーザーがバックグラウンドでしていること (ブラウザーの実行や、動画の視聴など) に応じて大きく変動します。

メモリ バジェットのための API は QueryVideoMemoryInfo です。 独立型 (ディスクリート) アダプターでは、"ローカル" はビデオ メモリで、"非ローカル" はシステム メモリです。 UMA アダプターでは、非ローカルは常に 0 です。 設計時に決定すべきことの 1 つに、エンジンで両方のバジェットを管理するか、ローカルのバジェットだけにするかがあります。 ローカルのバジェットだけを管理する方が単純ですが、いくつかの注意事項があります。たとえば、ローカル バジェットが最大 1 GB の場合に、UMA システムではすべてのヒープがその 1 GB から取得されるので、システム メモリへのオーバーフローはありません (ないことは明らかです)。

Direct3D 11 ではアプリケーション用のメモリが管理されていたため、未使用のリソースは実質的にページアウトされていました。

最も適切なリソース寸法を選択してください。 リソースのサイズが、そのアプリケーションが実際に実行される状況に対して適切かどうかを検討します。 ユーザーによっては、アプリケーションを実行するウィンドウや画面の解像度が 800 x 600 ということもあります。

分類戦略

メモリの制約のある状況で効果的にリソースを管理するには、リソースを次のように分類することを考慮します。

分類 オブジェクトと API の機能 管理に関する注意
Critical ゲーム UI コマンド アロケーター、コマンド キュー、クエリ ヒープ、リソース、リソース ヒープ。 これらの要素は、ページング不可能/常にコミットされるメモリに入れておく必要があります。
スケーリングされる/オプション レベル固有モデルとテクスチャ、スワップ チェーン、スカイ ボックス、一人称視点プレイヤー キャラクター モデル リソースおよびヒープ。 コミット済みリソース、ただし配置済みや予約済みのリソースでも同様に動作する可能性があります。 メモリ常駐バジェットの処理をレンダリング アルゴリズムに統合します。 適切なレベルの詳細さを選択し、フレームごとに 1 回以下の頻度で再評価します。 手法としては、可変サイズのリソースの使用やスワップ チェーンのスケーリングがあります。
再利用されるリソース シャドウ バッファー、遅延レンダリング リソース、後処理リソース、ライティング データ キャッシュ リソースおよびヒープ。 ヒープおよびエイリアシング バリアへの配置済みリソースの重複。 大規模なリソースまたはヒープ領域をフレーム内で再利用し、フレーム全体に対する要件を削減します。 フレーム内メモリ再利用の手法を使用します。 Direct3D 11 では、アプリケーションは同じ種類で十分な大きさのサイズを持つ可能性のあるリソースのみを再利用できました。 Direct3D 12 のヒープでは、リソースを重ね合わせることがさらに簡単になり、再利用の度合いが高まります。
ストリーミング リソース 地形、オープンワールド テクスチャ、ジオメトリ リソースおよびヒープ。 フリー スレッド作成、バックグラウンド CPU スレッド、バックグラウンド コピー コマンド キュー、リスト。 一般的に可視性 (視錐台または距離に基づく評価を使用) に基づく部分的な常駐と常駐の再評価がすべてのフレームで必要です。
タイルごとの部分的な常駐の管理とフレーム間再利用を使用する手法は、GPU アダプターでヒープ内予約済みリソースがサポートされている場合に使用できます。
フレーム間メモリ再利用を使用する手法を使用して、部分的なサブリソース常駐を実現できますが、最適ではありません。 配置済みリソースとヒープによって高速のリサイクルが可能になりますが、コミット済みリソースをフォールバックとして使用できます。

アプリケーションでほとんどの作業にストリーミング リソースを使用する傾向が高まると、配置済みと予約済みのリソースの活用が増えることになり、その結果として、これら 4 つの分類の間でのメモリ再利用が最大化されます。 アプリケーションでのストリーミングが増えると、アプリケーションがバジェットとして計画して優先する帯域幅も増えます。

Direct3D 12 では一般的に、グラフィックス エンジンはより多様かつ動的なバジェットに従う必要があり、このことを以前よりも厳密に行う必要があります。 理想的なアプリケーションは、4 つのカテゴリすべてをそのプロセスに与えられたバジェットに収めるものであり、ゲーム プレイをバックグラウンドのモバイル アプリから全画面の独立型バジェットまでスケーリングします。 しかし、多くのアプリケーションは最初に、"重要" カテゴリのリソースの種類の多さに苦心するでしょう。 Direct3D 11 では、リソースを匿名で作成して "重要" 状態のままにしていても、パフォーマンスに影響を与えることはありませんでした。 しかし Direct3D 12 では、開発者が、ランダムに作成されたリソースをエンジンとミドルウェア全体から念入りに探して他のカテゴリの 1 つに割り当てなおす必要があります。

その他に問題となる領域としては、ミドルウェア コンポーネント、ユーザー コントロール、フレーム内ストリーミングがあります。 ミドルウェア コンポーネントは、バジェットに対して公開されることも、緊密に連携することもない可能性があります。 ミドルウェア コンポーネントの機能はレンダリング手法として公開される可能性があり、アプリケーションはミドルウェアとエンジンの設定の公開に依存できる可能性があります。 開発者は、Direct3D 11 に依存してページングを行い、適切なフレーム レートを実現していました。 場合によっては、Direct3D 11 アプリケーションはリソースの内容のページインとアウトをフレームごとに行っていて、その結果としてユーザーが許容できるフレーム レートになっていました。 ほとんどのエンジンでは、リソース データのストリーミングはバックグラウンド アクティビティとしてのみ行われるため、高優先度のフレーム内ストリーミングへのグレースフルなフォールバックはありません。 このことをエンジンで実装しようとすると、Direct3D 12 への移行によって得られる CPU オーバーヘッドの改善がいくらか失われます。 エンジンの開発者がフレームをフェーズに分割することを検討すれば、リソースを再利用する機会が増えることになります。また、ミドルウェア ベンダーと協力して配置済みリソースとヒープをサポートできるようにすれば、フレーム内メモリ再利用が可能になります。

CreateCommittedResource

CreateReservedResource

Direct3D 12 プログラミング ガイド

メモリ管理

リソース バインディング