8

ニコル・ボーラス

結局のところ、コマンド バッファーを並行して構築できることは、Vulkan のセールス ポイントの 1 つです。

仕様(5.1コマンドプール)(強調鉱山):

コマンド プールはアプリケーションと同期されます。つまり、コマンド プールを複数のスレッドで同時に使用することはできません。これには、プールから割り当てられたコマンド バッファにコマンドを記録することによる使用、およびコマンド バッファまたはプール自体を割り当て、解放、およびリセットする操作が含まれます。

並行して記録する場合、この種のコマンド プールの目的全体が殺されませんか? 並行して記録する場合は、スレッドごとに個別のプールを用意したほうがよいのではないでしょうか。

すべて同じプールから (1 つのスレッドで) 割り当てられたコマンド バッファーを事前に記録し、それらを並列に実行する場合、それは理解できます。これには、償却されたリソース作成コストと並列実行の利点があります。ただし、並行記録とコマンド プールはあまり一致していないようです。

なぜすべてを事前に記録しないのか、個人的にはわかりません。では、なぜ並行してコマンド バッファーを構築する必要があるのでしょうか。そして、スレッドごとに 1 つのプールを使用する必要があるでしょうか?

4

2 に答える 2

9

並行して記録する場合は、スレッドごとに個別のプールを用意したほうがよいのではないでしょうか。

スレッドごとに個別のプールを使用すると、「並行して記録する場合にコマンド プールの目的全体が失われる」ことがわかりません。実際、各スレッドが適切と思われる独自のコマンド プールを管理できるため、かなり役立ちます。

たとえば、記述子プールとコマンド プールの構造上の違いを考えてみましょう。記述子プールを使用すると、基本的に、そこから何を割り当てるかを正確に伝えます。VkDescriptorPoolCreateInfo実装が各プールに使用するメモリ量を正確に事前に割り当てることができる詳細な情報を提供します。また、記述子プールからこれ以上割り当てることはできません。

対照的に、VkCommandPoolCreateInfo内容は... 何もありません。ああ、コマンド バッファがプライマリかセカンダリかを指定します。コマンドバッファが頻繁にリセットされるか、永続的であるかを示します。そして、他のいくつかのこと。しかし、それ以外は、コマンド バッファーの内容については何も言いません。割り当てるバッファ数に関する情報さえ提供しません。

記述子プールは固定されることを意図しています。必要に応じて割り当てられますが、構築時に設定された量までです。コマンド バッファは非常に動的であることを意図しており、特定のユース ケースの必要に応じて割り当てられます。

各プールが独自の malloc/free を持っていると考えてください。ユーザーはプールとそのバッファへのアクセスを同期する必要があるため、すべてのvkCmd*関数がメモリを割り当てるときにそうする必要はありません。これにより、コマンドの構築が高速になります。それはスレッド化に役立ちます。スレッドがそのコマンド プールをリセットすることを決定した場合、それを行うためにミューテックスやその他のものをロックする必要はありません。

スレッドごとに 1 つのコマンド プールを使用することは、概念的には問題ありません。実際、スレッドごとに 2 つ (ダブル バッファリング) にすることは、さらに理にかなっています。

なぜすべてを事前に記録しないのか、個人的にはわかりません。

静的な技術デモを作成していないためです。

これは経験不足によるものだと思いますが、並列記録は「スレッド 2-N がセカンダリ コマンド バッファーを記録し、スレッド 1 がそれ​​らすべてを 1 つのプライマリ コマンド バッファーで呼び出す」ようになると想像しました。この場合、コマンドは 1 つしかありません。スレッドごとのバッファ。そのため、コマンド プールの目的が失われると言ったのは、プールごとに 1 つの割り当てしか作成していないためです。

これは確かに、コマンド バッファーを並行して記録する実行可能な形式です。しかし、見落としていることが 2 つあります。

それは確かに並行録音の 1 つの形式ですが、それだけではありません。遅延レンダリングを行っている場合、ライティング パスの CB を構築するスレッドは、ジオメトリ パス (の一部) を担当するスレッドの 1 つよりもはるかに早く作業を終了します。したがって、適切に設計されたマルチスレッド システムでは、固定されたものの配置ではなく、必要に応じて作業をスレッドに配分する必要があります。そのため、個々のスレッドが複数のコマンド バッファーを構築することになることがよくあります。

そうでない場合でも、バッファリングのことは忘れてしまいます。次のフレームの CB を構築するときが来たら、既存の CB を上書きすることはできません。結局のところ、彼らはおそらくまだ仕事をしている列に並んでいるでしょう。したがって、各スレッドには少なくとも2 つのCB が必要です。現在実行中のものと現在構築中のものです。

そうでない場合でも、コマンド プールは CB に関連付けられたすべてのメモリを割り当てます。に例えたのには理由がありますmalloc/free。特定のプールで単一の CB のみを使用する場合でも、この CB の割り当て (vkCmd*関数によって発生する可能性があります) が別のスレッドと同期する必要がないという事実は良いことです。

いいえ、これは、複数のスレッドを使用して CB を構築する機能を妨げるものではありません。

于 2016-07-12T02:09:52.443 に答える
1

並行して記録する場合は、スレッドごとに個別のプールを用意したほうがよいのではないでしょうか。

まさにそのとおりです。それがあなたの仕様の引用が意味するものです。

すべて同じプールから (1 つのスレッドで) 割り当てられたコマンド バッファーを事前に記録し、それらを並列に実行する場合、それは理解できます。

Vulkan の方が優れています。(スレッドごとのプールから割り当てられた) コマンド バッファーを並列で事前に記録し、それらを並列実行することもできます (ワークロードがそれを助長する場合)。

なぜすべてを事前に記録しないのか、個人的にはわかりません。では、なぜ並行してコマンド バッファーを構築する必要があるのでしょうか。

それは難しいからです (特に、アプリが複雑になるにつれて)。ある時点で非生産的ですらあります (CmB をひねって事前に記録可能にする場合 - たとえば、80% が使用されない空のプレースホルダー バインディングで埋めます)。
必ずしも「必要」というわけではありません。Vulkan では、アプリ (またはその一部) に最適と思われるものを選択できます。

于 2016-07-12T12:21:35.620 に答える