Vulkanでprintf Debugをする(2025/03/16)
初めに
Vulkanでは設定をすれば、Shaderでprintf(に相当する関数)で標準出力に値を出力する、いわゆるprintf Debugをすることができます。
int index = int(gl_GlobalInvocationID.x);
debugPrintfEXT("Hello from shader!\n");
debugPrintfEXT("Thread ID: %d\n", gl_GlobalInvocationID.x);
以前、Nishikiさんがこれに関しての詳しい記事を書いてくださっていたのですが、(恐らく)Vulkan1.4からだと仕様変更があったみたいでちょっと必要な設定が増えていました。Vulkan1.3であれば多分問題ないはずです(前やった時そうだった覚えがあるので)。
この記事ではVulkan1.4での設定の仕方について解説します
やり方
環境
Vulkan 1.4.304.1
Vulkan.hpp使用
公式のDocument
1. Vulkan Configuratorで設定する
VulkanSDK/(version)/Bin
にあるvkconfig-gui.exe
を起動してください。これはVulkanの設定をすることができるもので、Validation Layerに関する項目の中にDebug Printf
という項目がありますのでチェックをしてください。その下のRedirect Printf message to stdout
にチェックを入れると標準出力としてprintfの結果が出力されるようになります。
2. ValidationFeatureEXTの設定
ここが前バージョンとの変更点で、Validation Layerの拡張としてprintf Debugをしますよという設定が必要になりました。具体的にはValidationFeatureEXTを書いてあげて、InstanceCreateInfoに追加してあげる必要があります。
ValidationFeatureEXTの設定の仕方はこんな感じです。
std::vector<vk::ValidationFeatureEnableEXT> enables = { vk::ValidationFeatureEnableEXT::eDebugPrintf };
vk::ValidationFeaturesEXT validationFeatures;
validationFeatures.pEnabledValidationFeatures = enables.data();
validationFeatures.enabledValidationFeatureCount = static_cast<uint32_t>(enables.size());
この構造体をInstanceCreateInfoのpNextに入れてあげて、Instanceを作成すればOKです。
vk::InstanceCreateInfo createInfo{};
createInfo.pNext = &validationFeatures;
3. Shaderでprintfを書く
以上でCPU側の設定は終わりです。次はShader側の処理です。HLSLだとまんまprintf
関数があるのですが、GLSLだと対応する関数がdebugPrintfEXT
というやつになっています。これを使うにはGL_EXT_debug_printf
という拡張を有効にする必要があります。
例としてはこんな感じになります
#version 460
#extension GL_EXT_debug_printf : enable
layout(local_size_x = 1, local_size_y = 1) in;
layout(binding = 0) buffer Data {
uint val[];
} data[3];
void main()
{
int index = int(gl_GlobalInvocationID.x);
debugPrintfEXT("Hello from shader!\n");
debugPrintfEXT("Thread ID: %d\n", gl_GlobalInvocationID.x);
data[2].val[index] = data[0].val[index] + data[1].val[index];
}
これで実行してみればちゃんと標準出力の方にprintfの結果が出力されるはずです(もしWarning出たらトラブルシューティングの項を見てください)
トラブルシューティング
実行するShaderによっては、次のようなDebug Print MessageのBuffer Sizeが小さすぎるというWarningが出て、printfの結果が出てこないことがあります。
Validation Warning: [ WARNING-DEBUG-PRINTF ] Object 0: handle = 0x2678dfa4a30, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x76589099 | vkQueueSubmit(): pSubmits[0] Internal Warning: Debug Printf message was truncated due to a buffer size (1024) being too small for the messages. (This can be adjusted with VK_LAYER_PRINTF_BUFFER_SIZE or vkconfig)
恐らくですが、Debug Printの仕組みとしてMessageを入れておくBufferがあり、終了後それをReadbackして出力するというような手順で出力されているのだと思われます。なので、このWarningはShader上でMessageのBufferを超えるほどprintfを呼び出しているよという意味であり、それでprintfの結果が出てこなくなったというわけです。
MessageのBuffer Sizeは先ほどのVulkan Configuratorの方にPrint buffer sizeという項目がありますのでそれで変更することができます。十分なサイズが確保できれば問題なく動くはずです。
(私はうっかり10万回処理を行うCompute Shaderを実行してしまいこのようなWarningが出てしまいました)
Discussion