summaryrefslogtreecommitdiff
path: root/appendices/VK_EXT_debug_utils.adoc
blob: a7e53b37d303c1bac262f6f567513a722ac49b0a (plain)
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
// Copyright 2017-2024 The Khronos Group Inc.
//
// SPDX-License-Identifier: CC-BY-4.0

include::{generated}/meta/{refprefix}VK_EXT_debug_utils.adoc[]

=== Other Extension Metadata

*Last Modified Date*::
    2020-04-03
*Revision*::
    2
*IP Status*::
    No known IP claims.
*Dependencies*::
  - This extension is written against version 1.0 of the Vulkan API.
  - Requires elink:VkObjectType
*Contributors*::
  - Mark Young, LunarG
  - Baldur Karlsson
  - Ian Elliott, Google
  - Courtney Goeltzenleuchter, Google
  - Karl Schultz, LunarG
  - Mark Lobodzinski, LunarG
  - Mike Schuchardt, LunarG
  - Jaakko Konttinen, AMD
  - Dan Ginsburg, Valve Software
  - Rolando Olivares, Epic Games
  - Dan Baker, Oxide Games
  - Kyle Spagnoli, NVIDIA
  - Jon Ashburn, LunarG
  - Piers Daniell, NVIDIA

=== Description

Due to the nature of the Vulkan interface, there is very little error
information available to the developer and application.
By using the `VK_EXT_debug_utils` extension, developers can: obtain more
information.
When combined with validation layers, even more detailed feedback on the
application's use of Vulkan will be provided.

This extension provides the following capabilities:

  - The ability to create a debug messenger which will pass along debug
    messages to an application supplied callback.
  - The ability to identify specific Vulkan objects using a name or tag to
    improve tracking.
  - The ability to identify specific sections within a sname:VkQueue or
    sname:VkCommandBuffer using labels to aid organization and offline
    analysis in external tools.

The main difference between this extension and `apiext:VK_EXT_debug_report`
and `apiext:VK_EXT_debug_marker` is that those extensions use
elink:VkDebugReportObjectTypeEXT to identify objects.
This extension uses the core elink:VkObjectType in place of
elink:VkDebugReportObjectTypeEXT.
The primary reason for this move is that no future object type handle
enumeration values will be added to elink:VkDebugReportObjectTypeEXT since
the creation of elink:VkObjectType.

In addition, this extension combines the functionality of both
`apiext:VK_EXT_debug_report` and `apiext:VK_EXT_debug_marker` by allowing
object name and debug markers (now called labels) to be returned to the
application's callback function.
This should assist in clarifying the details of a debug message including:
what objects are involved and potentially which location within a
slink:VkQueue or slink:VkCommandBuffer the message occurred.

include::{generated}/interfaces/VK_EXT_debug_utils.adoc[]

=== Examples

*Example 1*

`VK_EXT_debug_utils` allows an application to register multiple callbacks
with any Vulkan component wishing to report debug information.
Some callbacks may log the information to a file, others may cause a debug
break point or other application defined behavior.
An application can: register callbacks even when no validation layers are
enabled, but they will only be called for loader and, if implemented, driver
events.

To capture events that occur while creating or destroying an instance an
application can: link a slink:VkDebugUtilsMessengerCreateInfoEXT structure
to the pname:pNext element of the slink:VkInstanceCreateInfo structure given
to flink:vkCreateInstance.

Example uses: Create three callback objects.
One will log errors and warnings to the debug console using Windows
code:OutputDebugString.
The second will cause the debugger to break at that callback when an error
happens and the third will log warnings to stdout.

