Vulkan SDK 1.4.xに更新したら、これまで機嫌良く動作していたコードでも警告(エラー)が報告されるようになってしまいました。どうやら Vulkan Validation Layer (VVL) が更新され、よりチェックが厳しくなったようです。
エラーの内容
スワップチェインからイメージを取得する vkAcquireNextImageKHR の実行時に、以下のようなエラーが報告されました。ひとことでいうのならば、引数で指定したセマフォがまだ使用中であり、それを使ってしまった、というのが直接の原因です。
ERROR: [1402107823][VUID-vkQueueSubmit-pSignalSemaphores-00067] : vkQueueSubmit(): pSubmits[0].pSignalSemaphores[0] (VkSemaphore 0x1c000000001c) is being signaled by VkQueue 0x2726b0feb50, but it may still be in use by VkSwapchainKHR 0x70000000007.
Here are the most recently acquired image indices: 1, 2, 0, 1, [2], 0, 0, 0.
(brackets mark the last use of VkSemaphore 0x1c000000001c in a presentation operation)
Swapchain image 2 was presented but was not re-acquired, so VkSemaphore 0x1c000000001c may still be in use and cannot be safely reused with image index 0.
Vulkan insight: One solution is to assign each image its own semaphore. This also handles the case where vkAcquireNextImageKHR returns the same index twice in a row. Here are some common methods to ensure that a semaphore passed to vkQueuePresentKHR is not in use and can be safely reused:
a) Use a separate semaphore per swapchain image. Index these semaphores using the index of the acquired image.
b) Consider the VK_KHR_swapchain_maintenance1 extension. It allows using a VkFence with the presentation operation.
The Vulkan spec states: Each binary semaphore element of the pSignalSemaphores member of any element of pSubmits must be unsignaled when the semaphore signal operation it defines is executed on the device (https://vulkan.lunarg.com/doc/view/1.4.321.1/windows/antora/spec/latest/chapters/cmdbuffers.html#VUID-vkQueueSubmit-pSignalSemaphores-00067)
このときの実装について
このエラーを出す実装は、少し前のSaschaWillems氏のサンプルプログラムだったり、自分の昔のプログラムだったり、以前からある各種チュートリアルのプログラムなどが、該当します。いずれもコマンドバッファもしくはスワップチェインのイメージ数と対応するセマフォを用いて、順番に使用するタイプのものです。イメージと1対1の対応でセマフォを割り当てて使うというシンプルなものです。
スワップチェインから得られるイメージが順番に回ってくるのであれば、セマフォも順番に使用され、使用中のものが再度使われるといった状況は発生しないように考えられます。
エラーの詳細
ここで、エラーの状態をじっくりみてみると、スワップチェインから得られたイメージのインデックス番号が履歴付きで表示されています。[ ]は該当セマフォが担当した最終プレゼンテーション操作の箇所を指し示しています。
Here are the most recently acquired image indices: 1, 2, 0, 1, [2], 0, 0, 0.
今回スワップチェインイメージ数は3という条件であり、今回の描画フレームにおいて3つ前のセマフォを使おうとして使用中だった、と怒られたわけです。
イメージインデックスに着目
イメージインデックスの順序に着目してみます。順番に0,1,2,0,1,2… と続いて返ってくるのかと思えば、どうやらそうではないことが、この結果から判明しています。後半は常にインデックス0が返ってきています。
この結果より次のことが考えられます。
- イメージと同数のセマフォを用意しても解決しない
- 同じインデックスが同数返されると、問題が発生する
- イメージのインデックスを用いてセマフォを使う
- 同じインデックスが連続で返された場合に、問題が発生する
使用するセマフォをさらに用意して、順番に使っていく実装とすれば改善は出来ましたが、それでも一巡した場合では、今回と同様のエラーが報告されてしまいます。
解決策
今回の隠れた前提条件に、垂直同期ありというものがありました。そして、どの環境でも確実に使える「VK_PRESENT_MODE_FIFO_KHR」を使用していました。これも1つの要因になっていました。これをVK_PRESENT_MODE_MAILBOX_KHRに変更すると、イメージインデックス値がきれいなシーケンス順序となり、スワップチェインイメージ数と同数のセマフォ(の組)を用意して処理することができました。最近のSaschaWillems氏のサンプルプログラムはこのような方法となっているようでした。
もう1つの解決策は、使用済みセマフォを管理して、vkAcquireNextImageKHRで使用していくというものです。スワップチェインのイメージ数+1のプレセーション用セマフォを用意しておき、使用済みになったら待機リストへ登録し、次はそこから使っていくというイメージになります。こちらの方法は、KhronosGroup/Vulkan-Samplesで採用されている方法です。
コメント