From 57d0d10fcfd6f8881ae5d4885d3f5f9ad2fdebe7 Mon Sep 17 00:00:00 2001 From: spencer-lunarg Date: Mon, 27 Jul 2026 19:01:16 -0400 Subject: [PATCH] Cleanup VK_EXT_debug_utils section --- chapters/extensions/VK_EXT_debug_utils.adoc | 442 +++++------------- .../VK_EXT_debug_utils_being_end_insert.png | Bin 0 -> 27400 bytes 2 files changed, 127 insertions(+), 315 deletions(-) create mode 100644 chapters/images/extensions/VK_EXT_debug_utils_being_end_insert.png 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 0000000000000000000000000000000000000000..4f6f86f6e0366f8b3ef8e8fbf41efa48b57f180a GIT binary patch literal 27400 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 BroaFI literal 0 HcmV?d00001