1// Copyright 2017-2022 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[source,c++] 95------------------------------------------------------------------------------ 96 extern VkInstance instance; 97 VkResult res; 98 VkDebugUtilsMessengerEXT cb1, cb2, cb3; 99 100 // Must call extension functions through a function pointer: 101 PFN_vkCreateDebugUtilsMessengerEXT pfnCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"); 102 PFN_vkDestroyDebugUtilsMessengerEXT pfnDestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"); 103 104 VkDebugUtilsMessengerCreateInfoEXT callback1 = { 105 VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, // sType 106 NULL, // pNext 107 0, // flags 108 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | // messageSeverity 109 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, 110 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | // messageType 111 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, 112 myOutputDebugString, // pfnUserCallback 113 NULL // pUserData 114 }; 115 res = pfnCreateDebugUtilsMessengerEXT(instance, &callback1, NULL, &cb1); 116 if (res != VK_SUCCESS) { 117 // Do error handling for VK_ERROR_OUT_OF_MEMORY 118 } 119 120 callback1.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; 121 callback1.pfnUserCallback = myDebugBreak; 122 callback1.pUserData = NULL; 123 res = pfnCreateDebugUtilsMessengerEXT(instance, &callback1, NULL, &cb2); 124 if (res != VK_SUCCESS) { 125 // Do error handling for VK_ERROR_OUT_OF_MEMORY 126 } 127 128 VkDebugUtilsMessengerCreateInfoEXT callback3 = { 129 VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, // sType 130 NULL, // pNext 131 0, // flags 132 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, // messageSeverity 133 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | // messageType 134 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, 135 mystdOutLogger, // pfnUserCallback 136 NULL // pUserData 137 }; 138 res = pfnCreateDebugUtilsMessengerEXT(instance, &callback3, NULL, &cb3); 139 if (res != VK_SUCCESS) { 140 // Do error handling for VK_ERROR_OUT_OF_MEMORY 141 } 142 143 ... 144 145 // Remove callbacks when cleaning up 146 pfnDestroyDebugUtilsMessengerEXT(instance, cb1, NULL); 147 pfnDestroyDebugUtilsMessengerEXT(instance, cb2, NULL); 148 pfnDestroyDebugUtilsMessengerEXT(instance, cb3, NULL); 149------------------------------------------------------------------------------ 150 151*Example 2* 152 153Associate a name with an image, for easier debugging in external tools or 154with validation layers that can print a friendly name when referring to 155objects in error messages. 156 157[source,c++] 158---------------------------------------- 159 extern VkInstance instance; 160 extern VkDevice device; 161 extern VkImage image; 162 163 // Must call extension functions through a function pointer: 164 PFN_vkSetDebugUtilsObjectNameEXT pfnSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectNameEXT"); 165 166 // Set a name on the image 167 const VkDebugUtilsObjectNameInfoEXT imageNameInfo = 168 { 169 VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, // sType 170 NULL, // pNext 171 VK_OBJECT_TYPE_IMAGE, // objectType 172 (uint64_t)image, // objectHandle 173 "Brick Diffuse Texture", // pObjectName 174 }; 175 176 pfnSetDebugUtilsObjectNameEXT(device, &imageNameInfo); 177 178 // A subsequent error might print: 179 // Image 'Brick Diffuse Texture' (0xc0dec0dedeadbeef) is used in a 180 // command buffer with no memory bound to it. 181---------------------------------------- 182 183*Example 3* 184 185Annotating regions of a workload with naming information so that offline 186analysis tools can display a more usable visualization of the commands 187submitted. 188 189[source,c++] 190---------------------------------------- 191 extern VkInstance instance; 192 extern VkCommandBuffer commandBuffer; 193 194 // Must call extension functions through a function pointer: 195 PFN_vkQueueBeginDebugUtilsLabelEXT pfnQueueBeginDebugUtilsLabelEXT = (PFN_vkQueueBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkQueueBeginDebugUtilsLabelEXT"); 196 PFN_vkQueueEndDebugUtilsLabelEXT pfnQueueEndDebugUtilsLabelEXT = (PFN_vkQueueEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkQueueEndDebugUtilsLabelEXT"); 197 PFN_vkCmdBeginDebugUtilsLabelEXT pfnCmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdBeginDebugUtilsLabelEXT"); 198 PFN_vkCmdEndDebugUtilsLabelEXT pfnCmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdEndDebugUtilsLabelEXT"); 199 PFN_vkCmdInsertDebugUtilsLabelEXT pfnCmdInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdInsertDebugUtilsLabelEXT"); 200 201 // Describe the area being rendered 202 const VkDebugUtilsLabelEXT houseLabel = 203 { 204 VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, // sType 205 NULL, // pNext 206 "Brick House", // pLabelName 207 { 1.0f, 0.0f, 0.0f, 1.0f }, // color 208 }; 209 210 // Start an annotated group of calls under the 'Brick House' name 211 pfnCmdBeginDebugUtilsLabelEXT(commandBuffer, &houseLabel); 212 { 213 // A mutable structure for each part being rendered 214 VkDebugUtilsLabelEXT housePartLabel = 215 { 216 VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, // sType 217 NULL, // pNext 218 NULL, // pLabelName 219 { 0.0f, 0.0f, 0.0f, 0.0f }, // color 220 }; 221 222 // Set the name and insert the marker 223 housePartLabel.pLabelName = "Walls"; 224 pfnCmdInsertDebugUtilsLabelEXT(commandBuffer, &housePartLabel); 225 226 // Insert the drawcall for the walls 227 vkCmdDrawIndexed(commandBuffer, 1000, 1, 0, 0, 0); 228 229 // Insert a recursive region for two sets of windows 230 housePartLabel.pLabelName = "Windows"; 231 pfnCmdBeginDebugUtilsLabelEXT(commandBuffer, &housePartLabel); 232 { 233 vkCmdDrawIndexed(commandBuffer, 75, 6, 1000, 0, 0); 234 vkCmdDrawIndexed(commandBuffer, 100, 2, 1450, 0, 0); 235 } 236 pfnCmdEndDebugUtilsLabelEXT(commandBuffer); 237 238 housePartLabel.pLabelName = "Front Door"; 239 pfnCmdInsertDebugUtilsLabelEXT(commandBuffer, &housePartLabel); 240 241 vkCmdDrawIndexed(commandBuffer, 350, 1, 1650, 0, 0); 242 243 housePartLabel.pLabelName = "Roof"; 244 pfnCmdInsertDebugUtilsLabelEXT(commandBuffer, &housePartLabel); 245 246 vkCmdDrawIndexed(commandBuffer, 500, 1, 2000, 0, 0); 247 } 248 // End the house annotation started above 249 pfnCmdEndDebugUtilsLabelEXT(commandBuffer); 250 251 // Do other work 252 253 vkEndCommandBuffer(commandBuffer); 254 255 // Describe the queue being used 256 const VkDebugUtilsLabelEXT queueLabel = 257 { 258 VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, // sType 259 NULL, // pNext 260 "Main Render Work", // pLabelName 261 { 0.0f, 1.0f, 0.0f, 1.0f }, // color 262 }; 263 264 // Identify the queue label region 265 pfnQueueBeginDebugUtilsLabelEXT(queue, &queueLabel); 266 267 // Submit the work for the main render thread 268 const VkCommandBuffer cmd_bufs[] = {commandBuffer}; 269 VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, 270 .pNext = NULL, 271 .waitSemaphoreCount = 0, 272 .pWaitSemaphores = NULL, 273 .pWaitDstStageMask = NULL, 274 .commandBufferCount = 1, 275 .pCommandBuffers = cmd_bufs, 276 .signalSemaphoreCount = 0, 277 .pSignalSemaphores = NULL}; 278 vkQueueSubmit(queue, 1, &submit_info, fence); 279 280 // End the queue label region 281 pfnQueueEndDebugUtilsLabelEXT(queue); 282 283---------------------------------------- 284 285=== Issues 286 2871) Should we just name this extension `VK_EXT_debug_report2` 288 289*RESOLVED*: No. 290There is enough additional changes to the structures to break backwards 291compatibility. 292So, a new name was decided that would not indicate any interaction with the 293previous extension. 294 2952) Will validation layers immediately support all the new features. 296 297*RESOLVED*: Not immediately. 298As one can imagine, there is a lot of work involved with converting the 299validation layer logging over to the new functionality. 300Basic logging, as seen in the origin `apiext:VK_EXT_debug_report` extension 301will be made available immediately. 302However, adding the labels and object names will take time. 303Since the priority for Khronos at this time is to continue focusing on Valid 304Usage statements, it may take a while before the new functionality is fully 305exposed. 306 3073) If the validation layers will not expose the new functionality 308immediately, then what is the point of this extension? 309 310*RESOLVED*: We needed a replacement for `apiext:VK_EXT_debug_report` because 311the elink:VkDebugReportObjectTypeEXT enumeration will no longer be updated 312and any new objects will need to be debugged using the new functionality 313provided by this extension. 314 3154) Should this extension be split into two separate parts (1 extension that 316is an instance extension providing the callback functionality, and another 317device extension providing the general debug marker and annotation 318functionality)? 319 320*RESOLVED*: No, the functionality for this extension is too closely related. 321If we did split up the extension, where would the structures and enums live, 322and how would you define that the device behavior in the instance extension 323is really only valid if the device extension is enabled, and the 324functionality is passed in. 325It is cleaner to just define this all as an instance extension, plus it 326allows the application to enable all debug functionality provided with one 327enable string during flink:vkCreateInstance. 328 329=== Version History 330 331 * Revision 1, 2017-09-14 (Mark Young and all listed Contributors) 332 ** Initial draft, based on `apiext:VK_EXT_debug_report` and 333 `apiext:VK_EXT_debug_marker` in addition to previous feedback supplied 334 from various companies including Valve, Epic, and Oxide games. 335 * Revision 2, 2020-04-03 (Mark Young and Piers Daniell) 336 ** Updated to allow either `NULL` or an empty string to be passed in for 337 pname:pObjectName in sname:VkDebugUtilsObjectNameInfoEXT, because the 338 loader and various drivers support `NULL` already. 339