• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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