diff --git a/src/vulkan/util/meson.build b/src/vulkan/util/meson.build index ecd2cc8b452..1bfd7a6cddd 100644 --- a/src/vulkan/util/meson.build +++ b/src/vulkan/util/meson.build @@ -56,6 +56,8 @@ files_vulkan_util = files( 'vk_command_buffer.h', 'vk_debug_report.c', 'vk_debug_report.h', + 'vk_debug_utils.c', + 'vk_debug_utils.h', 'vk_deferred_operation.c', 'vk_deferred_operation.h', 'vk_descriptors.c', diff --git a/src/vulkan/util/vk_command_buffer.c b/src/vulkan/util/vk_command_buffer.c index 23d2b669e2a..35b346d1ef2 100644 --- a/src/vulkan/util/vk_command_buffer.c +++ b/src/vulkan/util/vk_command_buffer.c @@ -31,16 +31,22 @@ vk_command_buffer_init(struct vk_command_buffer *command_buffer, vk_object_base_init(device, &command_buffer->base, VK_OBJECT_TYPE_COMMAND_BUFFER); + util_dynarray_init(&command_buffer->labels, NULL); + command_buffer->region_begin = true; + return VK_SUCCESS; } void vk_command_buffer_reset(struct vk_command_buffer *command_buffer) { + util_dynarray_clear(&command_buffer->labels); + command_buffer->region_begin = true; } void vk_command_buffer_finish(struct vk_command_buffer *command_buffer) { + util_dynarray_fini(&command_buffer->labels); vk_object_base_finish(&command_buffer->base); } diff --git a/src/vulkan/util/vk_command_buffer.h b/src/vulkan/util/vk_command_buffer.h index 96caefe4ca9..36622cfd9e9 100644 --- a/src/vulkan/util/vk_command_buffer.h +++ b/src/vulkan/util/vk_command_buffer.h @@ -33,6 +33,46 @@ extern "C" { struct vk_command_buffer { struct vk_object_base base; + + /** + * VK_EXT_debug_utils + * + * The next two fields represent debug labels storage. + * + * VK_EXT_debug_utils spec requires that upon triggering a debug message + * with a command buffer attached to it, all "active" labels will also be + * provided to the callback. The spec describes two distinct ways of + * attaching a debug label to the command buffer: opening a label region + * and inserting a single label. + * + * Label region is active between the corresponding `*BeginDebugUtilsLabel` + * and `*EndDebugUtilsLabel` calls. The spec doesn't mention any limits on + * nestedness of label regions. This implementation assumes that there + * aren't any. + * + * The spec, however, doesn't explain the lifetime of a label submitted by + * an `*InsertDebugUtilsLabel` call. The LunarG whitepaper [1] (pp 12-15) + * provides a more detailed explanation along with some examples. According + * to those, such label remains active until the next `*DebugUtilsLabel` + * call. This means that there can be no more than one such label at a + * time. + * + * \c labels contains all active labels at this point in order of submission + * \c region_begin denotes whether the most recent label opens a new region + * If \t labels is empty \t region_begin must be true. + * + * Anytime we modify labels, we first check for \c region_begin. If it's + * false, it means that the most recent label was submitted by + * `*InsertDebugUtilsLabel` and we need to remove it before doing anything + * else. + * + * See the discussion here: + * https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10318#note_1061317 + * + * [1] https://www.lunarg.com/wp-content/uploads/2018/05/Vulkan-Debug-Utils_05_18_v1.pdf + */ + struct util_dynarray labels; + bool region_begin; }; VK_DEFINE_HANDLE_CASTS(vk_command_buffer, base, VkCommandBuffer, diff --git a/src/vulkan/util/vk_debug_utils.c b/src/vulkan/util/vk_debug_utils.c new file mode 100644 index 00000000000..cd798af1104 --- /dev/null +++ b/src/vulkan/util/vk_debug_utils.c @@ -0,0 +1,285 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "vk_debug_utils.h" + +#include "vk_common_entrypoints.h" +#include "vk_command_buffer.h" +#include "vk_device.h" +#include "vk_queue.h" +#include "vk_object.h" +#include "vk_alloc.h" +#include "vk_util.h" +#include "stdarg.h" +#include "u_dynarray.h" + +void +vk_debug_message(struct vk_instance *instance, + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT types, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) +{ + mtx_lock(&instance->debug_utils.callbacks_mutex); + + list_for_each_entry(struct vk_debug_utils_messenger, messenger, + &instance->debug_utils.callbacks, link) { + if ((messenger->severity & severity) && + (messenger->type & types)) + messenger->callback(severity, types, pCallbackData, messenger->data); + } + + mtx_unlock(&instance->debug_utils.callbacks_mutex); +} + +/* This function intended to be used by the drivers to report a + * message to the special messenger, provided in the pNext chain while + * creating an instance. It's only meant to be used during + * vkCreateInstance or vkDestroyInstance calls. + */ +void +vk_debug_message_instance(struct vk_instance *instance, + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT types, + const char *pMessageIdName, + int32_t messageIdNumber, + const char *pMessage) +{ + if (list_is_empty(&instance->debug_utils.instance_callbacks)) + return; + + const VkDebugUtilsMessengerCallbackDataEXT cbData = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT, + .pMessageIdName = pMessageIdName, + .messageIdNumber = messageIdNumber, + .pMessage = pMessage, + }; + + list_for_each_entry(struct vk_debug_utils_messenger, messenger, + &instance->debug_utils.instance_callbacks, link) { + if ((messenger->severity & severity) && + (messenger->type & types)) + messenger->callback(severity, types, &cbData, messenger->data); + } +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_CreateDebugUtilsMessengerEXT( + VkInstance _instance, + const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDebugUtilsMessengerEXT *pMessenger) +{ + VK_FROM_HANDLE(vk_instance, instance, _instance); + + struct vk_debug_utils_messenger *messenger = + vk_alloc2(&instance->alloc, pAllocator, + sizeof(struct vk_debug_utils_messenger), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (!messenger) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + if (pAllocator) + messenger->alloc = *pAllocator; + else + messenger->alloc = instance->alloc; + + vk_object_base_init(NULL, &messenger->base, + VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT); + + messenger->severity = pCreateInfo->messageSeverity; + messenger->type = pCreateInfo->messageType; + messenger->callback = pCreateInfo->pfnUserCallback; + messenger->data = pCreateInfo->pUserData; + + mtx_lock(&instance->debug_utils.callbacks_mutex); + list_addtail(&messenger->link, &instance->debug_utils.callbacks); + mtx_unlock(&instance->debug_utils.callbacks_mutex); + + *pMessenger = vk_debug_utils_messenger_to_handle(messenger); + + return VK_SUCCESS; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_SubmitDebugUtilsMessageEXT( + VkInstance _instance, + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) +{ + VK_FROM_HANDLE(vk_instance, instance, _instance); + + vk_debug_message(instance, messageSeverity, messageTypes, pCallbackData); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_DestroyDebugUtilsMessengerEXT( + VkInstance _instance, + VkDebugUtilsMessengerEXT _messenger, + const VkAllocationCallbacks *pAllocator) +{ + VK_FROM_HANDLE(vk_instance, instance, _instance); + VK_FROM_HANDLE(vk_debug_utils_messenger, messenger, _messenger); + + if (messenger == NULL) + return; + + mtx_lock(&instance->debug_utils.callbacks_mutex); + list_del(&messenger->link); + mtx_unlock(&instance->debug_utils.callbacks_mutex); + + vk_object_base_finish(&messenger->base); + vk_free2(&instance->alloc, pAllocator, messenger); +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_SetDebugUtilsObjectNameEXT( + VkDevice _device, + const VkDebugUtilsObjectNameInfoEXT *pNameInfo) +{ + VK_FROM_HANDLE(vk_device, device, _device); + struct vk_object_base *object = + vk_object_base_from_u64_handle(pNameInfo->objectHandle, + pNameInfo->objectType); + + if (object->object_name) { + vk_free(&device->alloc, object->object_name); + object->object_name = NULL; + } + object->object_name = vk_strdup(&device->alloc, pNameInfo->pObjectName, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!object->object_name) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + return VK_SUCCESS; +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_SetDebugUtilsObjectTagEXT( + VkDevice _device, + const VkDebugUtilsObjectTagInfoEXT *pTagInfo) +{ + /* no-op */ + return VK_SUCCESS; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdBeginDebugUtilsLabelEXT( + VkCommandBuffer _commandBuffer, + const VkDebugUtilsLabelEXT *pLabelInfo) +{ + VK_FROM_HANDLE(vk_command_buffer, command_buffer, _commandBuffer); + + /* If the latest label was submitted by CmdInsertDebugUtilsLabelEXT, we + * should remove it first. + */ + if (!command_buffer->region_begin) + (void)util_dynarray_pop(&command_buffer->labels, VkDebugUtilsLabelEXT); + + util_dynarray_append(&command_buffer->labels, VkDebugUtilsLabelEXT, + *pLabelInfo); + command_buffer->region_begin = true; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdEndDebugUtilsLabelEXT(VkCommandBuffer _commandBuffer) +{ + VK_FROM_HANDLE(vk_command_buffer, command_buffer, _commandBuffer); + + /* If the latest label was submitted by CmdInsertDebugUtilsLabelEXT, we + * should remove it first. + */ + if (!command_buffer->region_begin) + (void)util_dynarray_pop(&command_buffer->labels, VkDebugUtilsLabelEXT); + + (void)util_dynarray_pop(&command_buffer->labels, VkDebugUtilsLabelEXT); + command_buffer->region_begin = true; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdInsertDebugUtilsLabelEXT( + VkCommandBuffer _commandBuffer, + const VkDebugUtilsLabelEXT *pLabelInfo) +{ + VK_FROM_HANDLE(vk_command_buffer, command_buffer, _commandBuffer); + + /* If the latest label was submitted by CmdInsertDebugUtilsLabelEXT, we + * should remove it first. + */ + if (!command_buffer->region_begin) + (void)util_dynarray_pop(&command_buffer->labels, VkDebugUtilsLabelEXT); + + util_dynarray_append(&command_buffer->labels, VkDebugUtilsLabelEXT, + *pLabelInfo); + command_buffer->region_begin = false; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_QueueBeginDebugUtilsLabelEXT( + VkQueue _queue, + const VkDebugUtilsLabelEXT *pLabelInfo) +{ + VK_FROM_HANDLE(vk_queue, queue, _queue); + + /* If the latest label was submitted by QueueInsertDebugUtilsLabelEXT, we + * should remove it first. + */ + if (!queue->region_begin) + (void)util_dynarray_pop(&queue->labels, VkDebugUtilsLabelEXT); + + util_dynarray_append(&queue->labels, VkDebugUtilsLabelEXT, *pLabelInfo); + queue->region_begin = true; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_QueueEndDebugUtilsLabelEXT(VkQueue _queue) +{ + VK_FROM_HANDLE(vk_queue, queue, _queue); + + /* If the latest label was submitted by QueueInsertDebugUtilsLabelEXT, we + * should remove it first. + */ + if (!queue->region_begin) + (void)util_dynarray_pop(&queue->labels, VkDebugUtilsLabelEXT); + + (void)util_dynarray_pop(&queue->labels, VkDebugUtilsLabelEXT); + queue->region_begin = true; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_QueueInsertDebugUtilsLabelEXT( + VkQueue _queue, + const VkDebugUtilsLabelEXT *pLabelInfo) +{ + VK_FROM_HANDLE(vk_queue, queue, _queue); + + /* If the latest label was submitted by QueueInsertDebugUtilsLabelEXT, we + * should remove it first. + */ + if (!queue->region_begin) + (void)util_dynarray_pop(&queue->labels, VkDebugUtilsLabelEXT); + + util_dynarray_append(&queue->labels, VkDebugUtilsLabelEXT, *pLabelInfo); + queue->region_begin = false; +} diff --git a/src/vulkan/util/vk_debug_utils.h b/src/vulkan/util/vk_debug_utils.h new file mode 100644 index 00000000000..0ffb4b38cdb --- /dev/null +++ b/src/vulkan/util/vk_debug_utils.h @@ -0,0 +1,67 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef VK_DEBUG_UTILS_H +#define VK_DEBUG_UTILS_H + +#include "vk_instance.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct vk_debug_utils_messenger { + struct vk_object_base base; + VkAllocationCallbacks alloc; + + struct list_head link; + + VkDebugUtilsMessageSeverityFlagsEXT severity; + VkDebugUtilsMessageTypeFlagsEXT type; + PFN_vkDebugUtilsMessengerCallbackEXT callback; + void *data; +}; + +VK_DEFINE_NONDISP_HANDLE_CASTS(vk_debug_utils_messenger, base, + VkDebugUtilsMessengerEXT, + VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT) + +void +vk_debug_message(struct vk_instance *instance, + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT types, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData); + +void +vk_debug_message_instance(struct vk_instance *instance, + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT types, + const char *pMessageIdName, + int32_t messageIdNumber, + const char *pMessage); + +#ifdef __cplusplus +} +#endif + +#endif /* VK_DEBUG_UTILS_H */ diff --git a/src/vulkan/util/vk_instance.c b/src/vulkan/util/vk_instance.c index 5787be170df..fdb1b480f30 100644 --- a/src/vulkan/util/vk_instance.c +++ b/src/vulkan/util/vk_instance.c @@ -26,6 +26,7 @@ #include "vk_alloc.h" #include "vk_common_entrypoints.h" #include "vk_util.h" +#include "vk_debug_utils.h" #include "compiler/glsl_types.h" @@ -40,6 +41,37 @@ vk_instance_init(struct vk_instance *instance, vk_object_base_init(NULL, &instance->base, VK_OBJECT_TYPE_INSTANCE); instance->alloc = *alloc; + /* VK_EXT_debug_utils */ + /* These messengers will only be used during vkCreateInstance or + * vkDestroyInstance calls. + */ + list_inithead(&instance->debug_utils.instance_callbacks); + vk_foreach_struct_const(ext, pCreateInfo->pNext) { + if (ext->sType == + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) { + const VkDebugUtilsMessengerCreateInfoEXT *debugMessengerCreateInfo = + (const VkDebugUtilsMessengerCreateInfoEXT *)ext; + struct vk_debug_utils_messenger *messenger = + vk_alloc2(alloc, alloc, sizeof(struct vk_debug_utils_messenger), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (!messenger) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + vk_object_base_init(NULL, &messenger->base, + VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT); + + messenger->alloc = *alloc; + messenger->severity = debugMessengerCreateInfo->messageSeverity; + messenger->type = debugMessengerCreateInfo->messageType; + messenger->callback = debugMessengerCreateInfo->pfnUserCallback; + messenger->data = debugMessengerCreateInfo->pUserData; + + list_addtail(&messenger->link, + &instance->debug_utils.instance_callbacks); + } + } + instance->app_info = (struct vk_app_info) { .api_version = 0 }; if (pCreateInfo->pApplicationInfo) { const VkApplicationInfo *app = pCreateInfo->pApplicationInfo; @@ -93,6 +125,13 @@ vk_instance_init(struct vk_instance *instance, list_inithead(&instance->debug_report.callbacks); + if (mtx_init(&instance->debug_utils.callbacks_mutex, mtx_plain) != 0) { + mtx_destroy(&instance->debug_report.callbacks_mutex); + return VK_ERROR_INITIALIZATION_FAILED; + } + + list_inithead(&instance->debug_utils.callbacks); + glsl_type_singleton_init_or_ref(); return VK_SUCCESS; @@ -102,7 +141,25 @@ void vk_instance_finish(struct vk_instance *instance) { glsl_type_singleton_decref(); + if (unlikely(!list_is_empty(&instance->debug_utils.callbacks))) { + list_for_each_entry_safe(struct vk_debug_utils_messenger, messenger, + &instance->debug_utils.callbacks, link) { + list_del(&messenger->link); + vk_object_base_finish(&messenger->base); + vk_free2(&instance->alloc, &messenger->alloc, messenger); + } + } + if (unlikely(!list_is_empty(&instance->debug_utils.instance_callbacks))) { + list_for_each_entry_safe(struct vk_debug_utils_messenger, messenger, + &instance->debug_utils.instance_callbacks, + link) { + list_del(&messenger->link); + vk_object_base_finish(&messenger->base); + vk_free2(&instance->alloc, &messenger->alloc, messenger); + } + } mtx_destroy(&instance->debug_report.callbacks_mutex); + mtx_destroy(&instance->debug_utils.callbacks_mutex); vk_free(&instance->alloc, (char *)instance->app_info.app_name); vk_free(&instance->alloc, (char *)instance->app_info.engine_name); vk_object_base_finish(&instance->base); diff --git a/src/vulkan/util/vk_instance.h b/src/vulkan/util/vk_instance.h index 5f195ca0d8e..88af1a6b4ed 100644 --- a/src/vulkan/util/vk_instance.h +++ b/src/vulkan/util/vk_instance.h @@ -56,6 +56,17 @@ struct vk_instance { mtx_t callbacks_mutex; struct list_head callbacks; } debug_report; + + /* VK_EXT_debug_utils */ + struct { + /* These callbacks are only used while creating or destroying an + * instance + */ + struct list_head instance_callbacks; + mtx_t callbacks_mutex; + /* Persistent callbacks */ + struct list_head callbacks; + } debug_utils; }; VK_DEFINE_HANDLE_CASTS(vk_instance, base, VkInstance, diff --git a/src/vulkan/util/vk_object.c b/src/vulkan/util/vk_object.c index c6921ca5e62..08f1eeea5ad 100644 --- a/src/vulkan/util/vk_object.c +++ b/src/vulkan/util/vk_object.c @@ -44,12 +44,16 @@ vk_object_base_init(struct vk_device *device, vk_object_base_reinit(base); base->type = obj_type; base->device = device; + base->object_name = NULL; } void vk_object_base_finish(struct vk_object_base *base) { util_sparse_array_finish(&base->private_data); + + if (base->object_name != NULL) + vk_free(&base->device->alloc, base->object_name); } void diff --git a/src/vulkan/util/vk_object.h b/src/vulkan/util/vk_object.h index c9c751ae261..ebaa2376997 100644 --- a/src/vulkan/util/vk_object.h +++ b/src/vulkan/util/vk_object.h @@ -46,6 +46,9 @@ struct vk_object_base { /* For VK_EXT_private_data */ struct util_sparse_array private_data; + + /* VK_EXT_debug_utils */ + char *object_name; }; void vk_object_base_init(UNUSED struct vk_device *device, diff --git a/src/vulkan/util/vk_queue.c b/src/vulkan/util/vk_queue.c index 68000bfe7e5..1ed48155584 100644 --- a/src/vulkan/util/vk_queue.c +++ b/src/vulkan/util/vk_queue.c @@ -29,11 +29,15 @@ vk_queue_init(struct vk_queue *queue, struct vk_device *device) memset(queue, 0, sizeof(*queue)); vk_object_base_init(device, &queue->base, VK_OBJECT_TYPE_QUEUE); + util_dynarray_init(&queue->labels, NULL); + queue->region_begin = true; + return VK_SUCCESS; } void vk_queue_finish(struct vk_queue *queue) { + util_dynarray_fini(&queue->labels); vk_object_base_finish(&queue->base); } diff --git a/src/vulkan/util/vk_queue.h b/src/vulkan/util/vk_queue.h index a5df99c6bd9..14d7f0f2fd8 100644 --- a/src/vulkan/util/vk_queue.h +++ b/src/vulkan/util/vk_queue.h @@ -33,6 +33,46 @@ extern "C" { struct vk_queue { struct vk_object_base base; + + /** + * VK_EXT_debug_utils + * + * The next two fields represent debug labels storage. + * + * VK_EXT_debug_utils spec requires that upon triggering a debug message + * with a queue attached to it, all "active" labels will also be provided + * to the callback. The spec describes two distinct ways of attaching a + * debug label to the queue: opening a label region and inserting a single + * label. + * + * Label region is active between the corresponding `*BeginDebugUtilsLabel` + * and `*EndDebugUtilsLabel` calls. The spec doesn't mention any limits on + * nestedness of label regions. This implementation assumes that there + * aren't any. + * + * The spec, however, doesn't explain the lifetime of a label submitted by + * an `*InsertDebugUtilsLabel` call. The LunarG whitepaper [1] (pp 12-15) + * provides a more detailed explanation along with some examples. According + * to those, such label remains active until the next `*DebugUtilsLabel` + * call. This means that there can be no more than one such label at a + * time. + * + * \c labels contains all active labels at this point in order of submission + * \c region_begin denotes whether the most recent label opens a new region + * If \t labels is empty \t region_begin must be true. + * + * Anytime we modify labels, we first check for \c region_begin. If it's + * false, it means that the most recent label was submitted by + * `*InsertDebugUtilsLabel` and we need to remove it before doing anything + * else. + * + * See the discussion here: + * https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10318#note_1061317 + * + * [1] https://www.lunarg.com/wp-content/uploads/2018/05/Vulkan-Debug-Utils_05_18_v1.pdf + */ + struct util_dynarray labels; + bool region_begin; }; VK_DEFINE_HANDLE_CASTS(vk_queue, base, VkQueue, VK_OBJECT_TYPE_QUEUE)