Module: Mesa
Branch: main
Commit: 3b361b234ac49f41a94a9bcf94fb68d5407b4b83
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=3b361b234ac49f41a94a9bcf94fb68d5407b4b83

Author: Yevhenii Kolesnikov <[email protected]>
Date:   Fri Apr  2 18:07:22 2021 +0300

vulkan: Implement VK_EXT_debug_utils

This implements all the necessary features of VK_EXT_debug_utils in
common code.

Signed-off-by: Yevhenii Kolesnikov <[email protected]>
Reviewed-by: Jason Ekstrand <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10318>

---

 src/vulkan/util/meson.build         |   2 +
 src/vulkan/util/vk_command_buffer.c |   6 +
 src/vulkan/util/vk_command_buffer.h |  40 +++++
 src/vulkan/util/vk_debug_utils.c    | 285 ++++++++++++++++++++++++++++++++++++
 src/vulkan/util/vk_debug_utils.h    |  67 +++++++++
 src/vulkan/util/vk_instance.c       |  57 ++++++++
 src/vulkan/util/vk_instance.h       |  11 ++
 src/vulkan/util/vk_object.c         |   4 +
 src/vulkan/util/vk_object.h         |   3 +
 src/vulkan/util/vk_queue.c          |   4 +
 src/vulkan/util/vk_queue.h          |  40 +++++
 11 files changed, 519 insertions(+)

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)

Reply via email to