text: /*
   * 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;
  }
  