Fix Debug callbacks in layers in vkCreateInstance
authorMark Young <marky@lunarg.com>
Fri, 27 Oct 2023 18:59:32 +0000 (12:59 -0600)
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>
Tue, 31 Oct 2023 06:17:41 +0000 (00:17 -0600)
After a layer calls down to vkCreateInstance, it may need to create a
DebugUtils Messenger (or Report object) for capturing debug information.
With the old design, it would get handled as a "during vkCreateInstance"
debug utils messenger object because the loader trampoline was still
in the middle of "vkCreateInstance".  However, treat it separately
if it was created with a call to vkCreateDebugUtilsMessenger and that
allows it to capture info all the way until the instance is destroyed.

loader/debug_utils.c
loader/loader_common.h
loader/trampoline.c

index bdd6331778456f9927eb1b1d15403f51955c894d..471a8c774dfe5b5736fac083a3429d5eededfff7 100644 (file)
 
 VkResult util_CreateDebugUtilsMessenger(struct loader_instance *inst, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
                                         const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT messenger) {
-    VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
+    VkLayerDbgFunctionNode *new_dbg_function_node = NULL;
 
-    pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback(
+    new_dbg_function_node = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback(
         pAllocator, inst, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
 
-    if (!pNewDbgFuncNode) {
+    if (!new_dbg_function_node) {
         return VK_ERROR_OUT_OF_HOST_MEMORY;
     }
 
-    pNewDbgFuncNode->is_messenger = true;
-    pNewDbgFuncNode->messenger.messenger = messenger;
-    pNewDbgFuncNode->messenger.pfnUserCallback = pCreateInfo->pfnUserCallback;
-    pNewDbgFuncNode->messenger.messageSeverity = pCreateInfo->messageSeverity;
-    pNewDbgFuncNode->messenger.messageType = pCreateInfo->messageType;
-    pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
-    pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
-    inst->DbgFunctionHead = pNewDbgFuncNode;
+    new_dbg_function_node->is_messenger = true;
+    new_dbg_function_node->messenger.messenger = messenger;
+    new_dbg_function_node->messenger.pfnUserCallback = pCreateInfo->pfnUserCallback;
+    new_dbg_function_node->messenger.messageSeverity = pCreateInfo->messageSeverity;
+    new_dbg_function_node->messenger.messageType = pCreateInfo->messageType;
+    new_dbg_function_node->pUserData = pCreateInfo->pUserData;
+    new_dbg_function_node->pNext = inst->instance_only_dbg_function_head;
+    inst->instance_only_dbg_function_head = new_dbg_function_node;
+    inst->current_dbg_function_head = inst->instance_only_dbg_function_head;
 
     return VK_SUCCESS;
 }
@@ -82,7 +83,7 @@ VkBool32 util_SubmitDebugUtilsMessageEXT(const struct loader_instance *inst, VkD
     VkBool32 bail = false;
 
     if (NULL != pCallbackData) {
-        VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
+        VkLayerDbgFunctionNode *pTrav = inst->current_dbg_function_head;
         VkDebugReportObjectTypeEXT object_type = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;
         VkDebugReportFlagsEXT object_flags = 0;
         uint64_t object_handle = 0;
@@ -115,13 +116,15 @@ VkBool32 util_SubmitDebugUtilsMessageEXT(const struct loader_instance *inst, VkD
 
 void util_DestroyDebugUtilsMessenger(struct loader_instance *inst, VkDebugUtilsMessengerEXT messenger,
                                      const VkAllocationCallbacks *pAllocator) {
-    VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
+    VkLayerDbgFunctionNode *pTrav = inst->current_dbg_function_head;
     VkLayerDbgFunctionNode *pPrev = pTrav;
 
     while (pTrav) {
         if (pTrav->is_messenger && pTrav->messenger.messenger == messenger) {
             pPrev->pNext = pTrav->pNext;
-            if (inst->DbgFunctionHead == pTrav) inst->DbgFunctionHead = pTrav->pNext;
+            if (inst->current_dbg_function_head == pTrav) inst->current_dbg_function_head = pTrav->pNext;
+            if (inst->instance_only_dbg_function_head == pTrav) inst->instance_only_dbg_function_head = pTrav->pNext;
+            if (inst->standard_dbg_function_head == pTrav) inst->standard_dbg_function_head = pTrav->pNext;
             loader_free_with_instance_fallback(pAllocator, inst, pTrav);
             break;
         }
@@ -178,7 +181,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugUtilsMessengerEXT(VkInstanc
     struct loader_instance *inst = (struct loader_instance *)instance;
     VkResult res = VK_SUCCESS;
     uint32_t storage_idx;
-    VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
+    VkLayerDbgFunctionNode *new_dbg_func_node = NULL;
 
     icd_info = (VkDebugUtilsMessengerEXT *)loader_calloc_with_instance_fallback(
         pAllocator, inst, inst->total_icd_count * sizeof(VkDebugUtilsMessengerEXT), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
@@ -205,23 +208,24 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugUtilsMessengerEXT(VkInstanc
     // Setup the debug report callback in the terminator since a layer may want
     // to grab the information itself (RenderDoc) and then return back to the
     // user callback a sub-set of the messages.
-    pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback(
+    new_dbg_func_node = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback(
         pAllocator, inst, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
-    if (!pNewDbgFuncNode) {
+    if (!new_dbg_func_node) {
         res = VK_ERROR_OUT_OF_HOST_MEMORY;
         goto out;
     }
 
-    pNewDbgFuncNode->is_messenger = true;
-    pNewDbgFuncNode->messenger.pfnUserCallback = pCreateInfo->pfnUserCallback;
-    pNewDbgFuncNode->messenger.messageSeverity = pCreateInfo->messageSeverity;
-    pNewDbgFuncNode->messenger.messageType = pCreateInfo->messageType;
-    pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
-    pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
-    inst->DbgFunctionHead = pNewDbgFuncNode;
+    new_dbg_func_node->is_messenger = true;
+    new_dbg_func_node->messenger.pfnUserCallback = pCreateInfo->pfnUserCallback;
+    new_dbg_func_node->messenger.messageSeverity = pCreateInfo->messageSeverity;
+    new_dbg_func_node->messenger.messageType = pCreateInfo->messageType;
+    new_dbg_func_node->pUserData = pCreateInfo->pUserData;
+    new_dbg_func_node->pNext = inst->standard_dbg_function_head;
+    inst->standard_dbg_function_head = new_dbg_func_node;
+    inst->current_dbg_function_head = inst->standard_dbg_function_head;
 
     *(VkDebugUtilsMessengerEXT **)pMessenger = icd_info;
-    pNewDbgFuncNode->messenger.messenger = *pMessenger;
+    new_dbg_func_node->messenger.messenger = *pMessenger;
 
 out:
 
@@ -238,7 +242,7 @@ out:
             }
             storage_idx++;
         }
-        loader_free_with_instance_fallback(pAllocator, inst, pNewDbgFuncNode);
+        loader_free_with_instance_fallback(pAllocator, inst, new_dbg_func_node);
         loader_free_with_instance_fallback(pAllocator, inst, icd_info);
     }
 
@@ -290,21 +294,22 @@ VKAPI_ATTR void VKAPI_CALL terminator_SubmitDebugUtilsMessageEXT(VkInstance inst
 
 VkResult util_CreateDebugReportCallback(struct loader_instance *inst, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
                                         const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT callback) {
-    VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
+    VkLayerDbgFunctionNode *new_dbg_func_node = NULL;
 
-    pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback(
+    new_dbg_func_node = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback(
         pAllocator, inst, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
-    if (!pNewDbgFuncNode) {
+    if (!new_dbg_func_node) {
         return VK_ERROR_OUT_OF_HOST_MEMORY;
     }
 
-    pNewDbgFuncNode->is_messenger = false;
-    pNewDbgFuncNode->report.msgCallback = callback;
-    pNewDbgFuncNode->report.pfnMsgCallback = pCreateInfo->pfnCallback;
-    pNewDbgFuncNode->report.msgFlags = pCreateInfo->flags;
-    pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
-    pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
-    inst->DbgFunctionHead = pNewDbgFuncNode;
+    new_dbg_func_node->is_messenger = false;
+    new_dbg_func_node->report.msgCallback = callback;
+    new_dbg_func_node->report.pfnMsgCallback = pCreateInfo->pfnCallback;
+    new_dbg_func_node->report.msgFlags = pCreateInfo->flags;
+    new_dbg_func_node->pUserData = pCreateInfo->pUserData;
+    new_dbg_func_node->pNext = inst->instance_only_dbg_function_head;
+    inst->instance_only_dbg_function_head = new_dbg_func_node;
+    inst->current_dbg_function_head = inst->instance_only_dbg_function_head;
 
     return VK_SUCCESS;
 }
@@ -324,7 +329,7 @@ VKAPI_ATTR VkResult VKAPI_CALL debug_utils_CreateDebugReportCallbackEXT(VkInstan
 VkBool32 util_DebugReportMessage(const struct loader_instance *inst, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
                                  uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
     VkBool32 bail = false;
-    VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
+    VkLayerDbgFunctionNode *pTrav = inst->current_dbg_function_head;
     VkDebugUtilsMessageSeverityFlagBitsEXT severity;
     VkDebugUtilsMessageTypeFlagsEXT types;
     VkDebugUtilsMessengerCallbackDataEXT callback_data;
@@ -367,13 +372,15 @@ VkBool32 util_DebugReportMessage(const struct loader_instance *inst, VkFlags msg
 
 void util_DestroyDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackEXT callback,
                                      const VkAllocationCallbacks *pAllocator) {
-    VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
+    VkLayerDbgFunctionNode *pTrav = inst->current_dbg_function_head;
     VkLayerDbgFunctionNode *pPrev = pTrav;
 
     while (pTrav) {
         if (!pTrav->is_messenger && pTrav->report.msgCallback == callback) {
             pPrev->pNext = pTrav->pNext;
-            if (inst->DbgFunctionHead == pTrav) inst->DbgFunctionHead = pTrav->pNext;
+            if (inst->current_dbg_function_head == pTrav) inst->current_dbg_function_head = pTrav->pNext;
+            if (inst->instance_only_dbg_function_head == pTrav) inst->instance_only_dbg_function_head = pTrav->pNext;
+            if (inst->standard_dbg_function_head == pTrav) inst->standard_dbg_function_head = pTrav->pNext;
             loader_free_with_instance_fallback(pAllocator, inst, pTrav);
             break;
         }
@@ -431,7 +438,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallbackEXT(VkInstanc
     struct loader_instance *inst = (struct loader_instance *)instance;
     VkResult res = VK_SUCCESS;
     uint32_t storage_idx;
-    VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
+    VkLayerDbgFunctionNode *new_dbg_func_node = NULL;
 
     icd_info = ((VkDebugReportCallbackEXT *)loader_calloc_with_instance_fallback(
         pAllocator, inst, inst->total_icd_count * sizeof(VkDebugReportCallbackEXT), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
@@ -457,23 +464,24 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallbackEXT(VkInstanc
     // Setup the debug report callback in the terminator since a layer may want
     // to grab the information itself (RenderDoc) and then return back to the
     // user callback a sub-set of the messages.
-    pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback(
+    new_dbg_func_node = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback(
         pAllocator, inst, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
 
-    if (!pNewDbgFuncNode) {
+    if (!new_dbg_func_node) {
         res = VK_ERROR_OUT_OF_HOST_MEMORY;
         goto out;
     }
 
-    pNewDbgFuncNode->is_messenger = false;
-    pNewDbgFuncNode->report.pfnMsgCallback = pCreateInfo->pfnCallback;
-    pNewDbgFuncNode->report.msgFlags = pCreateInfo->flags;
-    pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
-    pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
-    inst->DbgFunctionHead = pNewDbgFuncNode;
+    new_dbg_func_node->is_messenger = false;
+    new_dbg_func_node->report.pfnMsgCallback = pCreateInfo->pfnCallback;
+    new_dbg_func_node->report.msgFlags = pCreateInfo->flags;
+    new_dbg_func_node->pUserData = pCreateInfo->pUserData;
+    new_dbg_func_node->pNext = inst->current_dbg_function_head;
+    inst->current_dbg_function_head = new_dbg_func_node;
+    inst->standard_dbg_function_head = inst->current_dbg_function_head;
 
     *(VkDebugReportCallbackEXT **)pCallback = icd_info;
-    pNewDbgFuncNode->report.msgCallback = *pCallback;
+    new_dbg_func_node->report.msgCallback = *pCallback;
 
 out:
 
@@ -490,7 +498,7 @@ out:
             }
             storage_idx++;
         }
-        loader_free_with_instance_fallback(pAllocator, inst, pNewDbgFuncNode);
+        loader_free_with_instance_fallback(pAllocator, inst, new_dbg_func_node);
         loader_free_with_instance_fallback(pAllocator, inst, icd_info);
     }
 
@@ -555,19 +563,19 @@ const VkExtensionProperties debug_utils_extension_info[] = {
 };
 
 void destroy_debug_callbacks_chain(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator) {
-    VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
+    VkLayerDbgFunctionNode *pTrav = inst->current_dbg_function_head;
     VkLayerDbgFunctionNode *pNext = NULL;
     while (pTrav) {
         pNext = pTrav->pNext;
         loader_free_with_instance_fallback(pAllocator, inst, pTrav);
         pTrav = pNext;
     }
-    inst->DbgFunctionHead = NULL;
+    inst->current_dbg_function_head = NULL;
 }
 
 VkResult add_debug_extensions_to_ext_list(const struct loader_instance *inst, struct loader_extension_list *ext_list) {
     return loader_add_to_ext_list(inst, ext_list, sizeof(debug_utils_extension_info) / sizeof(VkExtensionProperties),
-                           debug_utils_extension_info);
+                                  debug_utils_extension_info);
 }
 
 void check_for_enabled_debug_extensions(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) {
index 2ff67f863b8038ba93cca27b8b0909cbe7b2507b..028007ecf7e2c9844f9085fb86245a7bd26788e5 100644 (file)
@@ -307,13 +307,10 @@ struct loader_instance {
     struct loader_extension_list ext_list;  // icds and loaders extensions
     struct loader_instance_extension_enables enabled_known_extensions;
 
-    // Stores debug callbacks - used in the log
-    VkLayerDbgFunctionNode *DbgFunctionHead;
-
-    // Stores the debug callbacks set during instance creation
-    // These are kept separate because they aren't to be used outside of instance creation and destruction
-    // So they are swapped out at the end of instance creation and swapped in at instance destruction
-    VkLayerDbgFunctionNode *InstanceCreationDeletionDebugFunctionHead;
+    // Stores debug callbacks - used in the log.
+    VkLayerDbgFunctionNode *current_dbg_function_head;        // Current head
+    VkLayerDbgFunctionNode *instance_only_dbg_function_head;  // Only used for instance create/destroy
+    VkLayerDbgFunctionNode *standard_dbg_function_head;       // Always used until destroyed
 
     VkAllocationCallbacks alloc_callbacks;
 
index bcc55bf42579581254948ebc4acad80e56ba7e28..206203a54c290c8392e4110a42fe5e937746dc16 100644 (file)
@@ -484,6 +484,45 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceVersion(uint32_t
     return res;
 }
 
+// Add the "instance-only" debug functions to the list of active debug functions
+// at the very end.  This way it doesn't get replaced by any new messengers
+static void AddInstanceOnlyDebugFunctions(struct loader_instance *ptr_instance) {
+    VkLayerDbgFunctionNode *cur_node = ptr_instance->current_dbg_function_head;
+    if (cur_node == NULL) {
+        ptr_instance->current_dbg_function_head = ptr_instance->instance_only_dbg_function_head;
+    } else {
+        while (cur_node != NULL) {
+            if (cur_node == ptr_instance->instance_only_dbg_function_head) {
+                // Already added
+                break;
+            }
+            // Last item
+            else if (cur_node->pNext == NULL) {
+                cur_node->pNext = ptr_instance->instance_only_dbg_function_head;
+            }
+            cur_node = cur_node->pNext;
+        }
+    }
+}
+
+// Remove the "instance-only" debug functions from the list of active debug functions.
+// It should be added after the last actual debug utils/debug report function.
+static void RemoveInstanceOnlyDebugFunctions(struct loader_instance *ptr_instance) {
+    VkLayerDbgFunctionNode *cur_node = ptr_instance->current_dbg_function_head;
+
+    // Only thing in list is the instance only head
+    if (cur_node == ptr_instance->instance_only_dbg_function_head) {
+        ptr_instance->current_dbg_function_head = NULL;
+    }
+    while (cur_node != NULL) {
+        if (cur_node->pNext == ptr_instance->instance_only_dbg_function_head) {
+            cur_node->pNext = NULL;
+            break;
+        }
+        cur_node = cur_node->pNext;
+    }
+}
+
 LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo,
                                                               const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
     struct loader_instance *ptr_instance = NULL;
@@ -749,8 +788,7 @@ out:
             loader_instance_heap_free(ptr_instance, ptr_instance);
         } else {
             // success path, swap out created debug callbacks out so they aren't used until instance destruction
-            ptr_instance->InstanceCreationDeletionDebugFunctionHead = ptr_instance->DbgFunctionHead;
-            ptr_instance->DbgFunctionHead = NULL;
+            RemoveInstanceOnlyDebugFunctions(ptr_instance);
         }
         // Only unlock when ptr_instance isn't NULL, as if it is, the above code didn't make it to when loader_lock was locked.
         loader_platform_thread_unlock_mutex(&loader_lock);
@@ -784,8 +822,7 @@ LOADER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance,
     destroy_debug_callbacks_chain(ptr_instance, pAllocator);
 
     // Swap in the debug callbacks created during instance creation
-    ptr_instance->DbgFunctionHead = ptr_instance->InstanceCreationDeletionDebugFunctionHead;
-    ptr_instance->InstanceCreationDeletionDebugFunctionHead = NULL;
+    AddInstanceOnlyDebugFunctions(ptr_instance);
 
     disp = loader_get_instance_layer_dispatch(instance);
     disp->DestroyInstance(ptr_instance->instance, pAllocator);