Previously the loader would destroy any debug callbacks created during instance creation
to later create new ones during instance destruction. This required a memory allocation
to occur inside vkDestroyInstance, which can cause leaks if an OOM occurs during
instance destruction.
This commit simplifies the logic by keeping around the allocations made during instance
creation by moving them into their own debug node chain. Then during instance destruction
moves them back.
Also renames several functions to better describe their intended purpose.
#include "allocation.h"
#include "debug_utils.h"
+#include "log.h"
#include "loader.h"
#include "vk_loader_platform.h"
}
}
-// This utility (used by vkInstanceCreateInfo(), looks at a pNext chain. It
-// counts any VkDebugUtilsMessengerCreateInfoEXT structs that it finds. It
-// then allocates array that can hold that many structs, as well as that many
-// VkDebugUtilsMessengerEXT handles. It then copies each
-// VkDebugUtilsMessengerCreateInfoEXT, and initializes each handle.
-VkResult util_CopyDebugUtilsMessengerCreateInfos(const void *pChain, const VkAllocationCallbacks *pAllocator,
- uint32_t *num_messengers, VkDebugUtilsMessengerCreateInfoEXT **infos,
- VkDebugUtilsMessengerEXT **messengers) {
- uint32_t n = *num_messengers = 0;
- VkDebugUtilsMessengerCreateInfoEXT *pInfos = NULL;
- VkDebugUtilsMessengerEXT *pMessengers = NULL;
-
+VkResult util_CreateDebugUtilsMessengers(struct loader_instance *inst, const void *pChain,
+ const VkAllocationCallbacks *pAllocator) {
const void *pNext = pChain;
while (pNext) {
- // 1st, count the number VkDebugUtilsMessengerCreateInfoEXT:
- if (((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
- n++;
- }
- pNext = (void *)((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->pNext;
- }
- if (n == 0) {
- return VK_SUCCESS;
- }
-
- // 2nd, allocate memory for each VkDebugUtilsMessengerCreateInfoEXT:
- pInfos = *infos = ((VkDebugUtilsMessengerCreateInfoEXT *)loader_alloc(
- pAllocator, n * sizeof(VkDebugUtilsMessengerCreateInfoEXT), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
-
- if (!pInfos) {
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
- // 3rd, allocate memory for a unique handle for each callback:
- pMessengers = *messengers = ((VkDebugUtilsMessengerEXT *)loader_alloc(pAllocator, n * sizeof(VkDebugUtilsMessengerEXT),
- VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
- if (NULL == pMessengers) {
- loader_free(pAllocator, pInfos);
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
- // 4th, copy each VkDebugUtilsMessengerCreateInfoEXT for use by
- // vkDestroyInstance, and assign a unique handle to each messenger (just
- // use the address of the copied VkDebugUtilsMessengerCreateInfoEXT):
- pNext = pChain;
- while (pNext) {
- if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
- memcpy(pInfos, pNext, sizeof(VkDebugUtilsMessengerCreateInfoEXT));
- *pMessengers++ = (VkDebugUtilsMessengerEXT)(uintptr_t)pInfos++;
- }
- pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
- }
-
- *num_messengers = n;
- return VK_SUCCESS;
-}
-
-void util_FreeDebugUtilsMessengerCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerCreateInfoEXT *infos,
- VkDebugUtilsMessengerEXT *messengers) {
- loader_free(pAllocator, infos);
- loader_free(pAllocator, messengers);
-}
-
-VkResult util_CreateDebugUtilsMessengers(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
- uint32_t num_messengers, VkDebugUtilsMessengerCreateInfoEXT *infos,
- VkDebugUtilsMessengerEXT *messengers) {
- VkResult rtn = VK_SUCCESS;
- for (uint32_t i = 0; i < num_messengers; i++) {
- rtn = util_CreateDebugUtilsMessenger(inst, &infos[i], pAllocator, messengers[i]);
- if (rtn != VK_SUCCESS) {
- for (uint32_t j = 0; j < i; j++) {
- util_DestroyDebugUtilsMessenger(inst, messengers[j], pAllocator);
+ if (((const VkBaseInStructure *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
+ // Assign a unique handle to each messenger (just use the address of the VkDebugUtilsMessengerCreateInfoEXT)
+ // This is only being used this way due to it being for an 'anonymous' callback during instance creation
+ VkDebugUtilsMessengerEXT messenger_handle = (VkDebugUtilsMessengerEXT)(uintptr_t)pNext;
+ VkResult ret = util_CreateDebugUtilsMessenger(inst, (const VkDebugUtilsMessengerCreateInfoEXT *)pNext, pAllocator,
+ messenger_handle);
+ if (ret != VK_SUCCESS) {
+ return ret;
}
- return rtn;
}
+ pNext = (void *)((VkBaseInStructure *)pNext)->pNext;
}
- return rtn;
-}
-
-void util_DestroyDebugUtilsMessengers(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
- uint32_t num_messengers, VkDebugUtilsMessengerEXT *messengers) {
- for (uint32_t i = 0; i < num_messengers; i++) {
- util_DestroyDebugUtilsMessenger(inst, messengers[i], pAllocator);
- }
+ return VK_SUCCESS;
}
static VKAPI_ATTR void VKAPI_CALL debug_utils_SubmitDebugUtilsMessageEXT(
// VK_EXT_debug_report related items
-VkResult util_CreateDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
+VkResult util_CreateDebugReportCallback(struct loader_instance *inst, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT callback) {
VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
}
}
-// 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;
- VkDebugReportCallbackCreateInfoEXT *pInfos = NULL;
- VkDebugReportCallbackEXT *pCallbacks = NULL;
-
+VkResult util_CreateDebugReportCallbacks(struct loader_instance *inst, const void *pChain,
+ const VkAllocationCallbacks *pAllocator) {
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:
- pInfos = *infos = ((VkDebugReportCallbackCreateInfoEXT *)loader_alloc(
- pAllocator, n * sizeof(VkDebugReportCallbackCreateInfoEXT), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
- if (!pInfos) {
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
- // 3rd, allocate memory for a unique handle for each callback:
-
- pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)loader_alloc(pAllocator, n * sizeof(VkDebugReportCallbackEXT),
- VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
- if (!pCallbacks) {
- loader_free(pAllocator, 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)(uintptr_t)pInfos++;
- }
- pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
- }
-
- *num_callbacks = n;
- return VK_SUCCESS;
-}
-
-void util_FreeDebugReportCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackCreateInfoEXT *infos,
- VkDebugReportCallbackEXT *callbacks) {
- loader_free(pAllocator, infos);
- loader_free(pAllocator, callbacks);
-}
-
-VkResult util_CreateDebugReportCallbacks(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
- uint32_t num_callbacks, VkDebugReportCallbackCreateInfoEXT *infos,
- VkDebugReportCallbackEXT *callbacks) {
- VkResult rtn = VK_SUCCESS;
- 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);
+ if (((VkBaseInStructure *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
+ // Assign a unique handle to each callback (just use the address of the VkDebugReportCallbackCreateInfoEXT):
+ // This is only being used this way due to it being for an 'anonymous' callback during instance creation
+ VkDebugReportCallbackEXT report_handle = (VkDebugReportCallbackEXT)(uintptr_t)pNext;
+ VkResult ret =
+ util_CreateDebugReportCallback(inst, (const VkDebugReportCallbackCreateInfoEXT *)pNext, pAllocator, report_handle);
+ if (ret != VK_SUCCESS) {
+ return ret;
}
- return rtn;
}
+ pNext = (void *)((VkBaseInStructure *)pNext)->pNext;
}
- 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);
- }
+ return VK_SUCCESS;
}
static VKAPI_ATTR void VKAPI_CALL debug_utils_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
{VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION},
};
-void debug_utils_AddInstanceExtensions(const struct loader_instance *inst, struct loader_extension_list *ext_list) {
+void destroy_debug_callbacks_chain(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator) {
+ VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
+ VkLayerDbgFunctionNode *pNext = NULL;
+ while (pTrav) {
+ pNext = pTrav->pNext;
+ loader_free_with_instance_fallback(pAllocator, inst, pTrav);
+ pTrav = pNext;
+ }
+ inst->DbgFunctionHead = NULL;
+}
+
+void add_debug_extensions_to_ext_list(const struct loader_instance *inst, struct loader_extension_list *ext_list) {
loader_add_to_ext_list(inst, ext_list, sizeof(debug_utils_extension_info) / sizeof(VkExtensionProperties),
debug_utils_extension_info);
}
-void debug_utils_CreateInstance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) {
+void check_for_enabled_debug_extensions(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) {
for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
ptr_instance->enabled_known_extensions.ext_debug_report = 1;
}
}
-bool debug_utils_InstanceGpa(struct loader_instance *ptr_instance, const char *name, void **addr) {
+bool debug_extensions_InstanceGpa(struct loader_instance *ptr_instance, const char *name, void **addr) {
bool ret_type = false;
*addr = NULL;
// General utilities
-void debug_utils_AddInstanceExtensions(const struct loader_instance *inst, struct loader_extension_list *ext_list);
-void debug_utils_CreateInstance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo);
-bool debug_utils_InstanceGpa(struct loader_instance *ptr_instance, const char *name, void **addr);
+void add_debug_extensions_to_ext_list(const struct loader_instance *inst, struct loader_extension_list *ext_list);
+void check_for_enabled_debug_extensions(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo);
+bool debug_extensions_InstanceGpa(struct loader_instance *ptr_instance, const char *name, void **addr);
bool debug_utils_ReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec,
VkDebugUtilsMessageSeverityFlagBitsEXT *da_severity,
VkDebugUtilsMessageTypeFlagsEXT *da_type);
bool debug_utils_AnnotObjectToDebugReportObject(const VkDebugUtilsObjectNameInfoEXT *da_object_name_info,
VkDebugReportObjectTypeEXT *dr_object_type, uint64_t *dr_object_handle);
+void destroy_debug_callbacks_chain(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator);
+
// VK_EXT_debug_utils related items
VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugUtilsMessengerEXT(VkInstance instance,
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData);
-VkResult util_CreateDebugUtilsMessenger(struct loader_instance *inst, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
- const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT messenger);
-VkResult util_CreateDebugUtilsMessengers(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
- uint32_t num_messengers, VkDebugUtilsMessengerCreateInfoEXT *infos,
- VkDebugUtilsMessengerEXT *messengers);
+VkResult util_CreateDebugUtilsMessengers(struct loader_instance *inst, const void *pChain, const VkAllocationCallbacks *pAllocator);
VkBool32 util_SubmitDebugUtilsMessageEXT(const struct loader_instance *inst, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData);
-VkResult util_CopyDebugUtilsMessengerCreateInfos(const void *pChain, const VkAllocationCallbacks *pAllocator,
- uint32_t *num_messengers, VkDebugUtilsMessengerCreateInfoEXT **infos,
- VkDebugUtilsMessengerEXT **messengers);
-void util_DestroyDebugUtilsMessenger(struct loader_instance *inst, VkDebugUtilsMessengerEXT messenger,
- const VkAllocationCallbacks *pAllocator);
-void util_DestroyDebugUtilsMessengers(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
- uint32_t num_messengers, VkDebugUtilsMessengerEXT *messengers);
-void util_FreeDebugUtilsMessengerCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerCreateInfoEXT *infos,
- VkDebugUtilsMessengerEXT *messengers);
// VK_EXT_debug_report related items
VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
int32_t msgCode, const char *pLayerPrefix, const char *pMsg);
-VkResult util_CreateDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
- const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT callback);
-VkResult util_CreateDebugReportCallbacks(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
- uint32_t num_callbacks, VkDebugReportCallbackCreateInfoEXT *infos,
- VkDebugReportCallbackEXT *callbacks);
+VkResult util_CreateDebugReportCallbacks(struct loader_instance *inst, const void *pChain, const VkAllocationCallbacks *pAllocator);
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);
-VkResult util_CopyDebugReportCreateInfos(const void *pChain, const VkAllocationCallbacks *pAllocator, uint32_t *num_callbacks,
- VkDebugReportCallbackCreateInfoEXT **infos, VkDebugReportCallbackEXT **callbacks);
-void util_DestroyDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackEXT callback,
- const VkAllocationCallbacks *pAllocator);
-void util_DestroyDebugReportCallbacks(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator, uint32_t num_callbacks,
- VkDebugReportCallbackEXT *callbacks);
-void util_FreeDebugReportCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackCreateInfoEXT *infos,
- VkDebugReportCallbackEXT *callbacks);
// Instance extensions
void *addr;
- if (debug_utils_InstanceGpa(inst, funcName, &addr)) return addr;
+ if (debug_extensions_InstanceGpa(inst, funcName, &addr)) return addr;
if (wsi_swapchain_instance_gpa(inst, funcName, &addr)) return addr;
};
// Traverse loader's extensions, adding non-duplicate extensions to the list
- debug_utils_AddInstanceExtensions(inst, inst_exts);
+ add_debug_extensions_to_ext_list(inst, inst_exts);
static const VkExtensionProperties portability_enumeration_extension_info[] = {
{VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, VK_KHR_PORTABILITY_ENUMERATION_SPEC_VERSION}};
// The clearing should actually be handled by the overall memset of the pInstance structure in the
// trampoline.
wsi_create_instance(ptr_instance, pCreateInfo);
- debug_utils_CreateInstance(ptr_instance, pCreateInfo);
+ check_for_enabled_debug_extensions(ptr_instance, pCreateInfo);
extensions_create_instance(ptr_instance, pCreateInfo);
}
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;
- uint32_t num_tmp_report_callbacks;
- VkDebugReportCallbackCreateInfoEXT *tmp_report_create_infos;
- VkDebugReportCallbackEXT *tmp_report_callbacks;
- uint32_t num_tmp_messengers;
- VkDebugUtilsMessengerCreateInfoEXT *tmp_messenger_create_infos;
- VkDebugUtilsMessengerEXT *tmp_messengers;
+
+ // 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;
VkAllocationCallbacks alloc_callbacks;
struct loader_msg_callback_map_entry {
VkDebugReportCallbackEXT icd_obj;
VkDebugReportCallbackEXT loader_obj;
-};
\ No newline at end of file
+};
const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
struct loader_instance *ptr_instance = NULL;
VkInstance created_instance = VK_NULL_HANDLE;
- bool loaderLocked = false;
VkResult res = VK_ERROR_INITIALIZATION_FAILED;
LOADER_PLATFORM_THREAD_ONCE(&once_init, loader_initialize);
}
ptr_instance =
- (struct loader_instance *)loader_alloc(pAllocator, sizeof(struct loader_instance), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ (struct loader_instance *)loader_calloc(pAllocator, sizeof(struct loader_instance), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
VkInstanceCreateInfo ici = *pCreateInfo;
}
loader_platform_thread_lock_mutex(&loader_lock);
- loaderLocked = true;
- memset(ptr_instance, 0, sizeof(struct loader_instance));
if (pAllocator) {
ptr_instance->alloc_callbacks = *pAllocator;
}
ptr_instance->app_api_version.patch = 0;
}
- // Check the VkInstanceCreateInfoFlags wether to allow the portability enumeration flag
- if ((pCreateInfo->flags & VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR) == 1) {
- // Make sure the extension has been enabled
- for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
- if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0) {
- ptr_instance->portability_enumeration_enabled = true;
- loader_log(ptr_instance, VULKAN_LOADER_INFO_BIT, 0,
- "Portability enumeration bit was set, enumerating portability drivers.");
- }
- }
- }
-
// Look for one or more VK_EXT_debug_report or VK_EXT_debug_utils create info structures
// and setup a callback(s) for each one found.
- ptr_instance->num_tmp_report_callbacks = 0;
- ptr_instance->tmp_report_create_infos = NULL;
- ptr_instance->tmp_report_callbacks = NULL;
- ptr_instance->num_tmp_messengers = 0;
- ptr_instance->tmp_messenger_create_infos = NULL;
- ptr_instance->tmp_messengers = NULL;
// Handle cases of VK_EXT_debug_utils
- if (util_CopyDebugUtilsMessengerCreateInfos(pCreateInfo->pNext, pAllocator, &ptr_instance->num_tmp_messengers,
- &ptr_instance->tmp_messenger_create_infos, &ptr_instance->tmp_messengers)) {
- // One or more were found, but allocation failed. Therefore, clean up and fail this function:
- res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ // Setup the temporary messenger(s) here to catch early issues:
+ res = util_CreateDebugUtilsMessengers(ptr_instance, pCreateInfo->pNext, pAllocator);
+ if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
+ // Failure of setting up one or more of the messenger.
goto out;
- } else if (ptr_instance->num_tmp_messengers > 0) {
- // Setup the temporary messenger(s) here to catch early issues:
- if (util_CreateDebugUtilsMessengers(ptr_instance, pAllocator, ptr_instance->num_tmp_messengers,
- ptr_instance->tmp_messenger_create_infos, ptr_instance->tmp_messengers)) {
- // Failure of setting up one or more of the messenger. Therefore, clean up and fail this function:
- res = VK_ERROR_OUT_OF_HOST_MEMORY;
- goto out;
- }
}
// Handle cases of VK_EXT_debug_report
- if (util_CopyDebugReportCreateInfos(pCreateInfo->pNext, pAllocator, &ptr_instance->num_tmp_report_callbacks,
- &ptr_instance->tmp_report_create_infos, &ptr_instance->tmp_report_callbacks)) {
- // One or more were found, but allocation failed. Therefore, clean up and fail this function:
- res = VK_ERROR_OUT_OF_HOST_MEMORY;
+ // Setup the temporary callback(s) here to catch early issues:
+ res = util_CreateDebugReportCallbacks(ptr_instance, pCreateInfo->pNext, pAllocator);
+ if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
+ // Failure of setting up one or more of the callback.
goto out;
- } else if (ptr_instance->num_tmp_report_callbacks > 0) {
- // Setup the temporary callback(s) here to catch early issues:
- if (util_CreateDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_report_callbacks,
- ptr_instance->tmp_report_create_infos, ptr_instance->tmp_report_callbacks)) {
- // Failure of setting up one or more of the callback. Therefore, clean up and fail this function:
- res = VK_ERROR_OUT_OF_HOST_MEMORY;
- goto out;
+ }
+
+ // Check the VkInstanceCreateInfoFlags wether to allow the portability enumeration flag
+ if ((pCreateInfo->flags & VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR) == 1) {
+ // Make sure the extension has been enabled
+ for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
+ if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0) {
+ ptr_instance->portability_enumeration_enabled = true;
+ loader_log(ptr_instance, VULKAN_LOADER_INFO_BIT, 0,
+ "Portability enumeration bit was set, enumerating portability drivers.");
+ }
}
}
// This is why we don't clear inside of these function calls.
// The clearing should actually be handled by the overall memset of the pInstance structure above.
wsi_create_instance(ptr_instance, &ici);
- debug_utils_CreateInstance(ptr_instance, &ici);
+ check_for_enabled_debug_extensions(ptr_instance, &ici);
extensions_create_instance(ptr_instance, &ici);
*pInstance = (VkInstance)ptr_instance;
if (NULL != ptr_instance) {
if (res != VK_SUCCESS) {
+ // error path, should clean everything up
if (loader.instances == ptr_instance) {
loader.instances = ptr_instance->next;
}
if (NULL != ptr_instance->disp) {
loader_instance_heap_free(ptr_instance, ptr_instance->disp);
}
- if (ptr_instance->num_tmp_report_callbacks > 0) {
- // Remove temporary VK_EXT_debug_report items
- util_DestroyDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_report_callbacks,
- ptr_instance->tmp_report_callbacks);
- util_FreeDebugReportCreateInfos(pAllocator, ptr_instance->tmp_report_create_infos,
- ptr_instance->tmp_report_callbacks);
- }
- if (ptr_instance->num_tmp_messengers > 0) {
- // Remove temporary VK_EXT_debug_utils items
- util_DestroyDebugUtilsMessengers(ptr_instance, pAllocator, ptr_instance->num_tmp_messengers,
- ptr_instance->tmp_messengers);
- util_FreeDebugUtilsMessengerCreateInfos(pAllocator, ptr_instance->tmp_messenger_create_infos,
- ptr_instance->tmp_messengers);
- }
+ // Remove any created VK_EXT_debug_report or VK_EXT_debug_utils items
+ destroy_debug_callbacks_chain(ptr_instance, pAllocator);
if (NULL != ptr_instance->expanded_activated_layer_list.list) {
loader_deactivate_layers(ptr_instance, NULL, &ptr_instance->expanded_activated_layer_list);
loader_instance_heap_free(ptr_instance, ptr_instance);
} else {
- // Remove temporary VK_EXT_debug_report or VK_EXT_debug_utils items
- util_DestroyDebugUtilsMessengers(ptr_instance, pAllocator, ptr_instance->num_tmp_messengers,
- ptr_instance->tmp_messengers);
- util_DestroyDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_report_callbacks,
- ptr_instance->tmp_report_callbacks);
- }
-
- if (loaderLocked) {
- loader_platform_thread_unlock_mutex(&loader_lock);
+ // 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;
}
+ loader_platform_thread_unlock_mutex(&loader_lock);
}
return res;
LOADER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
const VkLayerInstanceDispatchTable *disp;
struct loader_instance *ptr_instance = NULL;
- bool callback_setup = false;
- bool messenger_setup = false;
if (instance == VK_NULL_HANDLE) {
return;
ptr_instance->alloc_callbacks = *pAllocator;
}
- if (ptr_instance->num_tmp_messengers > 0) {
- // Setup the temporary VK_EXT_debug_utils messenger(s) here to catch cleanup issues:
- if (!util_CreateDebugUtilsMessengers(ptr_instance, pAllocator, ptr_instance->num_tmp_messengers,
- ptr_instance->tmp_messenger_create_infos, ptr_instance->tmp_messengers)) {
- messenger_setup = true;
- }
- }
+ // Remove any callbacks that weren't cleaned up by the application
+ destroy_debug_callbacks_chain(ptr_instance, pAllocator);
- if (ptr_instance->num_tmp_report_callbacks > 0) {
- // Setup the temporary VK_EXT_debug_report callback(s) here to catch cleanup issues:
- if (!util_CreateDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_report_callbacks,
- ptr_instance->tmp_report_create_infos, ptr_instance->tmp_report_callbacks)) {
- callback_setup = true;
- }
- }
+ // Swap in the debug callbacks created during instance creation
+ ptr_instance->DbgFunctionHead = ptr_instance->InstanceCreationDeletionDebugFunctionHead;
+ ptr_instance->InstanceCreationDeletionDebugFunctionHead = NULL;
disp = loader_get_instance_layer_dispatch(instance);
disp->DestroyInstance(ptr_instance->instance, pAllocator);
loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_tramp);
}
- if (messenger_setup) {
- loader_log(ptr_instance, VULKAN_LOADER_INFO_BIT, 0,
- "vkDestroyInstance: destroying temporary instance debug util messenger");
-
- util_DestroyDebugUtilsMessengers(ptr_instance, pAllocator, ptr_instance->num_tmp_messengers, ptr_instance->tmp_messengers);
- util_FreeDebugUtilsMessengerCreateInfos(pAllocator, ptr_instance->tmp_messenger_create_infos, ptr_instance->tmp_messengers);
- }
-
- if (callback_setup) {
- loader_log(ptr_instance, VULKAN_LOADER_INFO_BIT, 0,
- "vkDestroyInstance: destroying temporary instance debug report callback");
-
- util_DestroyDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_report_callbacks,
- ptr_instance->tmp_report_callbacks);
- util_FreeDebugReportCreateInfos(pAllocator, ptr_instance->tmp_report_create_infos, ptr_instance->tmp_report_callbacks);
- }
+ // Destroy the debug callbacks created during instance creation
+ destroy_debug_callbacks_chain(ptr_instance, pAllocator);
loader_instance_heap_free(ptr_instance, ptr_instance->disp);
loader_instance_heap_free(ptr_instance, ptr_instance);
ASSERT_EQ(true, message_found);
}
-// Test report (error/warning) created in vkCreateInstance with info in vkDestroyInstance
-TEST_F(CreateDestroyInstanceReport, InfoInDestroyIgnored) {
- expected_message = "destroying temporary instance debug report callback";
- expected_object_type = VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT;
- expected_flag = VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
-
- VkInstance inst = VK_NULL_HANDLE;
- ASSERT_EQ(VK_SUCCESS, CreateReportInstance(VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT, &inst));
- env->vulkan_functions.vkDestroyInstance(inst, nullptr);
-
- // Should be not be found
- ASSERT_EQ(false, message_found);
-}
-
-// Test report (info) created in vkCreateInstance with info in vkDestroyInstance
-TEST_F(CreateDestroyInstanceReport, InfoInDestroy) {
- expected_message = "destroying temporary instance debug report callback";
- expected_object_type = VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT;
- expected_flag = VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
-
- VkInstance inst = VK_NULL_HANDLE;
- ASSERT_EQ(VK_SUCCESS, CreateReportInstance(VK_DEBUG_REPORT_INFORMATION_BIT_EXT, &inst));
- env->vulkan_functions.vkDestroyInstance(inst, nullptr);
-
- // Message should be found
- ASSERT_EQ(true, message_found);
-}
-
// Test report (error/warning) created in vkCreateInstance with error in vkEnumeratePhysicalDevices.
// This should not be logged because we have only defined the debug report logging for vkCreateInstance
// and vkDestroyInstance.
ASSERT_EQ(true, message_found);
}
-// Test debug utils error/warn created in vkCreateInstance with info in vkDestroyInstance
-TEST_F(CreateDestroyInstanceMessenger, DestroyInfoIgnoredSeverity) {
- expected_message = "destroying temporary instance debug util messenger";
- expected_object_type = VK_OBJECT_TYPE_INSTANCE;
- expected_message_flags = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
- expected_severity_flags = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
-
- VkApplicationInfo app_info;
- app_info.apiVersion = VK_MAKE_API_VERSION(1, 1, 0, 0);
-
- VkInstance inst = VK_NULL_HANDLE;
- ASSERT_EQ(VK_SUCCESS,
- CreateUtilsInstance(VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
- VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT,
- &inst, &app_info));
- env->vulkan_functions.vkDestroyInstance(inst, nullptr);
-
- ASSERT_EQ(false, message_found);
-}
-
-// Test debug utils info/performance created in vkCreateInstance with info/general in vkDestroyInstance
-TEST_F(CreateDestroyInstanceMessenger, DestroyInfoIgnoredType) {
- expected_message = "destroying temporary instance debug util messenger";
- expected_object_type = VK_OBJECT_TYPE_INSTANCE;
- expected_message_flags = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
- expected_severity_flags = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
-
- VkApplicationInfo app_info;
- app_info.apiVersion = VK_MAKE_API_VERSION(1, 1, 0, 0);
-
- VkInstance inst = VK_NULL_HANDLE;
- ASSERT_EQ(VK_SUCCESS, CreateUtilsInstance(VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
- VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, &inst, &app_info));
- env->vulkan_functions.vkDestroyInstance(inst, nullptr);
-
- ASSERT_EQ(false, message_found);
-}
-
-// Test debug utils info/general created in vkCreateInstance with info/general in vkDestroyInstance
-TEST_F(CreateDestroyInstanceMessenger, DestroyInfo) {
- expected_message = "destroying temporary instance debug util messenger";
- expected_object_type = VK_OBJECT_TYPE_INSTANCE;
- expected_message_flags = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
- expected_severity_flags = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
-
- VkApplicationInfo app_info;
- app_info.apiVersion = VK_MAKE_API_VERSION(1, 1, 0, 0);
-
- VkInstance inst = VK_NULL_HANDLE;
- ASSERT_EQ(VK_SUCCESS, CreateUtilsInstance(VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
- VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, &inst, &app_info));
- env->vulkan_functions.vkDestroyInstance(inst, nullptr);
-
- ASSERT_EQ(true, message_found);
-}
-
// Test debug utils error created in vkCreateInstance with error in vkEnumeratePhysicalDevices.
// This should not be logged because we have only defined the debug utils logging for vkCreateInstance
// and vkDestroyInstance.