主要参考VulkanでShaderからprintfする方法

在shader中开启GL_EXT_debug_printf拓展可以很方便的在shader中使用print。用法为:

在shader开头开启GL_EXT_debug_printf拓展:

1
#extension GL_EXT_debug_printf : enable

在shader中用和printf同样的方法调用debugPrintfEXT

1
2
3
4
5
6
void main()
{
...
debugPrintfEXT("from mesh thread group %d %d %d\n",gl_GlobalInvocationID.x, gl_GlobalInvocationID.y, gl_GlobalInvocationID.z);
...
}

接着需要在vulkan configurator中添加对这个拓展的支持。

在validation settings 中标红线处的选项改为Debug Printf Present

在vulkan创建instance的过程中需要初始化VkValidationFeaturesEXT 并将其加入VkInstanceCreateInfopNext链表中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
std::vector<VkValidationFeatureEnableEXT> m_validationFeatureEnabled;
m_validationFeatureEnabled.push_back(VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT);
...

VkInstanceCreateInfo inst_create{};
...
VkValidationFeaturesEXT validation_features{};

validation_features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
validation_features.enabledValidationFeatureCount = m_validationFeatureEnabled.size();
validation_features.pEnabledValidationFeatures = m_validationFeatureEnabled.data();
...

validation_features.pNext = inst_create.pNext;
inst_create.pNext = &validation_features;

由于打印的消息会在VK_DEBUG_REPORT_INFORMATION_BIT_EXT 层,而默认是不会输出INFORMATION信息的,因此,我们需要创建自定义的VkDebugReportCallbackEXT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT /*type*/,
uint64_t /*object*/, size_t /*location*/, int32_t /*message_code*/,
const char* layer_prefix, const char* message, void* /*user_data*/)
{
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
{
printf("%s: %s\n", layer_prefix, message);
}
else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
{
printf("%s: %s\n", layer_prefix, message);
}
else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)
{
printf("%s: %s\n", layer_prefix, message);
}
else
{
printf("%s: %s\n", layer_prefix, message);
}
return VK_FALSE;
}
...
int m_debugReportFlags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT | VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
VkDebugReportCallbackEXT m_debugCallback = NULL;
...
VkInstanceCreateInfo inst_create{};
...
VkDebugReportCallbackCreateInfoEXT debugReportCI{};

debugReportCI.pfnCallback = debug_callback;
debugReportCI.flags = m_debugReportFlags;
debugReportCI.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;

debugReportCI.pNext = inst_create.pNext;
inst_create.pNext = &debugReportCI;
...
vkCreateDebugReportCallbackEXT(m_VkInstance, &debugReportCI, NULL, &m_debugCallback);

设定好后便可在stdout中看到打印的信息:

对我这种编程苦手,这一特性在debug compute shader, mesh shader以及rt shader中相当有用。

注意 每帧最好只打印少量信息(例如:对compute shader只打印某个特定的线程),一次性打印太多信息会报message truncated。对于pixel shader最好还是通过输出颜色调试。

后记 这个特性搭配renderdoc使用非常丝滑,renderdoc除了能截取打印的所有字符串,还能得到compute shader对应线程组编号。