[source,c++]
----
    extern VkInstance instance;
    VkResult res;
    VkDebugUtilsMessengerEXT cb1, cb2, cb3;

    // Must call extension functions through a function pointer:
    PFN_vkCreateDebugUtilsMessengerEXT pfnCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
    PFN_vkDestroyDebugUtilsMessengerEXT pfnDestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");

    VkDebugUtilsMessengerCreateInfoEXT callback1 = {
        .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
        .pNext = NULL,
        .flags = 0,
        .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
                           VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT,
        .messageType= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
                      VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
        .pfnUserCallback = myOutputDebugString,
        .pUserData = NULL
    };
    res = pfnCreateDebugUtilsMessengerEXT(instance, &callback1, NULL, &cb1);
    if (res != VK_SUCCESS) {
       // Do error handling for VK_ERROR_OUT_OF_MEMORY
    }

    callback1.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
    callback1.pfnUserCallback = myDebugBreak;
    callback1.pUserData = NULL;
    res = pfnCreateDebugUtilsMessengerEXT(instance, &callback1, NULL, &cb2);
    if (res != VK_SUCCESS) {
       // Do error handling for VK_ERROR_OUT_OF_MEMORY
    }

    VkDebugUtilsMessengerCreateInfoEXT callback3 = {
        .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
        .pNext = NULL,
        .flags = 0,
        .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT,
        .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
                       VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
        .pfnUserCallback = mystdOutLogger,
        .pUserData = NULL
    };
    res = pfnCreateDebugUtilsMessengerEXT(instance, &callback3, NULL, &cb3);
    if (res != VK_SUCCESS) {
       // Do error handling for VK_ERROR_OUT_OF_MEMORY
    }

    ...

    // Remove callbacks when cleaning up
    pfnDestroyDebugUtilsMessengerEXT(instance, cb1, NULL);
    pfnDestroyDebugUtilsMessengerEXT(instance, cb2, NULL);
    pfnDestroyDebugUtilsMessengerEXT(instance, cb3, NULL);
----

*Example 2*

Associate a name with an image, for easier debugging in external tools or
with validation layers that can print a friendly name when referring to
objects in error messages.

[source,c++]
----
    extern VkInstance instance;
    extern VkDevice device;
    extern VkImage image;

    // Must call extension functions through a function pointer:
    PFN_vkSetDebugUtilsObjectNameEXT pfnSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectNameEXT");

    // Set a name on the image
    const VkDebugUtilsObjectNameInfoEXT imageNameInfo =
    {
        .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
        .pNext = NULL,
        .objectType = VK_OBJECT_TYPE_IMAGE,
        .objectHandle = (uint64_t)image,
        .pObjectName = "Brick Diffuse Texture",
    };

    pfnSetDebugUtilsObjectNameEXT(device, &imageNameInfo);

    // A subsequent error might print:
    //   Image 'Brick Diffuse Texture' (0xc0dec0dedeadbeef) is used in a
    //   command buffer with no memory bound to it.
----

*Example 3*

Annotating regions of a workload with naming information so that offline
analysis tools can display a more usable visualization of the commands
submitted.

