From e6ae483aedfb9f0e64697d4df0ff53519dd19957 Mon Sep 17 00:00:00 2001 From: Ian Elliott Date: Thu, 31 Mar 2016 10:48:19 -0600 Subject: loader: vk{Create|Destroy}Instance can have multiple tmp callbacks During code review of the Android version of the temporary debug_report callbacks code, it was decided to allow an array of VkDebugReportCallbackCreateInfoEXT structs to be passed to vkCreateInstance(). This code implements that, using some new utility functions in order to help keep the code clean. --- loader/debug_report.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ loader/debug_report.h | 21 ++++++++++ loader/loader.h | 4 +- loader/trampoline.c | 111 ++++++++++++++++++++++++++++++++++---------------- 4 files changed, 208 insertions(+), 36 deletions(-) diff --git a/loader/debug_report.c b/loader/debug_report.c index 7da370ce..3f49aa8c 100644 --- a/loader/debug_report.c +++ b/loader/debug_report.c @@ -156,6 +156,114 @@ void util_DestroyDebugReportCallback(struct loader_instance *inst, } } +// This utility (used by vkInstanceCreateInfo(), looks at a pNext chain. It +// counts any VkDebugReportCallbackCreateInfoEXT structs that it finds. It +// then allocates array that can hold that many structs, as well as that many +// VkDebugReportCallbackEXT handles. It then copies each +// VkDebugReportCallbackCreateInfoEXT, and initializes each handle. +VkResult +util_CopyDebugReportCreateInfos(const void *pChain, + const VkAllocationCallbacks *pAllocator, + uint32_t *num_callbacks, + VkDebugReportCallbackCreateInfoEXT **infos, + VkDebugReportCallbackEXT **callbacks) +{ + uint32_t n = *num_callbacks = 0; + + // NOTE: The loader is not using pAllocator, and so this function doesn't + // either. + + const void *pNext = pChain; + while (pNext) { + // 1st, count the number VkDebugReportCallbackCreateInfoEXT: + if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == + VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) { + n++; + } + pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext; + } + if (n == 0) { + return VK_SUCCESS; + } + + // 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT: + VkDebugReportCallbackCreateInfoEXT *pInfos = + *infos = ((VkDebugReportCallbackCreateInfoEXT *) + malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT))); + if (!pInfos) { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + // 3rd, allocate memory for a unique handle for each callback: + VkDebugReportCallbackEXT *pCallbacks = + *callbacks = ((VkDebugReportCallbackEXT *) + malloc(n * sizeof(VkDebugReportCallbackEXT))); + if (!pCallbacks) { + free(pInfos); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by + // vkDestroyInstance, and assign a unique handle to each callback (just + // use the address of the copied VkDebugReportCallbackCreateInfoEXT): + pNext = pChain; + while (pNext) { + if (((VkInstanceCreateInfo *)pNext)->sType == + VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) { + memcpy(pInfos, pNext, + sizeof(VkDebugReportCallbackCreateInfoEXT)); + *pCallbacks++ = (VkDebugReportCallbackEXT)pInfos++; + } + pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext; + } + + *num_callbacks = n; + return VK_SUCCESS; +} + +void util_FreeDebugReportCreateInfos(const VkAllocationCallbacks *pAllocator, + VkDebugReportCallbackCreateInfoEXT *infos, + VkDebugReportCallbackEXT *callbacks) +{ + free(infos); + free(callbacks); +} + +VkResult +util_CreateDebugReportCallbacks(struct loader_instance *inst, + const VkAllocationCallbacks *pAllocator, + uint32_t num_callbacks, + VkDebugReportCallbackCreateInfoEXT *infos, + VkDebugReportCallbackEXT *callbacks) +{ + VkResult rtn; + for (uint32_t i = 0 ; i < num_callbacks ; i++) { + rtn = util_CreateDebugReportCallback(inst, + &infos[i], + pAllocator, + callbacks[i]); + if (rtn != VK_SUCCESS) { + for (uint32_t j = 0 ; j < i ; j++) { + util_DestroyDebugReportCallback(inst, + callbacks[j], + pAllocator); + } + return rtn; + } + } + return rtn; +} + +void util_DestroyDebugReportCallbacks(struct loader_instance *inst, + const VkAllocationCallbacks *pAllocator, + uint32_t num_callbacks, + VkDebugReportCallbackEXT *callbacks) +{ + for (uint32_t i = 0 ; i < num_callbacks ; i++) { + util_DestroyDebugReportCallback(inst, + callbacks[i], + pAllocator); + } +} + static VKAPI_ATTR void VKAPI_CALL debug_report_DestroyDebugReportCallback(VkInstance instance, VkDebugReportCallbackEXT callback, diff --git a/loader/debug_report.h b/loader/debug_report.h index baac021e..72a31e53 100644 --- a/loader/debug_report.h +++ b/loader/debug_report.h @@ -142,6 +142,27 @@ void util_DestroyDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks *pAllocator); +VkResult +util_CopyDebugReportCreateInfos(const void *pChain, + const VkAllocationCallbacks *pAllocator, + uint32_t *num_callbacks, + VkDebugReportCallbackCreateInfoEXT **infos, + VkDebugReportCallbackEXT **callbacks); +void util_FreeDebugReportCreateInfos(const VkAllocationCallbacks *pAllocator, + VkDebugReportCallbackCreateInfoEXT *infos, + VkDebugReportCallbackEXT *callbacks); +VkResult +util_CreateDebugReportCallbacks(struct loader_instance *inst, + const VkAllocationCallbacks *pAllocator, + uint32_t num_callbacks, + VkDebugReportCallbackCreateInfoEXT *infos, + VkDebugReportCallbackEXT *callbacks); + +void util_DestroyDebugReportCallbacks(struct loader_instance *inst, + const VkAllocationCallbacks *pAllocator, + uint32_t num_callbacks, + VkDebugReportCallbackEXT *callbacks); + VkBool32 util_DebugReportMessage(const struct loader_instance *inst, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType, diff --git a/loader/loader.h b/loader/loader.h index 244066c0..8a0d4cc8 100644 --- a/loader/loader.h +++ b/loader/loader.h @@ -293,7 +293,9 @@ struct loader_instance { bool debug_report_enabled; VkLayerDbgFunctionNode *DbgFunctionHead; - VkDebugReportCallbackCreateInfoEXT debugReportCreateInfo; + uint32_t num_tmp_callbacks; + VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos; + VkDebugReportCallbackEXT *tmp_callbacks; VkAllocationCallbacks alloc_callbacks; diff --git a/loader/trampoline.c b/loader/trampoline.c index 9c9a879c..260fd340 100644 --- a/loader/trampoline.c +++ b/loader/trampoline.c @@ -242,8 +242,6 @@ vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, struct loader_instance *ptr_instance = NULL; VkInstance created_instance = VK_NULL_HANDLE; VkResult res = VK_ERROR_INITIALIZATION_FAILED; - VkDebugReportCallbackEXT instance_callback = VK_NULL_HANDLE; - void *pNext = (void *)pCreateInfo->pNext; loader_platform_thread_once(&once_init, loader_initialize); @@ -273,26 +271,38 @@ vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, #endif /* - * Look for a debug report create info structure - * and setup a callback if found. + * Look for one or more debug report create info structures + * and setup a callback(s) for each one found. */ - while (pNext) { - if (((VkInstanceCreateInfo *)pNext)->sType == - VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) { - // Use this pNext so that vkCreateInstance has a callback that can - // be used to log messages. Make a copy for use by - // vkDestroyInstance as well. - memcpy(&ptr_instance->debugReportCreateInfo, pNext, - sizeof(VkDebugReportCallbackCreateInfoEXT)); - instance_callback = (VkDebugReportCallbackEXT)ptr_instance; - if (util_CreateDebugReportCallback(ptr_instance, pNext, NULL, - instance_callback)) { - loader_heap_free(ptr_instance, ptr_instance); - loader_platform_thread_unlock_mutex(&loader_lock); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } + ptr_instance->num_tmp_callbacks = 0; + ptr_instance->tmp_dbg_create_infos = NULL; + ptr_instance->tmp_callbacks = NULL; + if (util_CopyDebugReportCreateInfos(pCreateInfo->pNext, + pAllocator, + &ptr_instance->num_tmp_callbacks, + &ptr_instance->tmp_dbg_create_infos, + &ptr_instance->tmp_callbacks)) { + // One or more were found, but allocation failed. Therefore, clean up + // and fail this function: + loader_heap_free(ptr_instance, ptr_instance); + loader_platform_thread_unlock_mutex(&loader_lock); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } else if (ptr_instance->num_tmp_callbacks > 0) { + // Setup the temporary callback(s) here to catch early issues: + if (util_CreateDebugReportCallbacks(ptr_instance, + pAllocator, + ptr_instance->num_tmp_callbacks, + ptr_instance->tmp_dbg_create_infos, + ptr_instance->tmp_callbacks)) { + // Failure of setting up one or more of the callback. Therefore, + // clean up and fail this function: + util_FreeDebugReportCreateInfos(pAllocator, + ptr_instance->tmp_dbg_create_infos, + ptr_instance->tmp_callbacks); + loader_heap_free(ptr_instance, ptr_instance); + loader_platform_thread_unlock_mutex(&loader_lock); + return VK_ERROR_OUT_OF_HOST_MEMORY; } - pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext; } /* Due to implicit layers need to get layer list even if @@ -312,8 +322,13 @@ vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, pCreateInfo->ppEnabledLayerNames, &ptr_instance->instance_layer_list); if (res != VK_SUCCESS) { - util_DestroyDebugReportCallback(ptr_instance, instance_callback, - NULL); + util_DestroyDebugReportCallbacks(ptr_instance, + pAllocator, + ptr_instance->num_tmp_callbacks, + ptr_instance->tmp_callbacks); + util_FreeDebugReportCreateInfos(pAllocator, + ptr_instance->tmp_dbg_create_infos, + ptr_instance->tmp_callbacks); loader_heap_free(ptr_instance, ptr_instance); loader_platform_thread_unlock_mutex(&loader_lock); return res; @@ -359,7 +374,13 @@ vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, loader_destroy_generic_list( ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list); - util_DestroyDebugReportCallback(ptr_instance, instance_callback, NULL); + util_DestroyDebugReportCallbacks(ptr_instance, + pAllocator, + ptr_instance->num_tmp_callbacks, + ptr_instance->tmp_callbacks); + util_FreeDebugReportCreateInfos(pAllocator, + ptr_instance->tmp_dbg_create_infos, + ptr_instance->tmp_callbacks); loader_platform_thread_unlock_mutex(&loader_lock); loader_heap_free(ptr_instance, ptr_instance); return res; @@ -380,7 +401,13 @@ vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, loader_destroy_generic_list( ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list); - util_DestroyDebugReportCallback(ptr_instance, instance_callback, NULL); + util_DestroyDebugReportCallbacks(ptr_instance, + pAllocator, + ptr_instance->num_tmp_callbacks, + ptr_instance->tmp_callbacks); + util_FreeDebugReportCreateInfos(pAllocator, + ptr_instance->tmp_dbg_create_infos, + ptr_instance->tmp_callbacks); loader_platform_thread_unlock_mutex(&loader_lock); loader_heap_free(ptr_instance, ptr_instance); return VK_ERROR_OUT_OF_HOST_MEMORY; @@ -405,7 +432,13 @@ vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list); loader.instances = ptr_instance->next; - util_DestroyDebugReportCallback(ptr_instance, instance_callback, NULL); + util_DestroyDebugReportCallbacks(ptr_instance, + pAllocator, + ptr_instance->num_tmp_callbacks, + ptr_instance->tmp_callbacks); + util_FreeDebugReportCreateInfos(pAllocator, + ptr_instance->tmp_dbg_create_infos, + ptr_instance->tmp_callbacks); loader_platform_thread_unlock_mutex(&loader_lock); loader_heap_free(ptr_instance, ptr_instance->disp); loader_heap_free(ptr_instance, ptr_instance); @@ -434,7 +467,10 @@ vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, } /* Remove temporary debug_report callback */ - util_DestroyDebugReportCallback(ptr_instance, instance_callback, NULL); + util_DestroyDebugReportCallbacks(ptr_instance, + pAllocator, + ptr_instance->num_tmp_callbacks, + ptr_instance->tmp_callbacks); loader_unexpand_inst_layer_names(ptr_instance, saved_layer_count, saved_layer_names, saved_layer_ptr, pCreateInfo); @@ -447,7 +483,6 @@ vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) { const VkLayerInstanceDispatchTable *disp; struct loader_instance *ptr_instance = NULL; - VkDebugReportCallbackEXT instance_callback = VK_NULL_HANDLE; bool callback_setup = false; disp = loader_get_instance_dispatch(instance); @@ -456,13 +491,13 @@ vkDestroyInstance(VkInstance instance, ptr_instance = loader_get_instance(instance); - if (ptr_instance->debugReportCreateInfo.sType == - VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) { - // Setup a temporary callback here to catch cleanup issues: - instance_callback = (VkDebugReportCallbackEXT)ptr_instance; - if (!util_CreateDebugReportCallback(ptr_instance, - &ptr_instance->debugReportCreateInfo, - NULL, instance_callback)) { + if (ptr_instance->num_tmp_callbacks > 0) { + // Setup the temporary callback(s) here to catch cleanup issues: + if (!util_CreateDebugReportCallbacks(ptr_instance, + pAllocator, + ptr_instance->num_tmp_callbacks, + ptr_instance->tmp_dbg_create_infos, + ptr_instance->tmp_callbacks)) { callback_setup = true; } } @@ -473,7 +508,13 @@ vkDestroyInstance(VkInstance instance, if (ptr_instance->phys_devs) loader_heap_free(ptr_instance, ptr_instance->phys_devs); if (callback_setup) { - util_DestroyDebugReportCallback(ptr_instance, instance_callback, NULL); + util_DestroyDebugReportCallbacks(ptr_instance, + pAllocator, + ptr_instance->num_tmp_callbacks, + ptr_instance->tmp_callbacks); + util_FreeDebugReportCreateInfos(pAllocator, + ptr_instance->tmp_dbg_create_infos, + ptr_instance->tmp_callbacks); } loader_heap_free(ptr_instance, ptr_instance->disp); loader_heap_free(ptr_instance, ptr_instance); -- cgit v1.2.3