Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8316fc7

Browse files
committed
Update tutorial to use VK_EXT_debug_utils (fixes #102)
1 parent 5ad7592 commit 8316fc7

30 files changed

Lines changed: 484 additions & 443 deletions

03_Drawing_a_triangle/00_Setup/02_Validation_layers.md

Lines changed: 64 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ If the check was successful then `vkCreateInstance` should not ever return a
169169

170170
Unfortunately just enabling the layers doesn't help much, because they currently
171171
have no way to relay the debug messages back to our program. To receive those
172-
messages we have to set up a callback, which requires the `VK_EXT_debug_report`
172+
messages we have to set up a callback, which requires the `VK_EXT_debug_utils`
173173
extension.
174174

175175
We'll first create a `getRequiredExtensions` function that will return the
@@ -185,7 +185,7 @@ std::vector<const char*> getRequiredExtensions() {
185185
std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
186186

187187
if (enableValidationLayers) {
188-
extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
188+
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
189189
}
190190

191191
return extensions;
@@ -194,8 +194,8 @@ std::vector<const char*> getRequiredExtensions() {
194194

195195
The extensions specified by GLFW are always required, but the debug report
196196
extension is conditionally added. Note that I've used the
197-
`VK_EXT_DEBUG_REPORT_EXTENSION_NAME` macro here which is equal to the literal
198-
string "VK_EXT_debug_report". Using this macro lets you avoid typos.
197+
`VK_EXT_DEBUG_UTILS_EXTENSION_NAME` macro here which is equal to the literal
198+
string "VK_EXT_debug_utils". Using this macro lets you avoid typos.
199199

200200
We can now use this function in `createInstance`:
201201

@@ -211,42 +211,51 @@ existence of this extension, because it should be implied by the availability of
211211
the validation layers.
212212

213213
Now let's see what a callback function looks like. Add a new static member
214-
function called `debugCallback` with the `PFN_vkDebugReportCallbackEXT`
214+
function called `debugCallback` with the `PFN_vkDebugUtilsMessengerCallbackEXT`
215215
prototype. The `VKAPI_ATTR` and `VKAPI_CALL` ensure that the function has the
216216
right signature for Vulkan to call it.
217217

218218
```c++
219219
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
220-
VkDebugReportFlagsEXT flags,
221-
VkDebugReportObjectTypeEXT objType,
222-
uint64_t obj,
223-
size_t location,
224-
int32_t code,
225-
const char* layerPrefix,
226-
const char* msg,
227-
void* userData) {
220+
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
221+
VkDebugUtilsMessageTypeFlagsEXT messageType,
222+
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
223+
void* pUserData) {
228224

229-
std::cerr << "validation layer: " << msg << std::endl;
225+
std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;
230226

231227
return VK_FALSE;
232228
}
233229
```
234230
235-
The first parameter specifies the type of message, which can be a combination of
236-
any of the following bit flags:
231+
The first parameter specifies the severity of the message, which is one of the following flags:
237232
238-
* `VK_DEBUG_REPORT_INFORMATION_BIT_EXT`
239-
* `VK_DEBUG_REPORT_WARNING_BIT_EXT`
240-
* `VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT`
241-
* `VK_DEBUG_REPORT_ERROR_BIT_EXT`
242-
* `VK_DEBUG_REPORT_DEBUG_BIT_EXT`
233+
* `VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT`: Diagnostic message
234+
* `VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT`: Informational message like the creation of a resource
235+
* `VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT`: Message about behavior that is not necessarily an error, but very likely a bug in your application
236+
* `VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT`: Message about behavior that is invalid and may cause crashes
243237
244-
The `objType` parameter specifies the type of object that is the subject of the
245-
message. For example if `obj` is a `VkPhysicalDevice` then `objType` would be
246-
`VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT`. This works because internally all
247-
Vulkan handles are typedef'd as `uint64_t`. The `msg` parameter contains the
248-
pointer to the message itself. Finally, there's a `userData` parameter to pass
249-
your own data to the callback.
238+
The values of this enumeration are set up in such a way that you can use a comparison operation to check if a message is equal or worse compared to some level of severity, for example:
239+
240+
```c++
241+
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
242+
// Message is important enough to show
243+
}
244+
```
245+
246+
The `messageType` parameter can have the following values:
247+
248+
* `VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT`: Some event has happened that is unrelated to the specification or performance
249+
* `VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT`: Something has happened that violates the specification or indicates a possible mistake
250+
* `VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT`: Potential non-optimal use of Vulkan
251+
252+
The `pCallbackData` parameter refers to a `VkDebugUtilsMessengerCallbackDataEXT` struct containing the details of the message itself, with the most important members being:
253+
254+
* `pMessage`: The debug message as a null-terminated string
255+
* `pObjects`: Array of Vulkan object handles related to the message
256+
* `objectCount`: Number of objects in array
257+
258+
Finally, the `pUserData` parameter contains a pointer that was specified during the setup of the callback and allows you to pass your own data to it.
250259

251260
The callback returns a boolean that indicates if the Vulkan call that triggered
252261
the validation layer message should be aborted. If the callback returns true,
@@ -256,11 +265,11 @@ always return `VK_FALSE`.
256265

257266
All that remains now is telling Vulkan about the callback function. Perhaps
258267
somewhat surprisingly, even the debug callback in Vulkan is managed with a
259-
handle that needs to be explicitly created and destroyed. Add a class member for
268+
handle that needs to be explicitly created and destroyed. Such a callback is called a *messenger* and you can have as many of them as you want. Add a class member for
260269
this handle right under `instance`:
261270

262271
```c++
263-
VkDebugReportCallbackEXT callback;
272+
VkDebugUtilsMessengerEXT callback;
264273
```
265274

266275
Now add a function `setupDebugCallback` to be called from `initVulkan` right
@@ -281,28 +290,32 @@ void setupDebugCallback() {
281290
We'll need to fill in a structure with details about the callback:
282291

283292
```c++
284-
VkDebugReportCallbackCreateInfoEXT createInfo = {};
285-
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
286-
createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
287-
createInfo.pfnCallback = debugCallback;
293+
VkDebugUtilsMessengerCreateInfoEXT createInfo = {};
294+
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
295+
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
296+
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
297+
createInfo.pfnUserCallback = debugCallback;
298+
createInfo.pUserData = nullptr; // Optional
288299
```
289300

290-
The `flags` field allows you to filter which types of messages you would like to
291-
receive. The `pfnCallback` field specifies the pointer to the callback function.
292-
You can optionally pass a pointer to the `pUserData` field which will be passed
293-
along to the callback function via the `userData` parameter. You could use this
294-
to pass a pointer to the `HelloTriangleApplication` class, for example.
301+
The `messageSeverity` field allows you to specify all the types of severities you would like your callback to be called for. I've specified all types except for `VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT` here to receive notifications about possible problems while leaving out verbose general debug info.
302+
303+
Similarly the `messageType` field lets you filter which types of messages your callback is notified about. I've simply enabled all types here. You can always disable some if they're not useful to you.
304+
305+
Finally, the `pfnUserCallback` field specifies the pointer to the callback function. You can optionally pass a pointer to the `pUserData` field which will be passed along to the callback function via the `pUserData` parameter. You could use this to pass a pointer to the `HelloTriangleApplication` class, for example.
306+
307+
Note that there are many more ways to configure validation layer messages and debug callbacks, but this is a good setup to get started with for this tutorial. See the [extension specification](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VK_EXT_debug_utils) for more info about the possibilities.
295308

296-
This struct should be passed to the `vkCreateDebugReportCallbackEXT` function to
297-
create the `VkDebugReportCallbackEXT` object. Unfortunately, because this
309+
This struct should be passed to the `vkCreateDebugUtilsMessengerEXT` function to
310+
create the `VkDebugUtilsMessengerEXT` object. Unfortunately, because this
298311
function is an extension function, it is not automatically loaded. We have to
299312
look up its address ourselves using `vkGetInstanceProcAddr`. We're going to
300313
create our own proxy function that handles this in the background. I've added it
301314
right above the `HelloTriangleApplication` class definition.
302315

303316
```c++
304-
VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback) {
305-
auto func = (PFN_vkCreateDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");
317+
VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pCallback) {
318+
auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
306319
if (func != nullptr) {
307320
return func(instance, pCreateInfo, pAllocator, pCallback);
308321
} else {
@@ -316,7 +329,7 @@ couldn't be loaded. We can now call this function to create the extension
316329
object if it's available:
317330
318331
```c++
319-
if (CreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &callback) != VK_SUCCESS) {
332+
if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &callback) != VK_SUCCESS) {
320333
throw std::runtime_error("failed to set up debug callback!");
321334
}
322335
```
@@ -332,16 +345,16 @@ window. You'll see that the following messages are printed to the command prompt
332345
![](/images/validation_layer_test.png)
333346

334347
Oops, it has already spotted a bug in our program! The
335-
`VkDebugReportCallbackEXT` object needs to be cleaned up with a call to
336-
`vkDestroyDebugReportCallbackEXT`. Similarly to `vkCreateDebugReportCallbackEXT`
337-
the function needs to be explicitly loaded. The reason for there being multiple messages is that multiple validation layers check for the deletion of the debug report callback.
348+
`VkDebugUtilsMessengerEXT` object needs to be cleaned up with a call to
349+
`vkDestroyDebugUtilsMessengerEXT`. Similarly to `vkCreateDebugUtilsMessengerEXT`
350+
the function needs to be explicitly loaded. Note that it is normal for this message to be printed multiple times. This happens because multiple validation layers check for for the deletion of the debug messenger.
338351

339352
Create another proxy function right
340-
below `CreateDebugReportCallbackEXT`:
353+
below `CreateDebugUtilsMessengerEXT`:
341354

342355
```c++
343-
void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator) {
344-
auto func = (PFN_vkDestroyDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
356+
void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT callback, const VkAllocationCallbacks* pAllocator) {
357+
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
345358
if (func != nullptr) {
346359
func(instance, callback, pAllocator);
347360
}
@@ -354,7 +367,7 @@ outside the class. We can then call it in the `cleanup` function:
354367
```c++
355368
void cleanup() {
356369
if (enableValidationLayers) {
357-
DestroyDebugReportCallbackEXT(instance, callback, nullptr);
370+
DestroyDebugUtilsMessengerEXT(instance, callback, nullptr);
358371
}
359372
360373
vkDestroyInstance(instance, nullptr);
@@ -372,7 +385,7 @@ breakpoint to the message callback and look at the stack trace.
372385
## Configuration
373386

374387
There are a lot more settings for the behavior of validation layers than just
375-
the flags specified in the `VkDebugReportCallbackCreateInfoEXT` struct. Browse
388+
the flags specified in the `VkDebugUtilsMessengerCreateInfoEXT` struct. Browse
376389
to the Vulkan SDK and go to the `Config` directory. There you will find a
377390
`vk_layer_settings.txt` file that explains how to configure the layers.
378391

code/02_validation_layers.cpp

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ const bool enableValidationLayers = false;
2020
const bool enableValidationLayers = true;
2121
#endif
2222

23-
VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback) {
24-
auto func = (PFN_vkCreateDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");
23+
VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pCallback) {
24+
auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
2525
if (func != nullptr) {
2626
return func(instance, pCreateInfo, pAllocator, pCallback);
2727
} else {
2828
return VK_ERROR_EXTENSION_NOT_PRESENT;
2929
}
3030
}
3131

32-
void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator) {
33-
auto func = (PFN_vkDestroyDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
32+
void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT callback, const VkAllocationCallbacks* pAllocator) {
33+
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
3434
if (func != nullptr) {
3535
func(instance, callback, pAllocator);
3636
}
@@ -49,7 +49,7 @@ class HelloTriangleApplication {
4949
GLFWwindow* window;
5050

5151
VkInstance instance;
52-
VkDebugReportCallbackEXT callback;
52+
VkDebugUtilsMessengerEXT callback;
5353

5454
void initWindow() {
5555
glfwInit();
@@ -73,7 +73,7 @@ class HelloTriangleApplication {
7373

7474
void cleanup() {
7575
if (enableValidationLayers) {
76-
DestroyDebugReportCallbackEXT(instance, callback, nullptr);
76+
DestroyDebugUtilsMessengerEXT(instance, callback, nullptr);
7777
}
7878

7979
vkDestroyInstance(instance, nullptr);
@@ -119,12 +119,13 @@ class HelloTriangleApplication {
119119
void setupDebugCallback() {
120120
if (!enableValidationLayers) return;
121121

122-
VkDebugReportCallbackCreateInfoEXT createInfo = {};
123-
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
124-
createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
125-
createInfo.pfnCallback = debugCallback;
122+
VkDebugUtilsMessengerCreateInfoEXT createInfo = {};
123+
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
124+
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
125+
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
126+
createInfo.pfnUserCallback = debugCallback;
126127

127-
if (CreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &callback) != VK_SUCCESS) {
128+
if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &callback) != VK_SUCCESS) {
128129
throw std::runtime_error("failed to set up debug callback!");
129130
}
130131
}
@@ -137,7 +138,7 @@ class HelloTriangleApplication {
137138
std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
138139

139140
if (enableValidationLayers) {
140-
extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
141+
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
141142
}
142143

143144
return extensions;
@@ -168,8 +169,8 @@ class HelloTriangleApplication {
168169
return true;
169170
}
170171

171-
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, int32_t code, const char* layerPrefix, const char* msg, void* userData) {
172-
std::cerr << "validation layer: " << msg << std::endl;
172+
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) {
173+
std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;
173174

174175
return VK_FALSE;
175176
}

0 commit comments

Comments
 (0)