これらのDirectX11呼び出しのうち、実際にデータをGPUに送信するのはどれですか。


7

グラフィックプログラミングとDirectX11を学ぼうとしています。

CPU-GPU転送とグラフィックプログラミング全般を最小限に抑える方法を学びたいと思っています。
オンラインリソースから自分に答えることができなかったという質問があります。

実際にデータをGPUに送信するD3Dメソッドはどれですか(同等に、静的メッシュの場合、すべての頂点データがフレームごとに、または1回だけGPUに渡されますか)。

コードは次のとおりです:
(stackexchangeの簡略化)

私の「メッシュ」クラスには、頂点バッファーがあります。

ID3D11Buffer *m_pVBuffer;

メッシュのコンストラクターで、いくつかの頂点を頂点バッファーに設定します。

D3D11_MAPPED_SUBRESOURCE ms;
devcon->Map(m_pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);
memcpy(ms.pData, &vertices[0], sizeof(VERTEX) * vertices.size());
devcon->Unmap(m_pVBuffer, NULL);

次に、メッシュの「レンダリング」メソッドでこれを行います。

UINT stride = sizeof(VERTEX);
UINT offset = 0;
devcon->IASetVertexBuffers(0, 1, &m_pVBuffer, &stride, &offset);
devcon->IASetIndexBuffer(m_pIBuffer, DXGI_FORMAT_R32_UINT, 0);
devcon->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
devcon->DrawIndexed(m_num_indices, 0, 0);

繰り返します:データをGPUにアップロードするのは、頂点バッファーをマップ、memcpy、およびマップ解除するときですか、それともIASetVertexBuffersを呼び出すときにフレームごとにアップロードされますか?

回答:


7

頂点バッファーをVRAMに保存するかメインRAMに保存するかを完全に制御できないため、これは難しい質問です。ドライバーは、頂点バッファーの作成時に指定された使用率とCPUアクセスフラグに基づいて、この決定を行います。

一般的に言えば、デフォルトで不変の使用法のバッファーはVRAMに格納されます。ステージングを使用するものはメインRAMに保存されます。動的に使用されるものはどちらの場所にもあり得ます。ただし、VRAMが不足している場合、ドライバーはリソースをフォールバックとしてメインRAMに格納します。

バッファーが最終的にVRAMに格納されると、CPUがバッファーを更新するたびに(つまり、マップ/マップ解除のペアを実行するときに)、データはシステムバス(CPUとGPUを接続する)を経由します。メインRAMにある場合、レンダリングにそのバッファーを使用するたびに、GPUはシステムバスを介してデータを読み取ります。

したがって、通常、静的メッシュの場合、不変の使用法を使用し、バッファーはVRAMに格納されるため、初期設定後に追加のシステムバス転送はありません。動的な頂点バッファー(パーティクルなど)の場合、動的な使用法を使用します。データはフレームごとに1回バスを通過します。VRAMにある場合、CPUがバスに書き込むためにバスが使用されます。これはメインRAMにあり、バスはGPUがそれを読み取るために使用されます。


私が実行したテストはこの答えを確認します。多くのオブジェクトをレンダリングすると、最初の数秒間は最初に速度が低下しますが、その後フレームレートが上がります。フレームごとに同じことを行うとすれば、これは、バッファの少なくとも一部がVRAMに「キャッシュ」されているためであるに違いありません。だから、答えは「一度だけアップロードされるだろう。たぶん、あなたはそれを当てにすべきではない。」です。
x10

0

答えは、高度に最適化されたハードウェアドライバーの特定の世代がどのように感じているかに依存します。つまり、一般的な答えはありません。

3Dカードは高度にシリアル化および並列化され、キャッシュされ、非同期で動作するため、ドライバーが現在レンダリングするように指示しているものよりも1-Nフレーム遅れてドライバーがレンダリングしているという事実をさらに複雑にします。

学習しているだけの場合、重要な情報は、レンダーを準備するためのシーケンスポイントです。データを記述し、データをコピーし、使用するデータをドライバーに伝え、レンダーを起動します。そして、それは実際には非常に深いうさぎの穴です。


0

私の理解は、これを読むことに主に基づいており、リソースが描画呼び出しで使用されるまで、ドライバーは通常、リソースをビデオメモリに送信しません。

つまり、コンストラクタはおそらくGPUハードウェアにまったく触れず、renderメソッドは触れません。ただし、GPUコマンドの大きなリストをバッファリングする方がCPU効率が高いため、DrawIndexed()呼び出しでも、すぐにハードウェアに到達しない可能性があります。

ドライバーは、実行時にGPUメモリからデータをアンロードすることもできます(メインRAMにデータのコピーがある場合)。極端な場合、これはフレームごとに複数回発生する可能性があります。

もちろん、これらすべてはドライバーによってプログラマーから隠されているので、そのようであることに依存することはできません-ドライバーは常に変化します。


描画呼び出しさえ行わない可能性が非常に高いです-描画呼び出しは、ドライバーが管理するコマンドバッファーに送られ、ドライバー自身のスイートタイムでフラッシュされます。
Maximus Minimus
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.