1// Copyright 2017-2024 The Khronos Group Inc. 2// 3// SPDX-License-Identifier: CC-BY-4.0 4 5include::{generated}/meta/{refprefix}VK_EXT_debug_utils.adoc[] 6 7=== Other Extension Metadata 8 9*Last Modified Date*:: 10 2020-04-03 11*Revision*:: 12 2 13*IP Status*:: 14 No known IP claims. 15*Dependencies*:: 16 - This extension is written against version 1.0 of the Vulkan API. 17 - Requires elink:VkObjectType 18*Contributors*:: 19 - Mark Young, LunarG 20 - Baldur Karlsson 21 - Ian Elliott, Google 22 - Courtney Goeltzenleuchter, Google 23 - Karl Schultz, LunarG 24 - Mark Lobodzinski, LunarG 25 - Mike Schuchardt, LunarG 26 - Jaakko Konttinen, AMD 27 - Dan Ginsburg, Valve Software 28 - Rolando Olivares, Epic Games 29 - Dan Baker, Oxide Games 30 - Kyle Spagnoli, NVIDIA 31 - Jon Ashburn, LunarG 32 - Piers Daniell, NVIDIA 33 34=== Description 35 36Due to the nature of the Vulkan interface, there is very little error 37information available to the developer and application. 38By using the `VK_EXT_debug_utils` extension, developers can: obtain more 39information. 40When combined with validation layers, even more detailed feedback on the 41application's use of Vulkan will be provided. 42 43This extension provides the following capabilities: 44 45 - The ability to create a debug messenger which will pass along debug 46 messages to an application supplied callback. 47 - The ability to identify specific Vulkan objects using a name or tag to 48 improve tracking. 49 - The ability to identify specific sections within a sname:VkQueue or 50 sname:VkCommandBuffer using labels to aid organization and offline 51 analysis in external tools. 52 53The main difference between this extension and `apiext:VK_EXT_debug_report` 54and `apiext:VK_EXT_debug_marker` is that those extensions use 55elink:VkDebugReportObjectTypeEXT to identify objects. 56This extension uses the core elink:VkObjectType in place of 57elink:VkDebugReportObjectTypeEXT. 58The primary reason for this move is that no future object type handle 59enumeration values will be added to elink:VkDebugReportObjectTypeEXT since 60the creation of elink:VkObjectType. 61 62In addition, this extension combines the functionality of both 63`apiext:VK_EXT_debug_report` and `apiext:VK_EXT_debug_marker` by allowing 64object name and debug markers (now called labels) to be returned to the 65application's callback function. 66This should assist in clarifying the details of a debug message including: 67what objects are involved and potentially which location within a 68slink:VkQueue or slink:VkCommandBuffer the message occurred. 69 70include::{generated}/interfaces/VK_EXT_debug_utils.adoc[] 71 72=== Examples 73 74*Example 1* 75 76`VK_EXT_debug_utils` allows an application to register multiple callbacks 77with any Vulkan component wishing to report debug information. 78Some callbacks may log the information to a file, others may cause a debug 79break point or other application defined behavior. 80An application can: register callbacks even when no validation layers are 81enabled, but they will only be called for loader and, if implemented, driver 82events. 83 84To capture events that occur while creating or destroying an instance an 85application can: link a slink:VkDebugUtilsMessengerCreateInfoEXT structure 86to the pname:pNext element of the slink:VkInstanceCreateInfo structure given 87to flink:vkCreateInstance. 88 89Example uses: Create three callback objects. 90One will log errors and warnings to the debug console using Windows 91code:OutputDebugString. 92The second will cause the debugger to break at that callback when an error 93happens and the third will log warnings to stdout. 94 95[source,c++] 96---- 97 extern VkInstance instance; 98 VkResult res; 99 VkDebugUtilsMessengerEXT cb1, cb2, cb3; 100 101 // Must call extension functions through a function pointer: 102 PFN_vkCreateDebugUtilsMessengerEXT pfnCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"); 103 PFN_vkDestroyDebugUtilsMessengerEXT pfnDestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"); 104 105 VkDebugUtilsMessengerCreateInfoEXT callback1 = { 106 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, 107 .pNext = NULL, 108 .flags = 0, 109 .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | 110 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, 111 .messageType= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | 112 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, 113 .pfnUserCallback = myOutputDebugString, 114 .pUserData = NULL 115 }; 116 res = pfnCreateDebugUtilsMessengerEXT(instance, &callback1, NULL, &cb1); 117 if (res != VK_SUCCESS) { 118 // Do error handling for VK_ERROR_OUT_OF_MEMORY 119 } 120 121 callback1.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; 122 callback1.pfnUserCallback = myDebugBreak; 123 callback1.pUserData = NULL; 124 res = pfnCreateDebugUtilsMessengerEXT(instance, &callback1, NULL, &cb2); 125 if (res != VK_SUCCESS) { 126 // Do error handling for VK_ERROR_OUT_OF_MEMORY 127 } 128 129 VkDebugUtilsMessengerCreateInfoEXT callback3 = { 130 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, 131 .pNext = NULL, 132 .flags = 0, 133 .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, 134 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | 135 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, 136 .pfnUserCallback = mystdOutLogger, 137 .pUserData = NULL 138 }; 139 res = pfnCreateDebugUtilsMessengerEXT(instance, &callback3, NULL, &cb3); 140 if (res != VK_SUCCESS) { 141 // Do error handling for VK_ERROR_OUT_OF_MEMORY 142 } 143 144 ... 145 146 // Remove callbacks when cleaning up 147 pfnDestroyDebugUtilsMessengerEXT(instance, cb1, NULL); 148 pfnDestroyDebugUtilsMessengerEXT(instance, cb2, NULL); 149 pfnDestroyDebugUtilsMessengerEXT(instance, cb3, NULL); 150---- 151 152*Example 2* 153 154Associate a name with an image, for easier debugging in external tools or 155with validation layers that can print a friendly name when referring to 156objects in error messages. 157 158[source,c++] 159---- 160 extern VkInstance instance; 161 extern VkDevice device; 162 extern VkImage image; 163 164 // Must call extension functions through a function pointer: 165 PFN_vkSetDebugUtilsObjectNameEXT pfnSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectNameEXT"); 166 167 // Set a name on the image 168 const VkDebugUtilsObjectNameInfoEXT imageNameInfo = 169 { 170 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, 171 .pNext = NULL, 172 .objectType = VK_OBJECT_TYPE_IMAGE, 173 .objectHandle = (uint64_t)image, 174 .pObjectName = "Brick Diffuse Texture", 175 }; 176 177 pfnSetDebugUtilsObjectNameEXT(device, &imageNameInfo); 178 179 // A subsequent error might print: 180 // Image 'Brick Diffuse Texture' (0xc0dec0dedeadbeef) is used in a 181 // command buffer with no memory bound to it. 182---- 183 184*Example 3* 185 186Annotating regions of a workload with naming information so that offline 187analysis tools can display a more usable visualization of the commands 188submitted. 189 190[source,c++] 191---- 192 extern VkInstance instance; 193 extern VkCommandBuffer commandBuffer; 194 195 // Must call extension functions through a function pointer: 196 PFN_vkQueueBeginDebugUtilsLabelEXT pfnQueueBeginDebugUtilsLabelEXT = (PFN_vkQueueBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkQueueBeginDebugUtilsLabelEXT"); 197 PFN_vkQueueEndDebugUtilsLabelEXT pfnQueueEndDebugUtilsLabelEXT = (PFN_vkQueueEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkQueueEndDebugUtilsLabelEXT"); 198 PFN_vkCmdBeginDebugUtilsLabelEXT pfnCmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdBeginDebugUtilsLabelEXT"); 199 PFN_vkCmdEndDebugUtilsLabelEXT pfnCmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdEndDebugUtilsLabelEXT"); 200 PFN_vkCmdInsertDebugUtilsLabelEXT pfnCmdInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdInsertDebugUtilsLabelEXT"); 201 202 // Describe the area being rendered 203 const VkDebugUtilsLabelEXT houseLabel = 204 { 205 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, 206 .pNext = NULL, 207 .pLabelName = "Brick House", 208 .color = { 1.0f, 0.0f, 0.0f, 1.0f }, 209 }; 210 211 // Start an annotated group of calls under the 'Brick House' name 212 pfnCmdBeginDebugUtilsLabelEXT(commandBuffer, &houseLabel); 213 { 214 // A mutable structure for each part being rendered 215 VkDebugUtilsLabelEXT housePartLabel = 216 { 217 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, 218 .pNext = NULL, 219 .pLabelName = NULL, 220 .color = { 0.0f, 0.0f, 0.0f, 0.0f }, 221 }; 222 223 // Set the name and insert the marker 224 housePartLabel.pLabelName = "Walls"; 225 pfnCmdInsertDebugUtilsLabelEXT(commandBuffer, &housePartLabel); 226 227 // Insert the drawcall for the walls 228 vkCmdDrawIndexed(commandBuffer, 1000, 1, 0, 0, 0); 229 230 // Insert a recursive region for two sets of windows 231 housePartLabel.pLabelName = "Windows"; 232 pfnCmdBeginDebugUtilsLabelEXT(commandBuffer, &housePartLabel); 233 { 234 vkCmdDrawIndexed(commandBuffer, 75, 6, 1000, 0, 0); 235 vkCmdDrawIndexed(commandBuffer, 100, 2, 1450, 0, 0); 236 } 237 pfnCmdEndDebugUtilsLabelEXT(commandBuffer); 238 239 housePartLabel.pLabelName = "Front Door"; 240 pfnCmdInsertDebugUtilsLabelEXT(commandBuffer, &housePartLabel); 241 242 vkCmdDrawIndexed(commandBuffer, 350, 1, 1650, 0, 0); 243 244 housePartLabel.pLabelName = "Roof"; 245 pfnCmdInsertDebugUtilsLabelEXT(commandBuffer, &housePartLabel); 246 247 vkCmdDrawIndexed(commandBuffer, 500, 1, 2000, 0, 0); 248 } 249 // End the house annotation started above 250 pfnCmdEndDebugUtilsLabelEXT(commandBuffer); 251 252 // Do other work 253 254 vkEndCommandBuffer(commandBuffer); 255 256 // Describe the queue being used 257 const VkDebugUtilsLabelEXT queueLabel = 258 { 259 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, 260 .pNext = NULL, 261 .pLabelName = "Main Render Work", 262 .color = { 0.0f, 1.0f, 0.0f, 1.0f }, 263 }; 264 265 // Identify the queue label region 266 pfnQueueBeginDebugUtilsLabelEXT(queue, &queueLabel); 267 268 // Submit the work for the main render thread 269 const VkCommandBuffer cmd_bufs[] = {commandBuffer}; 270 VkSubmitInfo submit_info = 271 { 272 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, 273 .pNext = NULL, 274 .waitSemaphoreCount = 0, 275 .pWaitSemaphores = NULL, 276 .pWaitDstStageMask = NULL, 277 .commandBufferCount = 1, 278 .pCommandBuffers = cmd_bufs, 279 .signalSemaphoreCount = 0, 280 .pSignalSemaphores = NULL 281 }; 282 vkQueueSubmit(queue, 1, &submit_info, fence); 283 284 // End the queue label region 285 pfnQueueEndDebugUtilsLabelEXT(queue); 286---- 287 288=== Issues 289 2901) Should we just name this extension `VK_EXT_debug_report2` 291 292*RESOLVED*: No. 293There is enough additional changes to the structures to break backwards 294compatibility. 295So, a new name was decided that would not indicate any interaction with the 296previous extension. 297 2982) Will validation layers immediately support all the new features. 299 300*RESOLVED*: Not immediately. 301As one can imagine, there is a lot of work involved with converting the 302validation layer logging over to the new functionality. 303Basic logging, as seen in the origin `apiext:VK_EXT_debug_report` extension 304will be made available immediately. 305However, adding the labels and object names will take time. 306Since the priority for Khronos at this time is to continue focusing on Valid 307Usage statements, it may take a while before the new functionality is fully 308exposed. 309 3103) If the validation layers will not expose the new functionality 311immediately, then what is the point of this extension? 312 313*RESOLVED*: We needed a replacement for `apiext:VK_EXT_debug_report` because 314the elink:VkDebugReportObjectTypeEXT enumeration will no longer be updated 315and any new objects will need to be debugged using the new functionality 316provided by this extension. 317 3184) Should this extension be split into two separate parts (1 extension that 319is an instance extension providing the callback functionality, and another 320device extension providing the general debug marker and annotation 321functionality)? 322 323*RESOLVED*: No, the functionality for this extension is too closely related. 324If we did split up the extension, where would the structures and enums live, 325and how would you define that the device behavior in the instance extension 326is really only valid if the device extension is enabled, and the 327functionality is passed in. 328It is cleaner to just define this all as an instance extension, plus it 329allows the application to enable all debug functionality provided with one 330enable string during flink:vkCreateInstance. 331 332=== Version History 333 334 * Revision 1, 2017-09-14 (Mark Young and all listed Contributors) 335 ** Initial draft, based on `apiext:VK_EXT_debug_report` and 336 `apiext:VK_EXT_debug_marker` in addition to previous feedback supplied 337 from various companies including Valve, Epic, and Oxide games. 338 * Revision 2, 2020-04-03 (Mark Young and Piers Daniell) 339 ** Updated to allow either `NULL` or an empty string to be passed in for 340 pname:pObjectName in sname:VkDebugUtilsObjectNameInfoEXT, because the 341 loader and various drivers support `NULL` already. 342