2-3. キュー

Vulkanにおけるキューとは、GPUの実行するコマンドを保持する待ち行列です。有り体に言えばGPUの「やることリスト」です。GPUにコマンドを送るときは、このキューにコマンドを詰め込むことになります。

ところで、1つのGPUが持っているキューは1つだけとは限りません。いくつも持っている場合があります。また、それらキューによってサポートしている機能とサポートしていない機能があったりもします。キューにコマンドを送るときは、そのキューが何の機能をサポートしているかを事前に把握しておく必要があります。あるキューがサポートしていない機能を要するような仕事はそのキューには詰め込めません。また、ある物理デバイスの全てのキューがその機能をサポートしていないならば、その物理デバイスでその機能を要するコマンドは使えません。

ある物理デバイスの持っているキューの情報は getQueueFamilyPropertiesメソッドで取得できます。メソッド名にある「キューファミリ」というのは、同じ能力を持っているキューをひとまとめにしたものです。1つの物理デバイスには1個以上のキューファミリがあり、1つのキューファミリには1個以上の同等の機能を持ったキューが所属しています。

1つのキューファミリの情報は vk::QueueFamilyProperties構造体で表され、 getQueueFamilyPropertiesを呼ぶと vectorに入った vk::QueueFamilyPropertiesの形で物理デバイスのキューファミリの情報を返してくれます。

試しに、ある物理デバイスの全てのキューファミリの情報を表示するプログラムを作ってみましょう。(1-4. プロジェクトの作成(Windows/VisualStudio2019)に従って空のプロジェクトから作った方はコンソール画面が出ないと思います。プロジェクトのプロパティ→リンカー→システム→サブシステム→コンソールを選んでコンソールアプリケーションにして下さい)

どのような結果が出力されたでしょうか。手元の環境(外付けグラボなし・CPUintel core i7)では以下のようになりました。

どうやらintel core i7内臓のGPUはキューファミリが1つだけ、キューも1つだけ、描画と計算とデータ移動は全てサポートということのようです。面白いですね。

2-1. インスタンスと物理デバイスの項において「本来であれば各物理デバイスを吟味する」と書いたのを覚えていますでしょうか。今までの知識を元に「グラフィックスをサポートするキューファミリを最低でも1つ持っている」物理デバイスを選択するようなプログラムを書いてみましょう。どんなGPUだってそれくらいの機能はサポートしているかも知れませんが、1つもGPUが存在しない状況はあり得るかもしれません。

さて、これで使用に適した物理デバイスを選ぶことが出来るようになりました。グラフィック機能をサポートしたキューを間違いなく持っています。

ではそのキューを取得しましょう。キューは論理デバイス( vk::Device)の getQueueメソッドで取得できます。第1引数がキューファミリのインデックス、第2引数が取得したいキューのキューファミリ内でのインデックスです。

取得したいキューのキューファミリのインデックスを指定するということは、グラフィック機能をサポートしているキューファミリを見つけるだけでなく、そのキューファミリのインデックスも覚えておく必要がありますね。そのようなコードを追加しましょう。

このgraphicsQueueFamilyIndexを使用してGetQueueを呼びます。取得するキューはキューファミリ内のどのキューでも変わりないので最初のキュー(0番)にします。

これを 実行してみましょう。すると実行時エラーが出たのではないでしょうか。一体なぜエラーが出たのでしょう。

 

 

実はVulkanでは論理デバイスからキューを取得するとき、論理デバイスにあらかじめ「このキューを使うよ」ということを伝えておく必要があります。論理デバイスの作成時、 vk::DeviceCreateInfo構造体に「この論理デバイスを通じてこのキューファミリからいくつのキューを使う」という情報を指定する必要があるのです。その情報は vk::DeviceQueueCreateInfo構造体の配列で表されます。

今のところ欲しいキューは1つだけなので要素数1の配列にします。 queueFamilyIndexはキューの欲しいキューファミリのインデックスを表し、 queueCountはそのキューファミリからいくつのキューが欲しいかを表します。今欲しいのはグラフィック機能をサポートするキューを1つだけです。 pQueuePrioritiesはキューのタスク実行の優先度を表すfloat値配列を指定します。1.0fを指定しておきます。キューごとに優先度の値が決められるため、この配列はそのキューファミリから欲しいキューの数だけの要素数を持ちます。 vk::DeviceCreateInfopQueueCreateInfosに先ほどの vk::DeviceQueueCreateInfo構造体配列の先頭アドレス、 queueCreateInfoCountに配列の要素数を指定します。上記のコードを追加した上で再度実行してみましょう。今度はエラーもなく通ったのではないでしょうか。

これで無事キューを取得することが出来ました。ここにコマンドを詰め込んでいくので、その方法を次回解説します。

なお、 vk::Queuevk::PhysicalDeviceと同じく、後始末の必要はありません。


この節では物理デバイスの選択とキューの取得をやりました。次回はコマンドバッファの作成とキューへの送信をやります。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です