キューは仕事が GPU に届く唯一の方法:vkQueueSubmit が
コマンドバッファを入れ、ハードウェアが順序通りに排出する。
キューファミリは何を実行できるかを広告するキューの
クラス——eGraphics、eCompute、eTransfer、
eSparseBinding——vkGetPhysicalDeviceQueueFamilyProperties
で一度クエリされ、VkDevice 作成時に選択される。
機能階層
example.txt
eGraphics ⊃ eCompute, eTransfer, present (usually)
eCompute ⊃ eTransfer
eTransfer ∋ copies only — the "DMA queue"ほとんどのデスクトップアプリはすべてに1つの
グラフィックス対応キューを使う(このシリーズも)——
すべての作業タイプを実行でき、ほとんどのベンダーでは
present も可能(vkGetPhysicalDeviceSurfaceSupportKHR)。
なぜ複数キューが存在するのか
- 非同期コンピュート:2番目のキューにコンピュート作業を サブミットして1番目のグラフィックスとオーバーラップ—— ベンダースケジューラは並行実行できる。
- 専用転送(DMA):グラフィックスが動いている間に アップロードが進行——エンジンは転送キュー経由でテクスチャを ストリームする。
- present は別ファミリかもしれない —— 一部の
iGPU/仮想デバイスでは present キュー ≠ グラフィックス
キュー;想定せず
surfaceSupportを実際に確認しなければ ならない。
噛む部分:所有権転送
異なるキューファミリで使われるバッファ/イメージは、
eConcurrent 共有か、明示的な転送をしなければならない:
srcQueueFamilyIndex/dstQueueFamilyIndex を設定した
release/acquire バリアペア。忘れるとゴミをサンプル——古典的
マルチキューバグ。
キューの使ってはいけない方法
- queue[0] が present できると想定しない。 常にファミリ ごとに surface サポートをクエリ;AMD/NVIDIA/Intel で異なる。
- 「キューが多い = より並列」はデフォルトでは誤り。 1ファミリの2キューは1ハードウェアチャネルで直列化すること が多い——ファミリの queueCount とベンダーの実際の エンジン分割を確認。
- 外部同期はあなたの仕事。 2スレッドから同じキューに
サブミットするには mutex(またはスレッドごとのキュー)が
必要——
vkQueueSubmitは内部的にスレッドセーフではない。 - キュー間順序にはセマフォが必要。 コマンドバッファ内の バリアは別キューの作業を順序付けできない (同期解説参照)。
eTransfer専用キューはバリア/グラフィックスができない —— 純粋 DMA キューはコピーのみ実行;アップロードのレイアウト 遷移は依然グラフィックス/コンピュートキューで発生する。
小規模プロジェクトの経験則:1つの graphics+present キュー、 アップロードが測定可能に停滞したら転送キューを追加、 プロファイリングがグラフィックスフェーズ間で GPU が アイドルと言ったら非同期コンピュートを追加。
この記事が役に立った場合は、TechOverflow での新しい記事の調査と公開を支援するため、「Buy Me a Coffee」でのご支援、または PayPal 経由でのご寄付をご検討ください