[source,c++]
----
    extern VkInstance instance;
    extern VkCommandBuffer commandBuffer;

    // Must call extension functions through a function pointer:
    PFN_vkQueueBeginDebugUtilsLabelEXT pfnQueueBeginDebugUtilsLabelEXT = (PFN_vkQueueBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkQueueBeginDebugUtilsLabelEXT");
    PFN_vkQueueEndDebugUtilsLabelEXT pfnQueueEndDebugUtilsLabelEXT = (PFN_vkQueueEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkQueueEndDebugUtilsLabelEXT");
    PFN_vkCmdBeginDebugUtilsLabelEXT pfnCmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdBeginDebugUtilsLabelEXT");
    PFN_vkCmdEndDebugUtilsLabelEXT pfnCmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdEndDebugUtilsLabelEXT");
    PFN_vkCmdInsertDebugUtilsLabelEXT pfnCmdInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdInsertDebugUtilsLabelEXT");

    // Describe the area being rendered
    const VkDebugUtilsLabelEXT houseLabel =
    {
        .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
        .pNext = NULL,
        .pLabelName = "Brick House",
        .color = { 1.0f, 0.0f, 0.0f, 1.0f },
    };

    // Start an annotated group of calls under the 'Brick House' name
    pfnCmdBeginDebugUtilsLabelEXT(commandBuffer, &houseLabel);
    {
        // A mutable structure for each part being rendered
        VkDebugUtilsLabelEXT housePartLabel =
        {
            .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
            .pNext = NULL,
            .pLabelName = NULL,
            .color = { 0.0f, 0.0f, 0.0f, 0.0f },
        };

        // Set the name and insert the marker
        housePartLabel.pLabelName = "Walls";
        pfnCmdInsertDebugUtilsLabelEXT(commandBuffer, &housePartLabel);

        // Insert the drawcall for the walls
        vkCmdDrawIndexed(commandBuffer, 1000, 1, 0, 0, 0);

        // Insert a recursive region for two sets of windows
        housePartLabel.pLabelName = "Windows";
        pfnCmdBeginDebugUtilsLabelEXT(commandBuffer, &housePartLabel);
        {
            vkCmdDrawIndexed(commandBuffer, 75, 6, 1000, 0, 0);
            vkCmdDrawIndexed(commandBuffer, 100, 2, 1450, 0, 0);
        }
        pfnCmdEndDebugUtilsLabelEXT(commandBuffer);

        housePartLabel.pLabelName = "Front Door";
        pfnCmdInsertDebugUtilsLabelEXT(commandBuffer, &housePartLabel);

        vkCmdDrawIndexed(commandBuffer, 350, 1, 1650, 0, 0);

        housePartLabel.pLabelName = "Roof";
        pfnCmdInsertDebugUtilsLabelEXT(commandBuffer, &housePartLabel);

        vkCmdDrawIndexed(commandBuffer, 500, 1, 2000, 0, 0);
    }
    // End the house annotation started above
    pfnCmdEndDebugUtilsLabelEXT(commandBuffer);

    // Do other work

    vkEndCommandBuffer(commandBuffer);

    // Describe the queue being used
    const VkDebugUtilsLabelEXT queueLabel =
    {
        .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
        .pNext = NULL,
        .pLabelName = "Main Render Work",
        .color = { 0.0f, 1.0f, 0.0f, 1.0f },
    };

    // Identify the queue label region
    pfnQueueBeginDebugUtilsLabelEXT(queue, &queueLabel);

    // Submit the work for the main render thread
    const VkCommandBuffer cmd_bufs[] = {commandBuffer};
    VkSubmitInfo submit_info =
    {
        .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
        .pNext = NULL,
        .waitSemaphoreCount = 0,
        .pWaitSemaphores = NULL,
        .pWaitDstStageMask = NULL,
        .commandBufferCount = 1,
        .pCommandBuffers = cmd_bufs,
        .signalSemaphoreCount = 0,
        .pSignalSemaphores = NULL
    };
    vkQueueSubmit(queue, 1, &submit_info, fence);

    // End the queue label region
    pfnQueueEndDebugUtilsLabelEXT(queue);
----

=== Issues

1) Should we just name this extension `VK_EXT_debug_report2`

*RESOLVED*: No.
There is enough additional changes to the structures to break backwards
compatibility.
So, a new name was decided that would not indicate any interaction with the
previous extension.

2) Will validation layers immediately support all the new features.

*RESOLVED*: Not immediately.
As one can imagine, there is a lot of work involved with converting the
validation layer logging over to the new functionality.
Basic logging, as seen in the origin `apiext:VK_EXT_debug_report` extension
will be made available immediately.
However, adding the labels and object names will take time.
Since the priority for Khronos at this time is to continue focusing on Valid
Usage statements, it may take a while before the new functionality is fully
exposed.

3) If the validation layers will not expose the new functionality
immediately, then what is the point of this extension?

*RESOLVED*: We needed a replacement for `apiext:VK_EXT_debug_report` because
the elink:VkDebugReportObjectTypeEXT enumeration will no longer be updated
and any new objects will need to be debugged using the new functionality
provided by this extension.

4) Should this extension be split into two separate parts (1 extension that
is an instance extension providing the callback functionality, and another
device extension providing the general debug marker and annotation
functionality)?

*RESOLVED*: No, the functionality for this extension is too closely related.
If we did split up the extension, where would the structures and enums live,
and how would you define that the device behavior in the instance extension
is really only valid if the device extension is enabled, and the
functionality is passed in.
It is cleaner to just define this all as an instance extension, plus it
allows the application to enable all debug functionality provided with one
enable string during flink:vkCreateInstance.

=== Version History

  * Revision 1, 2017-09-14 (Mark Young and all listed Contributors)
  ** Initial draft, based on `apiext:VK_EXT_debug_report` and
     `apiext:VK_EXT_debug_marker` in addition to previous feedback supplied
     from various companies including Valve, Epic, and Oxide games.
  * Revision 2, 2020-04-03 (Mark Young and Piers Daniell)
  ** Updated to allow either `NULL` or an empty string to be passed in for
     pname:pObjectName in sname:VkDebugUtilsObjectNameInfoEXT, because the
     loader and various drivers support `NULL` already.