🌋

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であれば多分問題ないはずです(前やった時そうだった覚えがあるので)。

https://zenn.dev/nishiki/articles/838303e9cdef1e

この記事ではVulkan1.4での設定の仕方について解説します

やり方

環境
Vulkan 1.4.304.1
Vulkan.hpp使用

公式のDocument
https://docs.vulkan.org/samples/latest/samples/extensions/shader_debugprintf/README.html

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