diff --git a/chapters/extensions/VK_EXT_debug_utils.adoc b/chapters/extensions/VK_EXT_debug_utils.adoc index 0ba63bd7..10557dec 100644 --- a/chapters/extensions/VK_EXT_debug_utils.adoc +++ b/chapters/extensions/VK_EXT_debug_utils.adoc @@ -1,8 +1,8 @@ // Copyright 2019-2026 The Khronos Group, Inc. // SPDX-License-Identifier: CC-BY-4.0 -ifndef::chapters[:chapters: ../../] -ifndef::images[:images: ../../images/] +ifndef::chapters[:chapters: ../] +ifndef::images[:images: ../images/] [[VK_EXT_debug_utils]] = VK_EXT_debug_utils @@ -26,25 +26,14 @@ The debug messenger is the core component for receiving validation and debug mes === Creating a Debug Messenger +[NOTE] +==== +See link:https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/main/docs/error_messages.md#custom-callback[Validation Layer Custom Callback] for more details about the debug callback. +==== + [source,cpp] ---- -// Function to create the debug messenger -VkResult CreateDebugUtilsMessengerEXT( - VkInstance instance, - const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDebugUtilsMessengerEXT* pMessenger) { - - auto vkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"); - - if (vkCreateDebugUtilsMessengerEXT != nullptr) { - return vkCreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger); - } else { - return VK_ERROR_EXTENSION_NOT_PRESENT; - } -} - -// Callback function for handling debug messages +// Custom callback function for handling debug messages VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, @@ -53,11 +42,24 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( std::cerr << "Validation layer: " << pCallbackData->pMessage << std::endl; - // Return VK_FALSE to indicate the Vulkan call should not be aborted - return VK_FALSE; + // Filter based on severity + if (messageSeverity < VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + return VK_FALSE; // Ignore verbose and info messages + } + + // Filter based on type + if (!(messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT)) { + return VK_FALSE; // Only show validation messages + } + + // Filter based on message ID + if (strstr(pCallbackData->pMessageIdName, "VUID-vkCmdDraw-magFilter-04553") != NULL) { + return VK_FALSE; + } + + return VK_FALSE; // if true, call will NOT be sent down to the driver } -// Setting up the debug messenger VkDebugUtilsMessengerCreateInfoEXT createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; createInfo.messageSeverity = @@ -72,94 +74,38 @@ createInfo.pfnUserCallback = debugCallback; createInfo.pUserData = nullptr; // Optional user data VkDebugUtilsMessengerEXT debugMessenger; -if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) { +if (vkCreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) { throw std::runtime_error("Failed to set up debug messenger!"); } ----- - -=== Destroying a Debug Messenger -[source,cpp] ----- -void DestroyDebugUtilsMessengerEXT( - VkInstance instance, - VkDebugUtilsMessengerEXT messenger, - const VkAllocationCallbacks* pAllocator) { - - auto vkDestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"); - - if (func != nullptr) { - vkDestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator); - } +// Don't forget to clean up after +void OnDestroy() { + vkDestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator); } ---- == Object Naming -One of the most useful features of the extension is the ability to assign names to Vulkan objects. This makes it much easier to identify objects in validation messages and debugging tools. +One of the **most** useful features of the extension is the ability to assign names to Vulkan objects. This makes it much easier to identify objects in validation messages and debugging tools. [source,cpp] ---- -// Function to set a debug name for a Vulkan object -void SetDebugUtilsObjectName( - VkDevice device, - VkObjectType objectType, - uint64_t objectHandle, - const char* name) { - - VkDebugUtilsObjectNameInfoEXT nameInfo{}; - nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - nameInfo.objectType = objectType; - nameInfo.objectHandle = objectHandle; - nameInfo.pObjectName = name; - - auto vkSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectNameEXT"); - - if (vkSetDebugUtilsObjectNameEXT != nullptr) { - vkSetDebugUtilsObjectNameEXT(device, &nameInfo); - } -} - -// Example: Naming a buffer -VkBuffer buffer; // Your buffer handle -SetDebugUtilsObjectName( - device, - VK_OBJECT_TYPE_BUFFER, - (uint64_t)buffer, - "My Vertex Buffer" -); ----- - -== Debug Markers and Regions - -Debug markers and regions allow you to annotate command buffer operations, making it easier to identify specific operations in debugging tools. +VkBuffer buffer = engine.CreateBuffer(); -=== Inserting Debug Markers +VkDebugUtilsObjectNameInfoEXT nameInfo{}; +nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; +nameInfo.objectType = VK_OBJECT_TYPE_BUFFER; +nameInfo.objectHandle = (uint64_t)buffer; +nameInfo.pObjectName = "My Vertex Buffer"; -[source,cpp] +vkSetDebugUtilsObjectNameEXT(device, &nameInfo); ---- -// Insert a debug marker into a command buffer -void CmdInsertDebugMarker( - VkCommandBuffer commandBuffer, - const char* markerName, - const float color[4]) { - - VkDebugUtilsLabelEXT markerInfo{}; - markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; - markerInfo.pLabelName = markerName; - memcpy(markerInfo.color, color, sizeof(float) * 4); - auto vkCmdInsertDebugUtilsLabelEXT = (PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdInsertDebugUtilsLabelEXT"); +It is that simple! When you create your Vulkan handles, to just add the `vkSetDebugUtilsObjectNameEXT` call to it right away. - if (vkCmdInsertDebugUtilsLabelEXT != nullptr) { - vkCmdInsertDebugUtilsLabelEXT(commandBuffer, &markerInfo); - } -} +== Debug Markers and Regions -// Example usage -float color[4] = {1.0f, 0.0f, 0.0f, 1.0f}; // Red color -CmdInsertDebugMarker(commandBuffer, "Important Draw Call", color); ----- +Debug markers and regions allow you to annotate command buffer operations, making it easier to identify specific operations in debugging tools. === Debug Regions @@ -176,34 +122,99 @@ void CmdBeginDebugRegion( VkDebugUtilsLabelEXT labelInfo{}; labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; labelInfo.pLabelName = regionName; + // Optional colors, not all tools will make use of this memcpy(labelInfo.color, color, sizeof(float) * 4); - auto vkCmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdBeginDebugUtilsLabelEXT"); - - if (vkCmdBeginDebugUtilsLabelEXT != nullptr) { - vkCmdBeginDebugUtilsLabelEXT(commandBuffer, &labelInfo); - } -} - -// End a debug region -void CmdEndDebugRegion(VkCommandBuffer commandBuffer) { - auto vkCmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdEndDebugUtilsLabelEXT"); - - if (vkCmdEndDebugUtilsLabelEXT != nullptr) { - vkCmdEndDebugUtilsLabelEXT(commandBuffer); - } + vkCmdBeginDebugUtilsLabelEXT(commandBuffer, &labelInfo); } // Example usage float shadowPassColor[4] = {0.0f, 0.0f, 0.0f, 1.0f}; // Black color CmdBeginDebugRegion(commandBuffer, "Shadow Pass", shadowPassColor); // Record shadow pass commands... -CmdEndDebugRegion(commandBuffer); +vkCmdEndDebugUtilsLabelEXT(commandBuffer); float geometryPassColor[4] = {0.0f, 1.0f, 0.0f, 1.0f}; // Green color CmdBeginDebugRegion(commandBuffer, "Geometry Pass", geometryPassColor); // Record geometry pass commands... -CmdEndDebugRegion(commandBuffer); +vkCmdEndDebugUtilsLabelEXT(commandBuffer); +---- + +==== Debug Region Stack + +The calls to `vkCmdBeginDebugUtilsLabelEXT`/`vkCmdEndDebugUtilsLabelEXT` are stack based, tools will append the various regions in when reporting a messsage. + +[source,cpp] +---- +// Region: [] +vkCmdBeginDebugUtilsLabelEXT("AAA"); +// Region: ["AAA"] +vkCmdBeginDebugUtilsLabelEXT("BBB"); +// Region: ["AAA", "BBB"] +vkCmdEndDebugUtilsLabelEXT(); +// Region: ["AAA"] +vkCmdBeginDebugUtilsLabelEXT("CCC"); +// Region: ["AAA", "CCC"] +vkCmdEndDebugUtilsLabelEXT(); +// Region: ["AAA"] +vkCmdEndDebugUtilsLabelEXT(); +// Region: [] +---- + +=== Inserting Debug Markers + +While the `Begin`/`End` are great for marking a region, you might want to mark an event on the timeline, this is where `Insert` is useful. + +To showcase this, if you go + +[source,cpp] +---- +for (int i = 0; i < 4; ++i) { + vkCmdBeginDebugUtilsLabelEXT("Draw " + i); + vkCmdDraw(); + vkCmdEndDebugUtilsLabelEXT(); +} +---- + +you will get a 4 small regions which can quickly turn into a lot of micro folding in an UI. Instead if you go + +[source,cpp] +---- +for (int i = 0; i < 4; ++i) { + vkCmdInsertDebugUtilsLabelEXT("Draw " + i); + vkCmdDraw(); +} +---- + +The UI will now just display a single element instead of a range for each item + +image::{images}extensions/VK_EXT_debug_utils_being_end_insert.png[VK_EXT_debug_utils_being_end_insert.png] + +[NOTE] +==== +Tools like the Validation Layers will **not** make use of an insert as it needs a range when printing the error message +==== + +[source,cpp] +---- +// Insert a debug marker into a command buffer +void CmdInsertDebugMarker( + VkCommandBuffer commandBuffer, + const char* markerName, + const float color[4]) { + + VkDebugUtilsLabelEXT markerInfo{}; + markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + markerInfo.pLabelName = markerName; + // Optional colors, not all tools will make use of this + memcpy(markerInfo.color, color, sizeof(float) * 4); + + vkCmdInsertDebugUtilsLabelEXT(commandBuffer, &markerInfo); +} + +// Example usage +float color[4] = {1.0f, 0.0f, 0.0f, 1.0f}; // Red color +CmdInsertDebugMarker(commandBuffer, "Important Draw Call", color); ---- == Queue Labels @@ -221,13 +232,10 @@ void QueueBeginDebugRegion( VkDebugUtilsLabelEXT labelInfo{}; labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; labelInfo.pLabelName = regionName; + // Optional colors, not all tools will make use of this memcpy(labelInfo.color, color, sizeof(float) * 4); - auto vkQueueBeginDebugUtilsLabelEXT = (PFN_vkQueueBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkQueueBeginDebugUtilsLabelEXT"); - - if (vkQueueBeginDebugUtilsLabelEXT != nullptr) { - vkQueueBeginDebugUtilsLabelEXT(queue, &labelInfo); - } + vkQueueBeginDebugUtilsLabelEXT(queue, &labelInfo); } // Insert a queue label @@ -239,23 +247,14 @@ void QueueInsertDebugMarker( VkDebugUtilsLabelEXT markerInfo{}; markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; markerInfo.pLabelName = markerName; + // Optional colors, not all tools will make use of this memcpy(markerInfo.color, color, sizeof(float) * 4); - auto vkQueueInsertDebugUtilsLabelEXT = (PFN_vkQueueInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkQueueInsertDebugUtilsLabelEXT"); - - if (vkQueueInsertDebugUtilsLabelEXT != nullptr) { - vkQueueInsertDebugUtilsLabelEXT(queue, &markerInfo); - } + vkQueueInsertDebugUtilsLabelEXT(queue, &markerInfo); } // End a queue label -void QueueEndDebugRegion(VkQueue queue) { - auto vkQueueEndDebugUtilsLabelEXT = (PFN_vkQueueEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkQueueEndDebugUtilsLabelEXT"); - - if (vkQueueEndDebugUtilsLabelEXT != nullptr) { - vkQueueEndDebugUtilsLabelEXT(queue); - } -} +vkQueueEndDebugUtilsLabelEXT(queue); ---- == Best Practices @@ -278,6 +277,7 @@ Establish consistent naming conventions for your debug labels to make them more Many external debugging tools support `VK_EXT_debug_utils` annotations: +* **Validation Layesr**: Displays names and regions in error messages * **RenderDoc**: Displays debug markers and regions in its event timeline * **NVIDIA Nsight**: Shows debug labels in its frame debugger * **AMD Radeon GPU Profiler**: Uses debug regions to organize GPU workloads @@ -412,88 +412,12 @@ const char* extensions[] = { "VK_EXT_debug_utils", ... }; === Creating a Debug Callback -The process of creating a debug callback has changed: - -[source,cpp] ----- -// Old way with VK_EXT_debug_report -VkDebugReportCallbackCreateInfoEXT createInfo = {}; -createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; -createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | - VK_DEBUG_REPORT_WARNING_BIT_EXT; -createInfo.pfnCallback = debugReportCallback; - -VkDebugReportCallbackEXT callback; -auto vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); -vkCreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &callback); - -// New way with VK_EXT_debug_utils -VkDebugUtilsMessengerCreateInfoEXT createInfo = {}; -createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; -createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; -createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; -createInfo.pfnUserCallback = debugUtilsCallback; - -VkDebugUtilsMessengerEXT messenger; -auto vkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"); -vkCreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &messenger); ----- - -=== Converting the Callback Function - -The callback function signature and parameters have changed: - -[source,cpp] ----- -// Old callback for VK_EXT_debug_report -VKAPI_ATTR VkBool32 VKAPI_CALL debugReportCallback( - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char* pLayerPrefix, - const char* pMessage, - void* pUserData) { - - std::cerr << "Validation layer: " << pMessage << std::endl; - return VK_FALSE; -} - -// New callback for VK_EXT_debug_utils -VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsCallback( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData) { - - std::cerr << "Validation layer: " << pCallbackData->pMessage << std::endl; - return VK_FALSE; -} ----- +Replace `vkCreateDebugReportCallbackEXT`/`vkDestroyDebugReportCallbackEXT` with `vkCreateDebugUtilsMessengerEXT`/`vkDestroyDebugUtilsMessengerEXT` === Mapping Message Severity The message severity flags have been renamed and expanded: -[source,cpp] ----- -// VK_EXT_debug_report severity flags -VK_DEBUG_REPORT_INFORMATION_BIT_EXT -VK_DEBUG_REPORT_WARNING_BIT_EXT -VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT -VK_DEBUG_REPORT_ERROR_BIT_EXT -VK_DEBUG_REPORT_DEBUG_BIT_EXT - -// VK_EXT_debug_utils severity flags (more granular) -VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT -VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT -VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT -VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT ----- - Mapping between the two: * `VK_DEBUG_REPORT_INFORMATION_BIT_EXT` → `VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT` @@ -502,118 +426,6 @@ Mapping between the two: * `VK_DEBUG_REPORT_ERROR_BIT_EXT` → `VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT` * `VK_DEBUG_REPORT_DEBUG_BIT_EXT` → `VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT` -=== Message Types - -`VK_EXT_debug_utils` introduces message types which didn't exist in `VK_EXT_debug_report`: - -[source,cpp] ----- -VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT -VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT -VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT ----- - -For most validation layer messages, you'll want to use `VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT`. - -=== Destroying the Debug Callback - -The destruction function has also changed: - -[source,cpp] ----- -// Old way with VK_EXT_debug_report -auto vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); -vkDestroyDebugReportCallbackEXT(instance, callback, nullptr); - -// New way with VK_EXT_debug_utils -auto vkDestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"); -vkDestroyDebugUtilsMessengerEXT(instance, messenger, nullptr); ----- - -=== Object Naming - -One of the biggest advantages of `VK_EXT_debug_utils` is the ability to name Vulkan objects, which wasn't possible with `VK_EXT_debug_report`: - -[source,cpp] ----- -// Not available in VK_EXT_debug_report - -// New capability in VK_EXT_debug_utils -VkDebugUtilsObjectNameInfoEXT nameInfo = {}; -nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; -nameInfo.objectType = VK_OBJECT_TYPE_BUFFER; -nameInfo.objectHandle = (uint64_t)buffer; -nameInfo.pObjectName = "My Vertex Buffer"; - -auto vkSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectNameEXT"); -vkSetDebugUtilsObjectNameEXT(device, &nameInfo); ----- - -=== Debug Markers and Regions - -Another major feature in `VK_EXT_debug_utils` that wasn't in `VK_EXT_debug_report` is the ability to insert debug markers and regions: - -[source,cpp] ----- -// Not available in VK_EXT_debug_report - -// New capability in VK_EXT_debug_utils for command buffer labeling -VkDebugUtilsLabelEXT labelInfo = {}; -labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; -labelInfo.pLabelName = "Draw Skybox"; -float color[4] = {0.0f, 0.0f, 1.0f, 1.0f}; // Blue -memcpy(labelInfo.color, color, sizeof(float) * 4); - -auto vkCmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdBeginDebugUtilsLabelEXT"); -vkCmdBeginDebugUtilsLabelEXT(commandBuffer, &labelInfo); - -// Record commands... - -auto vkCmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdEndDebugUtilsLabelEXT"); -vkCmdEndDebugUtilsLabelEXT(commandBuffer); ----- - -=== Filtering Messages - -Both extensions allow filtering messages, but `VK_EXT_debug_utils` provides more granular control: - -[source,cpp] ----- -// VK_EXT_debug_report filtering (limited) -VkBool32 debugReportCallback(/* ... */) { - // Filter based on message content - if (strstr(pMessage, "specialuse-extension") != NULL) { - return VK_FALSE; - } - // ... -} - -// VK_EXT_debug_utils filtering (more options) -VkBool32 debugUtilsCallback( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData) { - - // Filter based on severity - if (messageSeverity < VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { - return VK_FALSE; // Ignore verbose and info messages - } - - // Filter based on type - if (!(messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT)) { - return VK_FALSE; // Only show validation messages - } - - // Filter based on message ID - if (strstr(pCallbackData->pMessageIdName, "specialuse-extension") != NULL) { - return VK_FALSE; - } - - // ... -} ----- - == Conclusion The `VK_EXT_debug_utils` extension represents a significant advancement in Vulkan debugging capabilities. By providing a comprehensive set of tools for object naming, command annotation, and validation feedback, it addresses critical challenges in GPU application development. diff --git a/chapters/images/extensions/VK_EXT_debug_utils_being_end_insert.png b/chapters/images/extensions/VK_EXT_debug_utils_being_end_insert.png new file mode 100644 index 00000000..4f6f86f6 Binary files /dev/null and b/chapters/images/extensions/VK_EXT_debug_utils_being_end_insert.png differ