Vulkan:キューとキューファミリの解説

キューは仕事が 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 が アイドルと言ったら非同期コンピュートを追加。


同じカテゴリの類似記事をチェック: C++ Vulkan