diff options
| author | Mark Young <marky@lunarg.com> | 2017-11-09 10:37:04 -0700 |
|---|---|---|
| committer | Mike Schuchardt <mikes@lunarg.com> | 2018-03-09 13:54:31 -0700 |
| commit | 4df1d6e03c91637d89d70339674deaece0d7641e (patch) | |
| tree | 274058c2d30cad6b10da6fe6e994da3f22521750 /loader | |
| parent | 9a6be7a671252c15a6b632568cc3f05631f8ef6f (diff) | |
| download | usermoji-4df1d6e03c91637d89d70339674deaece0d7641e.tar.xz | |
Implement initial VK_EXT_debug_utils changes
This affects the loader, scripts, and layers and introduces the
changes to support the VK_EXT_debug_utils extension.
Change-Id: Ia5336f63e85b00f1e59416c06aacd4ae331fd692
Diffstat (limited to 'loader')
| -rw-r--r-- | loader/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | loader/debug_report.c | 466 | ||||
| -rw-r--r-- | loader/debug_report.h | 138 | ||||
| -rw-r--r-- | loader/debug_utils.c | 1004 | ||||
| -rw-r--r-- | loader/debug_utils.h | 101 | ||||
| -rw-r--r-- | loader/extension_manual.c | 2 | ||||
| -rw-r--r-- | loader/gpa_helper.h | 4 | ||||
| -rw-r--r-- | loader/loader.c | 46 | ||||
| -rw-r--r-- | loader/loader.h | 9 | ||||
| -rw-r--r-- | loader/trampoline.c | 101 | ||||
| -rw-r--r-- | loader/vk_loader_layer.h | 19 |
11 files changed, 1248 insertions, 646 deletions
diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index 2f96665a..f543f861 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -75,8 +75,8 @@ set(NORMAL_LOADER_SRCS trampoline.c wsi.c wsi.h - debug_report.c - debug_report.h + debug_utils.c + debug_utils.h gpa_helper.h cJSON.c cJSON.h diff --git a/loader/debug_report.c b/loader/debug_report.c deleted file mode 100644 index 04e55ccf..00000000 --- a/loader/debug_report.c +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright (c) 2015-2016 The Khronos Group Inc. - * Copyright (c) 2015-2016 Valve Corporation - * Copyright (c) 2015-2016 LunarG, Inc. - * Copyright (C) 2015-2016 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> - * Author: Jon Ashburn <jon@LunarG.com> - * - */ - -#define _GNU_SOURCE -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <inttypes.h> -#ifndef WIN32 -#include <signal.h> -#else -#endif -#include "vk_loader_platform.h" -#include "debug_report.h" -#include "vulkan/vk_layer.h" - -typedef void(VKAPI_PTR *PFN_stringCallback)(char *message); - -static const VkExtensionProperties debug_report_extension_info = { - .extensionName = VK_EXT_DEBUG_REPORT_EXTENSION_NAME, .specVersion = VK_EXT_DEBUG_REPORT_SPEC_VERSION, -}; - -void debug_report_add_instance_extensions(const struct loader_instance *inst, struct loader_extension_list *ext_list) { - loader_add_to_ext_list(inst, ext_list, 1, &debug_report_extension_info); -} - -void debug_report_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) { - ptr_instance->enabled_known_extensions.ext_debug_report = 0; - - 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; - return; - } - } -} - -VkResult util_CreateDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackCreateInfoEXT *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT callback) { - VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL; - -#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) - { -#else - if (pAllocator != NULL) { - pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode), - sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); - } else { -#endif - pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode), - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); - } - if (!pNewDbgFuncNode) { - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode)); - - pNewDbgFuncNode->msgCallback = callback; - pNewDbgFuncNode->pfnMsgCallback = pCreateInfo->pfnCallback; - pNewDbgFuncNode->msgFlags = pCreateInfo->flags; - pNewDbgFuncNode->pUserData = pCreateInfo->pUserData; - pNewDbgFuncNode->pNext = inst->DbgFunctionHead; - inst->DbgFunctionHead = pNewDbgFuncNode; - - return VK_SUCCESS; -} - -static VKAPI_ATTR VkResult VKAPI_CALL -debug_report_CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback) { - struct loader_instance *inst = loader_get_instance(instance); - loader_platform_thread_lock_mutex(&loader_lock); - VkResult result = inst->disp->layer_inst_disp.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback); - loader_platform_thread_unlock_mutex(&loader_lock); - return result; -} - -// Utility function to handle reporting -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; - while (pTrav) { - if (pTrav->msgFlags & msgFlags) { - if (pTrav->pfnMsgCallback(msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, pMsg, pTrav->pUserData)) { - bail = true; - } - } - pTrav = pTrav->pNext; - } - - return bail; -} - -void util_DestroyDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackEXT callback, - const VkAllocationCallbacks *pAllocator) { - VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead; - VkLayerDbgFunctionNode *pPrev = pTrav; - - while (pTrav) { - if (pTrav->msgCallback == callback) { - pPrev->pNext = pTrav->pNext; - if (inst->DbgFunctionHead == pTrav) inst->DbgFunctionHead = pTrav->pNext; -#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) - { -#else - if (pAllocator != NULL) { - pAllocator->pfnFree(pAllocator->pUserData, pTrav); - } else { -#endif - loader_instance_heap_free(inst, pTrav); - } - break; - } - pPrev = pTrav; - pTrav = pTrav->pNext; - } -} - -// 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; - - // 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: -#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) - { -#else - if (pAllocator != NULL) { - pInfos = *infos = ((VkDebugReportCallbackCreateInfoEXT *)pAllocator->pfnAllocation( - pAllocator->pUserData, n * sizeof(VkDebugReportCallbackCreateInfoEXT), sizeof(void *), - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); - } else { -#endif - 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: -#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) - { -#else - if (pAllocator != NULL) { - pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)pAllocator->pfnAllocation( - pAllocator->pUserData, n * sizeof(VkDebugReportCallbackEXT), sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); - if (!pCallbacks) { - pAllocator->pfnFree(pAllocator->pUserData, pInfos); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - } else { -#endif - 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)(uintptr_t)pInfos++; - } - pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext; - } - - *num_callbacks = n; - return VK_SUCCESS; -} - -void util_FreeDebugReportCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackCreateInfoEXT *infos, - VkDebugReportCallbackEXT *callbacks) { -#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) - { -#else - if (pAllocator != NULL) { - pAllocator->pfnFree(pAllocator->pUserData, infos); - pAllocator->pfnFree(pAllocator->pUserData, callbacks); - } else { -#endif - free(infos); - free(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); - } - 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_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, - const VkAllocationCallbacks *pAllocator) { - struct loader_instance *inst = loader_get_instance(instance); - loader_platform_thread_lock_mutex(&loader_lock); - - inst->disp->layer_inst_disp.DestroyDebugReportCallbackEXT(instance, callback, pAllocator); - - util_DestroyDebugReportCallback(inst, callback, pAllocator); - - loader_platform_thread_unlock_mutex(&loader_lock); -} - -static VKAPI_ATTR void VKAPI_CALL debug_report_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objType, uint64_t object, - size_t location, int32_t msgCode, const char *pLayerPrefix, - const char *pMsg) { - struct loader_instance *inst = loader_get_instance(instance); - - inst->disp->layer_inst_disp.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg); -} - -// This is the instance chain terminator function -// for CreateDebugReportCallback -VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallbackEXT(VkInstance instance, - const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkDebugReportCallbackEXT *pCallback) { - VkDebugReportCallbackEXT *icd_info = NULL; - const struct loader_icd_term *icd_term; - struct loader_instance *inst = (struct loader_instance *)instance; - VkResult res = VK_SUCCESS; - uint32_t storage_idx; - VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL; - -#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) - { -#else - if (pAllocator != NULL) { - icd_info = ((VkDebugReportCallbackEXT *)pAllocator->pfnAllocation(pAllocator->pUserData, - inst->total_icd_count * sizeof(VkDebugReportCallbackEXT), - sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); - if (icd_info) { - memset(icd_info, 0, inst->total_icd_count * sizeof(VkDebugReportCallbackEXT)); - } - } else { -#endif - icd_info = calloc(sizeof(VkDebugReportCallbackEXT), inst->total_icd_count); - } - if (!icd_info) { - res = VK_ERROR_OUT_OF_HOST_MEMORY; - goto out; - } - - storage_idx = 0; - for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { - if (!icd_term->dispatch.CreateDebugReportCallbackEXT) { - continue; - } - - res = icd_term->dispatch.CreateDebugReportCallbackEXT(icd_term->instance, pCreateInfo, pAllocator, &icd_info[storage_idx]); - - if (res != VK_SUCCESS) { - goto out; - } - storage_idx++; - } - -// 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. -#if (DEBUG_DISABLE_APP_ALLOCATORS == 0) - if (pAllocator != NULL) { - pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode), - sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); - } else { -#else - { -#endif - pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode), - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); - } - if (!pNewDbgFuncNode) { - res = VK_ERROR_OUT_OF_HOST_MEMORY; - goto out; - } - memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode)); - - pNewDbgFuncNode->pfnMsgCallback = pCreateInfo->pfnCallback; - pNewDbgFuncNode->msgFlags = pCreateInfo->flags; - pNewDbgFuncNode->pUserData = pCreateInfo->pUserData; - pNewDbgFuncNode->pNext = inst->DbgFunctionHead; - inst->DbgFunctionHead = pNewDbgFuncNode; - - *(VkDebugReportCallbackEXT **)pCallback = icd_info; - pNewDbgFuncNode->msgCallback = *pCallback; - -out: - - // Roll back on errors - if (VK_SUCCESS != res) { - storage_idx = 0; - for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { - if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) { - continue; - } - - if (icd_info && icd_info[storage_idx]) { - icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator); - } - storage_idx++; - } - -#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) - { -#else - if (pAllocator != NULL) { - if (NULL != pNewDbgFuncNode) { - pAllocator->pfnFree(pAllocator->pUserData, pNewDbgFuncNode); - } - if (NULL != icd_info) { - pAllocator->pfnFree(pAllocator->pUserData, icd_info); - } - } else { -#endif - if (NULL != pNewDbgFuncNode) { - free(pNewDbgFuncNode); - } - if (NULL != icd_info) { - free(icd_info); - } - } - } - - return res; -} - -// This is the instance chain terminator function for DestroyDebugReportCallback -VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, - const VkAllocationCallbacks *pAllocator) { - uint32_t storage_idx; - VkDebugReportCallbackEXT *icd_info; - const struct loader_icd_term *icd_term; - - struct loader_instance *inst = (struct loader_instance *)instance; - icd_info = *(VkDebugReportCallbackEXT **)&callback; - storage_idx = 0; - for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { - if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) { - continue; - } - - if (icd_info[storage_idx]) { - icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator); - } - storage_idx++; - } - -#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) - { -#else - if (pAllocator != NULL) { - pAllocator->pfnFree(pAllocator->pUserData, icd_info); - } else { -#endif - free(icd_info); - } -} - -// This is the instance chain terminator function for DebugReportMessage -VKAPI_ATTR void VKAPI_CALL terminator_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location, - int32_t msgCode, const char *pLayerPrefix, const char *pMsg) { - const struct loader_icd_term *icd_term; - - struct loader_instance *inst = (struct loader_instance *)instance; - - loader_platform_thread_lock_mutex(&loader_lock); - for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { - if (icd_term->dispatch.DebugReportMessageEXT != NULL) { - icd_term->dispatch.DebugReportMessageEXT(icd_term->instance, flags, objType, object, location, msgCode, pLayerPrefix, - pMsg); - } - } - - // Now that all ICDs have seen the message, call the necessary callbacks. Ignoring "bail" return value - // as there is nothing to bail from at this point. - - util_DebugReportMessage(inst, flags, objType, object, location, msgCode, pLayerPrefix, pMsg); - - loader_platform_thread_unlock_mutex(&loader_lock); -} - -bool debug_report_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr) { - // debug_report is currently advertised to be supported by the loader, - // so always return the entry points if name matches and it's enabled - *addr = NULL; - - if (!strcmp("vkCreateDebugReportCallbackEXT", name)) { - *addr = (ptr_instance->enabled_known_extensions.ext_debug_report == 1) ? (void *)debug_report_CreateDebugReportCallbackEXT - : NULL; - return true; - } - if (!strcmp("vkDestroyDebugReportCallbackEXT", name)) { - *addr = (ptr_instance->enabled_known_extensions.ext_debug_report == 1) ? (void *)debug_report_DestroyDebugReportCallbackEXT - : NULL; - return true; - } - if (!strcmp("vkDebugReportMessageEXT", name)) { - *addr = (ptr_instance->enabled_known_extensions.ext_debug_report == 1) ? (void *)debug_report_DebugReportMessageEXT : NULL; - return true; - } - return false; -} diff --git a/loader/debug_report.h b/loader/debug_report.h deleted file mode 100644 index 89074d7f..00000000 --- a/loader/debug_report.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2015-2016 The Khronos Group Inc. - * Copyright (c) 2015-2016 Valve Corporation - * Copyright (c) 2015-2016 LunarG, Inc. - * Copyright (C) 2015-2016 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> - * Author: Jon Ashburn <jon@lunarg.com> - * - */ - -#include "vk_loader_platform.h" -#include "loader.h" - -// CreateMsgCallback is global and needs to be -// applied to all layers and ICDs. -// What happens if a layer is enabled on both the instance chain -// as well as the device chain and a call to CreateMsgCallback is made? -// Do we need to make sure that each layer / driver only gets called once? -// Should a layer implementing support for CreateMsgCallback only be allowed (?) -// to live on one chain? Or maybe make it the application's responsibility. -// If the app enables DRAW_STATE on at both CreateInstance time and CreateDevice -// time, CreateMsgCallback will call the DRAW_STATE layer twice. Once via -// the instance chain and once via the device chain. -// The loader should only return the DEBUG_REPORT extension as supported -// for the GetGlobalExtensionSupport call. That should help eliminate one -// duplication. -// Since the instance chain requires us iterating over the available ICDs -// and each ICD will have it's own unique MsgCallback object we need to -// track those objects to give back the right one. -// This also implies that the loader has to intercept vkDestroyObject and -// if the extension is enabled and the object type is a MsgCallback then -// we must translate the object into the proper ICD specific ones. -// DestroyObject works on a device chain. Should not be what's destroying -// the MsgCallback object. That needs to be an instance thing. So, since -// we used an instance to create it, we need a custom Destroy that also -// takes an instance. That way we can iterate over the ICDs properly. -// Example use: -// CreateInstance: DEBUG_REPORT -// Loader will create instance chain with enabled extensions. -// TODO: Should validation layers be enabled here? If not, they will not be in -// the instance chain. -// fn = GetProcAddr(INSTANCE, "vkCreateMsgCallback") -> point to loader's -// vkCreateMsgCallback -// App creates a callback object: fn(..., &MsgCallbackObject1) -// Have only established the instance chain so far. Loader will call the -// instance chain. -// Each layer in the instance chain will call down to the next layer, -// terminating with -// the CreateMsgCallback loader terminator function that creates the actual -// MsgCallbackObject1 object. -// The loader CreateMsgCallback terminator will iterate over the ICDs. -// Calling each ICD that supports vkCreateMsgCallback and collect answers in -// icd_msg_callback_map here. -// As result is sent back up the chain each layer has opportunity to record the -// callback operation and -// appropriate MsgCallback object. -// ... -// Any reports matching the flags set in MsgCallbackObject1 will generate the -// defined callback behavior -// in the layer / ICD that initiated that report. -// ... -// CreateDevice: MemTracker:... -// App does not include DEBUG_REPORT as that is a global extension. -// TODO: GetExtensionSupport must not report DEBUG_REPORT when using instance. -// App MUST include any desired validation layers or they will not participate -// in the device call chain. -// App creates a callback object: fn(..., &MsgCallbackObject2) -// Loader's vkCreateMsgCallback is called. -// Loader sends call down instance chain - this is a global extension - any -// validation layer that was -// enabled at CreateInstance will be able to register the callback. Loader will -// iterate over the ICDs and -// will record the ICD's version of the MsgCallback2 object here. -// ... -// Any report will go to the layer's report function and it will check the flags -// for MsgCallbackObject1 -// and MsgCallbackObject2 and take the appropriate action as indicated by the -// app. -// ... -// App calls vkDestroyMsgCallback( MsgCallbackObject1 ) -// Loader's DestroyMsgCallback is where call starts. DestroyMsgCallback will be -// sent down instance chain -// ending in the loader's DestroyMsgCallback terminator which will iterate over -// the ICD's destroying each -// ICD version of that MsgCallback object and then destroy the loader's version -// of the object. -// Any reports generated after this will only have MsgCallbackObject2 available. - -void debug_report_add_instance_extensions(const struct loader_instance *inst, struct loader_extension_list *ext_list); - -void debug_report_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo); - -bool debug_report_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr); - -VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallbackEXT(VkInstance instance, - const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkDebugReportCallbackEXT *pCallback); - -VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, - const VkAllocationCallbacks *pAllocator); - -VKAPI_ATTR void VKAPI_CALL terminator_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, - 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); - -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, - uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg); diff --git a/loader/debug_utils.c b/loader/debug_utils.c new file mode 100644 index 00000000..36891319 --- /dev/null +++ b/loader/debug_utils.c @@ -0,0 +1,1004 @@ +/* + * Copyright (c) 2015-2017 The Khronos Group Inc. + * Copyright (c) 2015-2017 Valve Corporation + * Copyright (c) 2015-2017 LunarG, Inc. + * Copyright (C) 2015-2016 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> + * Author: Jon Ashburn <jon@LunarG.com> + * Author: Mark Young <marky@lunarg.com> + * + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <inttypes.h> +#ifndef WIN32 +#include <signal.h> +#else +#endif +#include "vk_loader_platform.h" +#include "debug_utils.h" +#include "vulkan/vk_layer.h" +#include "vk_object_types.h" + +// VK_EXT_debug_report related items + +VkResult util_CreateDebugUtilsMessenger(struct loader_instance *inst, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT messenger) { + VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL; + +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode), + sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + } else { +#endif + pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode), + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + } + if (!pNewDbgFuncNode) { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode)); + + 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; + + return VK_SUCCESS; +} + +static VKAPI_ATTR VkResult VKAPI_CALL +debug_utils_CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pMessenger) { + struct loader_instance *inst = loader_get_instance(instance); + loader_platform_thread_lock_mutex(&loader_lock); + VkResult result = inst->disp->layer_inst_disp.CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger); + loader_platform_thread_unlock_mutex(&loader_lock); + return result; +} + +VkBool32 util_SubmitDebugUtilsMessageEXT(const struct loader_instance *inst, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) { + VkBool32 bail = false; + + if (NULL != pCallbackData && NULL != pCallbackData->pObjects && 0 < pCallbackData->objectCount) { + VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead; + VkDebugReportObjectTypeEXT object_type; + VkDebugReportFlagsEXT object_flags = 0; + uint64_t object_handle; + + debug_utils_AnnotFlagsToReportFlags(messageSeverity, messageTypes, &object_flags); + debug_utils_AnnotObjectToDebugReportObject(pCallbackData->pObjects, &object_type, &object_handle); + + while (pTrav) { + if (pTrav->is_messenger && (pTrav->messenger.messageSeverity & messageSeverity) && + (pTrav->messenger.messageType & messageTypes)) { + if (pTrav->messenger.pfnUserCallback(messageSeverity, messageTypes, pCallbackData, pTrav->pUserData)) { + bail = true; + } + } + if (!pTrav->is_messenger && pTrav->report.msgFlags & object_flags) { + if (pTrav->report.pfnMsgCallback(object_flags, object_type, object_handle, 0, pCallbackData->messageIdNumber, + pCallbackData->pMessageIdName, pCallbackData->pMessage, pTrav->pUserData)) { + bail = true; + } + } + + pTrav = pTrav->pNext; + } + } + + return bail; +} + +void util_DestroyDebugUtilsMessenger(struct loader_instance *inst, VkDebugUtilsMessengerEXT messenger, + const VkAllocationCallbacks *pAllocator) { + VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead; + 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 (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + pAllocator->pfnFree(pAllocator->pUserData, pTrav); + } else { +#endif + loader_instance_heap_free(inst, pTrav); + } + break; + } + pPrev = pTrav; + pTrav = pTrav->pNext; + } +} + +// 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; + + 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: +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + pInfos = *infos = ((VkDebugUtilsMessengerCreateInfoEXT *)pAllocator->pfnAllocation( + pAllocator->pUserData, n * sizeof(VkDebugUtilsMessengerCreateInfoEXT), sizeof(void *), + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); + } else { +#endif + pInfos = *infos = ((VkDebugUtilsMessengerCreateInfoEXT *)malloc(n * sizeof(VkDebugUtilsMessengerCreateInfoEXT))); + } + if (!pInfos) { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } +// 3rd, allocate memory for a unique handle for each callback: +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + pMessengers = *messengers = ((VkDebugUtilsMessengerEXT *)pAllocator->pfnAllocation( + pAllocator->pUserData, n * sizeof(VkDebugUtilsMessengerEXT), sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); + if (NULL == pMessengers) { + pAllocator->pfnFree(pAllocator->pUserData, pInfos); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } else { +#endif + pMessengers = *messengers = ((VkDebugUtilsMessengerEXT *)malloc(n * sizeof(VkDebugUtilsMessengerEXT))); + if (NULL == pMessengers) { + free(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) { +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + pAllocator->pfnFree(pAllocator->pUserData, infos); + pAllocator->pfnFree(pAllocator->pUserData, messengers); + } else { +#endif + free(infos); + free(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); + } + return rtn; + } + } + 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); + } +} + +static VKAPI_ATTR void VKAPI_CALL debug_utils_SubmitDebugUtilsMessageEXT( + VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) { + struct loader_instance *inst = loader_get_instance(instance); + + inst->disp->layer_inst_disp.SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, pCallbackData); +} + +static VKAPI_ATTR void VKAPI_CALL debug_utils_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger, + const VkAllocationCallbacks *pAllocator) { + struct loader_instance *inst = loader_get_instance(instance); + loader_platform_thread_lock_mutex(&loader_lock); + + inst->disp->layer_inst_disp.DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator); + + util_DestroyDebugUtilsMessenger(inst, messenger, pAllocator); + + loader_platform_thread_unlock_mutex(&loader_lock); +} + +// This is the instance chain terminator function for CreateDebugUtilsMessenger +VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugUtilsMessengerEXT(VkInstance instance, + const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDebugUtilsMessengerEXT *pMessenger) { + VkDebugUtilsMessengerEXT *icd_info = NULL; + const struct loader_icd_term *icd_term; + struct loader_instance *inst = (struct loader_instance *)instance; + VkResult res = VK_SUCCESS; + uint32_t storage_idx; + VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL; + +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + icd_info = ((VkDebugUtilsMessengerEXT *)pAllocator->pfnAllocation(pAllocator->pUserData, + inst->total_icd_count * sizeof(VkDebugUtilsMessengerEXT), + sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); + if (icd_info) { + memset(icd_info, 0, inst->total_icd_count * sizeof(VkDebugUtilsMessengerEXT)); + } + } else { +#endif + icd_info = calloc(sizeof(VkDebugUtilsMessengerEXT), inst->total_icd_count); + } + if (!icd_info) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + + storage_idx = 0; + for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { + if (!icd_term->dispatch.CreateDebugUtilsMessengerEXT) { + continue; + } + + res = icd_term->dispatch.CreateDebugUtilsMessengerEXT(icd_term->instance, pCreateInfo, pAllocator, &icd_info[storage_idx]); + + if (res != VK_SUCCESS) { + goto out; + } + storage_idx++; + } + +// 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. +#if (DEBUG_DISABLE_APP_ALLOCATORS == 0) + if (pAllocator != NULL) { + pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode), + sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + } else { +#else + { +#endif + pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode), + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + } + if (!pNewDbgFuncNode) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode)); + + 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; + + *(VkDebugUtilsMessengerEXT **)pMessenger = icd_info; + pNewDbgFuncNode->messenger.messenger = *pMessenger; + +out: + + // Roll back on errors + if (VK_SUCCESS != res) { + storage_idx = 0; + for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { + if (NULL == icd_term->dispatch.DestroyDebugUtilsMessengerEXT) { + continue; + } + + if (icd_info && icd_info[storage_idx]) { + icd_term->dispatch.DestroyDebugUtilsMessengerEXT(icd_term->instance, icd_info[storage_idx], pAllocator); + } + storage_idx++; + } + +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + if (NULL != pNewDbgFuncNode) { + pAllocator->pfnFree(pAllocator->pUserData, pNewDbgFuncNode); + } + if (NULL != icd_info) { + pAllocator->pfnFree(pAllocator->pUserData, icd_info); + } + } else { +#endif + if (NULL != pNewDbgFuncNode) { + free(pNewDbgFuncNode); + } + if (NULL != icd_info) { + free(icd_info); + } + } + } + + return res; +} + +// This is the instance chain terminator function for DestroyDebugUtilsMessenger +VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger, + const VkAllocationCallbacks *pAllocator) { + uint32_t storage_idx; + VkDebugUtilsMessengerEXT *icd_info; + const struct loader_icd_term *icd_term; + + struct loader_instance *inst = (struct loader_instance *)instance; + icd_info = *(VkDebugUtilsMessengerEXT **)&messenger; + storage_idx = 0; + for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { + if (NULL == icd_term->dispatch.DestroyDebugUtilsMessengerEXT) { + continue; + } + + if (icd_info[storage_idx]) { + icd_term->dispatch.DestroyDebugUtilsMessengerEXT(icd_term->instance, icd_info[storage_idx], pAllocator); + } + storage_idx++; + } + +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + pAllocator->pfnFree(pAllocator->pUserData, icd_info); + } else { +#endif + free(icd_info); + } +} + +// This is the instance chain terminator function for SubmitDebugUtilsMessageEXT +VKAPI_ATTR void VKAPI_CALL terminator_SubmitDebugUtilsMessageEXT(VkInstance instance, + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) { + const struct loader_icd_term *icd_term; + + struct loader_instance *inst = (struct loader_instance *)instance; + + loader_platform_thread_lock_mutex(&loader_lock); + for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { + if (icd_term->dispatch.SubmitDebugUtilsMessageEXT != NULL) { + icd_term->dispatch.SubmitDebugUtilsMessageEXT(icd_term->instance, messageSeverity, messageTypes, pCallbackData); + } + } + + // Now that all ICDs have seen the message, call the necessary callbacks. Ignoring "bail" return value + // as there is nothing to bail from at this point. + + util_SubmitDebugUtilsMessageEXT(inst, messageSeverity, messageTypes, pCallbackData); + + loader_platform_thread_unlock_mutex(&loader_lock); +} + +// VK_EXT_debug_report related items + +VkResult util_CreateDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT callback) { + VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL; + +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode), + sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + } else { +#endif + pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode), + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + } + if (!pNewDbgFuncNode) { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode)); + + 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; + + return VK_SUCCESS; +} + +static VKAPI_ATTR VkResult VKAPI_CALL +debug_utils_CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback) { + struct loader_instance *inst = loader_get_instance(instance); + loader_platform_thread_lock_mutex(&loader_lock); + VkResult result = inst->disp->layer_inst_disp.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback); + loader_platform_thread_unlock_mutex(&loader_lock); + return result; +} + +// Utility function to handle reporting +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; + VkDebugUtilsMessageSeverityFlagBitsEXT severity; + VkDebugUtilsMessageTypeFlagsEXT types; + VkDebugUtilsMessengerCallbackDataEXT callback_data; + VkDebugUtilsObjectNameInfoEXT object_name; + + debug_utils_ReportFlagsToAnnotFlags(msgFlags, false, &severity, &types); + debug_utils_ReportObjectToAnnotObject(objectType, srcObject, &object_name); + + callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT; + callback_data.pNext = NULL; + callback_data.flags = 0; + callback_data.pMessageIdName = pLayerPrefix; + callback_data.messageIdNumber = msgCode; + callback_data.pMessage = pMsg; + callback_data.cmdBufLabelCount = 0; + callback_data.pCmdBufLabels = NULL; + callback_data.queueLabelCount = 0; + callback_data.pQueueLabels = NULL; + callback_data.objectCount = 1; + callback_data.pObjects = &object_name; + + while (pTrav) { + if (!pTrav->is_messenger && pTrav->report.msgFlags & msgFlags) { + if (pTrav->report.pfnMsgCallback(msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, pMsg, + pTrav->pUserData)) { + bail = true; + } + } + if (pTrav->is_messenger && (pTrav->messenger.messageSeverity & severity) && (pTrav->messenger.messageType & types)) { + if (pTrav->messenger.pfnUserCallback(severity, types, &callback_data, pTrav->pUserData)) { + bail = true; + } + } + + pTrav = pTrav->pNext; + } + + return bail; +} + +void util_DestroyDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackEXT callback, + const VkAllocationCallbacks *pAllocator) { + VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead; + 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 (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + pAllocator->pfnFree(pAllocator->pUserData, pTrav); + } else { +#endif + loader_instance_heap_free(inst, pTrav); + } + break; + } + pPrev = pTrav; + pTrav = pTrav->pNext; + } +} + +// 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; + + 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: +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + pInfos = *infos = ((VkDebugReportCallbackCreateInfoEXT *)pAllocator->pfnAllocation( + pAllocator->pUserData, n * sizeof(VkDebugReportCallbackCreateInfoEXT), sizeof(void *), + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); + } else { +#endif + 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: +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)pAllocator->pfnAllocation( + pAllocator->pUserData, n * sizeof(VkDebugReportCallbackEXT), sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); + if (!pCallbacks) { + pAllocator->pfnFree(pAllocator->pUserData, pInfos); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } else { +#endif + 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)(uintptr_t)pInfos++; + } + pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext; + } + + *num_callbacks = n; + return VK_SUCCESS; +} + +void util_FreeDebugReportCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackCreateInfoEXT *infos, + VkDebugReportCallbackEXT *callbacks) { +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + pAllocator->pfnFree(pAllocator->pUserData, infos); + pAllocator->pfnFree(pAllocator->pUserData, callbacks); + } else { +#endif + free(infos); + free(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); + } + 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_utils_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, + const VkAllocationCallbacks *pAllocator) { + struct loader_instance *inst = loader_get_instance(instance); + loader_platform_thread_lock_mutex(&loader_lock); + + inst->disp->layer_inst_disp.DestroyDebugReportCallbackEXT(instance, callback, pAllocator); + + util_DestroyDebugReportCallback(inst, callback, pAllocator); + + loader_platform_thread_unlock_mutex(&loader_lock); +} + +static VKAPI_ATTR void VKAPI_CALL debug_utils_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objType, uint64_t object, + size_t location, int32_t msgCode, const char *pLayerPrefix, + const char *pMsg) { + struct loader_instance *inst = loader_get_instance(instance); + + inst->disp->layer_inst_disp.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg); +} + +// This is the instance chain terminator function +// for CreateDebugReportCallback +VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallbackEXT(VkInstance instance, + const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDebugReportCallbackEXT *pCallback) { + VkDebugReportCallbackEXT *icd_info = NULL; + const struct loader_icd_term *icd_term; + struct loader_instance *inst = (struct loader_instance *)instance; + VkResult res = VK_SUCCESS; + uint32_t storage_idx; + VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL; + +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + icd_info = ((VkDebugReportCallbackEXT *)pAllocator->pfnAllocation(pAllocator->pUserData, + inst->total_icd_count * sizeof(VkDebugReportCallbackEXT), + sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); + if (icd_info) { + memset(icd_info, 0, inst->total_icd_count * sizeof(VkDebugReportCallbackEXT)); + } + } else { +#endif + icd_info = calloc(sizeof(VkDebugReportCallbackEXT), inst->total_icd_count); + } + if (!icd_info) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + + storage_idx = 0; + for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { + if (!icd_term->dispatch.CreateDebugReportCallbackEXT) { + continue; + } + + res = icd_term->dispatch.CreateDebugReportCallbackEXT(icd_term->instance, pCreateInfo, pAllocator, &icd_info[storage_idx]); + + if (res != VK_SUCCESS) { + goto out; + } + storage_idx++; + } + +// 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. +#if (DEBUG_DISABLE_APP_ALLOCATORS == 0) + if (pAllocator != NULL) { + pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode), + sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + } else { +#else + { +#endif + pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode), + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + } + if (!pNewDbgFuncNode) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode)); + + 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; + + *(VkDebugReportCallbackEXT **)pCallback = icd_info; + pNewDbgFuncNode->report.msgCallback = *pCallback; + +out: + + // Roll back on errors + if (VK_SUCCESS != res) { + storage_idx = 0; + for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { + if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) { + continue; + } + + if (icd_info && icd_info[storage_idx]) { + icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator); + } + storage_idx++; + } + +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + if (NULL != pNewDbgFuncNode) { + pAllocator->pfnFree(pAllocator->pUserData, pNewDbgFuncNode); + } + if (NULL != icd_info) { + pAllocator->pfnFree(pAllocator->pUserData, icd_info); + } + } else { +#endif + if (NULL != pNewDbgFuncNode) { + free(pNewDbgFuncNode); + } + if (NULL != icd_info) { + free(icd_info); + } + } + } + + return res; +} + +// This is the instance chain terminator function for DestroyDebugReportCallback +VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, + const VkAllocationCallbacks *pAllocator) { + uint32_t storage_idx; + VkDebugReportCallbackEXT *icd_info; + const struct loader_icd_term *icd_term; + + struct loader_instance *inst = (struct loader_instance *)instance; + icd_info = *(VkDebugReportCallbackEXT **)&callback; + storage_idx = 0; + for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { + if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) { + continue; + } + + if (icd_info[storage_idx]) { + icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator); + } + storage_idx++; + } + +#if (DEBUG_DISABLE_APP_ALLOCATORS == 1) + { +#else + if (pAllocator != NULL) { + pAllocator->pfnFree(pAllocator->pUserData, icd_info); + } else { +#endif + free(icd_info); + } +} + +// This is the instance chain terminator function for DebugReportMessage +VKAPI_ATTR void VKAPI_CALL terminator_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location, + int32_t msgCode, const char *pLayerPrefix, const char *pMsg) { + const struct loader_icd_term *icd_term; + + struct loader_instance *inst = (struct loader_instance *)instance; + + loader_platform_thread_lock_mutex(&loader_lock); + for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { + if (icd_term->dispatch.DebugReportMessageEXT != NULL) { + icd_term->dispatch.DebugReportMessageEXT(icd_term->instance, flags, objType, object, location, msgCode, pLayerPrefix, + pMsg); + } + } + + // Now that all ICDs have seen the message, call the necessary callbacks. Ignoring "bail" return value + // as there is nothing to bail from at this point. + + util_DebugReportMessage(inst, flags, objType, object, location, msgCode, pLayerPrefix, pMsg); + + loader_platform_thread_unlock_mutex(&loader_lock); +} + +// General utilities + +static const VkExtensionProperties debug_utils_extension_info[] = { + {VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}, + {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) { + 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) { + ptr_instance->enabled_known_extensions.ext_debug_report = 0; + ptr_instance->enabled_known_extensions.ext_debug_utils = 0; + + 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; + } else if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) { + ptr_instance->enabled_known_extensions.ext_debug_utils = 1; + } + } +} + +bool debug_utils_InstanceGpa(struct loader_instance *ptr_instance, const char *name, void **addr) { + bool ret_type = false; + + *addr = NULL; + + if (ptr_instance->enabled_known_extensions.ext_debug_report == 1) { + if (!strcmp("vkCreateDebugReportCallbackEXT", name)) { + *addr = (void *)debug_utils_CreateDebugReportCallbackEXT; + ret_type = true; + } else if (!strcmp("vkDestroyDebugReportCallbackEXT", name)) { + *addr = (void *)debug_utils_DestroyDebugReportCallbackEXT; + ret_type = true; + } else if (!strcmp("vkDebugReportMessageEXT", name)) { + *addr = (void *)debug_utils_DebugReportMessageEXT; + return true; + } + } + if (ptr_instance->enabled_known_extensions.ext_debug_utils == 1) { + if (!strcmp("vkCreateDebugUtilsMessengerEXT", name)) { + *addr = (void *)debug_utils_CreateDebugUtilsMessengerEXT; + ret_type = true; + } else if (!strcmp("vkDestroyDebugUtilsMessengerEXT", name)) { + *addr = (void *)debug_utils_DestroyDebugUtilsMessengerEXT; + ret_type = true; + } else if (!strcmp("vkSubmitDebugUtilsMessageEXT", name)) { + *addr = (void *)debug_utils_SubmitDebugUtilsMessageEXT; + ret_type = true; + } + } + + return ret_type; +} + +bool debug_utils_ReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec, + VkDebugUtilsMessageSeverityFlagBitsEXT *da_severity, + VkDebugUtilsMessageTypeFlagsEXT *da_type) { + bool type_set = false; + if (NULL == da_severity || NULL == da_type) { + return false; + } + *da_type = 0; + + if ((dr_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0) { + *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; + *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; + type_set = true; + } else if ((dr_flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)) != 0) { + *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + } else if ((dr_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) { + *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + } else if ((dr_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0) { + *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; + *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; + type_set = true; + } + + if ((dr_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0) { + *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + } else if (!type_set) { + if (default_flag_is_spec) { + *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + } else { + *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; + } + } + + return true; +} + +bool debug_utils_AnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity, + VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags) { + if (NULL == dr_flags) { + return false; + } + + *dr_flags = 0; + + if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) { + *dr_flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT; + } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) { + if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) { + *dr_flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; + } else { + *dr_flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT; + } + } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) { + *dr_flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT; + } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) { + *dr_flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT; + } + + return true; +} + +bool debug_utils_ReportObjectToAnnotObject(VkDebugReportObjectTypeEXT dr_object_type, uint64_t object_handle, + VkDebugUtilsObjectNameInfoEXT *da_object_name_info) { + if (NULL == da_object_name_info) { + return false; + } + da_object_name_info->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + da_object_name_info->pNext = NULL; + da_object_name_info->objectHandle = (uint64_t)(uintptr_t)object_handle; + da_object_name_info->pObjectName = NULL; + da_object_name_info->objectType = convertDebugReportObjectToCoreObject(dr_object_type); + return true; +} + +bool debug_utils_AnnotObjectToDebugReportObject(const VkDebugUtilsObjectNameInfoEXT *da_object_name_info, + VkDebugReportObjectTypeEXT *dr_object_type, uint64_t *dr_object_handle) { + if (NULL == da_object_name_info || NULL == dr_object_type || NULL == dr_object_handle) { + return false; + } + *dr_object_type = convertCoreObjectToDebugReportObject(da_object_name_info->objectType); + *dr_object_handle = da_object_name_info->objectHandle; + return true; +} diff --git a/loader/debug_utils.h b/loader/debug_utils.h new file mode 100644 index 00000000..c33a6fce --- /dev/null +++ b/loader/debug_utils.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015-2017 The Khronos Group Inc. + * Copyright (c) 2015-2017 Valve Corporation + * Copyright (c) 2015-2017 LunarG, Inc. + * Copyright (C) 2015-2016 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> + * Author: Jon Ashburn <jon@lunarg.com> + * Author: Mark Young <markyk@lunarg.com> + * + */ + +#include "vk_loader_platform.h" +#include "loader.h" + +// 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); +bool debug_utils_ReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec, + VkDebugUtilsMessageSeverityFlagBitsEXT *da_severity, + VkDebugUtilsMessageTypeFlagsEXT *da_type); +bool debug_utils_AnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity, + VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags); +bool debug_utils_ReportObjectToAnnotObject(VkDebugReportObjectTypeEXT dr_object_type, uint64_t object_handle, + VkDebugUtilsObjectNameInfoEXT *da_object_name_info); +bool debug_utils_AnnotObjectToDebugReportObject(const VkDebugUtilsObjectNameInfoEXT *da_object_name_info, + VkDebugReportObjectTypeEXT *dr_object_type, uint64_t *dr_object_handle); + +// VK_EXT_debug_utils related items + +VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugUtilsMessengerEXT(VkInstance instance, + const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDebugUtilsMessengerEXT *pMessenger); +VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger, + const VkAllocationCallbacks *pAllocator); +VKAPI_ATTR void VKAPI_CALL terminator_SubmitDebugUtilsMessageEXT(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); +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 + +VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallbackEXT(VkInstance instance, + const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDebugReportCallbackEXT *pCallback); + +VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, + const VkAllocationCallbacks *pAllocator); + +VKAPI_ATTR void VKAPI_CALL terminator_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, + 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); +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); diff --git a/loader/extension_manual.c b/loader/extension_manual.c index 65c625ea..2b70af70 100644 --- a/loader/extension_manual.c +++ b/loader/extension_manual.c @@ -28,7 +28,7 @@ #include "vk_loader_extensions.h" #include <vulkan/vk_icd.h> #include "wsi.h" -#include "debug_report.h" +#include "debug_utils.h" // ---- Manually added trampoline/terminator functions diff --git a/loader/gpa_helper.h b/loader/gpa_helper.h index 463e352b..1196edf5 100644 --- a/loader/gpa_helper.h +++ b/loader/gpa_helper.h @@ -20,7 +20,7 @@ */ #include <string.h> -#include "debug_report.h" +#include "debug_utils.h" #include "wsi.h" static inline void *trampolineGetProcAddr(struct loader_instance *inst, const char *funcName) { @@ -189,7 +189,7 @@ static inline void *trampolineGetProcAddr(struct loader_instance *inst, const ch // Instance extensions void *addr; - if (debug_report_instance_gpa(inst, funcName, &addr)) return addr; + if (debug_utils_InstanceGpa(inst, funcName, &addr)) return addr; if (wsi_swapchain_instance_gpa(inst, funcName, &addr)) return addr; diff --git a/loader/loader.c b/loader/loader.c index d4e0e026..92be90b7 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -45,7 +45,7 @@ #include "vk_loader_platform.h" #include "loader.h" #include "gpa_helper.h" -#include "debug_report.h" +#include "debug_utils.h" #include "wsi.h" #include "vulkan/vk_icd.h" #include "cJSON.h" @@ -322,8 +322,46 @@ void loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t ms va_end(ap); if (inst) { - util_DebugReportMessage(inst, msg_type, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, (uint64_t)(uintptr_t)inst, 0, msg_code, - "loader", msg); + VkDebugUtilsMessageSeverityFlagBitsEXT severity; + VkDebugUtilsMessageTypeFlagsEXT type; + VkDebugUtilsMessengerCallbackDataEXT callback_data; + VkDebugUtilsObjectNameInfoEXT object_name; + + if ((msg_type & LOADER_INFO_BIT) != 0) { + severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; + } else if ((msg_type & LOADER_WARN_BIT) != 0) { + severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + } else if ((msg_type & LOADER_ERROR_BIT) != 0) { + severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + } else if ((msg_type & LOADER_DEBUG_BIT) != 0) { + severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; + } + + if ((msg_type & LOADER_PERF_BIT) != 0) { + type = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + } else { + type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; + } + + callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT; + callback_data.pNext = NULL; + callback_data.flags = 0; + callback_data.pMessageIdName = "Loader Message"; + callback_data.messageIdNumber = 0; + callback_data.pMessage = msg; + callback_data.queueLabelCount = 0; + callback_data.pQueueLabels = NULL; + callback_data.cmdBufLabelCount = 0; + callback_data.pCmdBufLabels = NULL; + callback_data.objectCount = 1; + callback_data.pObjects = &object_name; + object_name.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + object_name.pNext = NULL; + object_name.objectType = VK_OBJECT_TYPE_INSTANCE; + object_name.objectHandle = (uint64_t)(uintptr_t)inst; + object_name.pObjectName = NULL; + + util_SubmitDebugUtilsMessageEXT(inst, severity, type, &callback_data); } if (!(msg_type & g_loader_log_msgs)) { @@ -1608,7 +1646,7 @@ VkResult loader_get_icd_loader_instance_extensions(const struct loader_instance }; // Traverse loader's extensions, adding non-duplicate extensions to the list - debug_report_add_instance_extensions(inst, inst_exts); + debug_utils_AddInstanceExtensions(inst, inst_exts); out: return res; diff --git a/loader/loader.h b/loader/loader.h index ae928f95..9342e21c 100644 --- a/loader/loader.h +++ b/loader/loader.h @@ -276,9 +276,12 @@ struct loader_instance { union loader_instance_extension_enables enabled_known_extensions; VkLayerDbgFunctionNode *DbgFunctionHead; - uint32_t num_tmp_callbacks; - VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos; - VkDebugReportCallbackEXT *tmp_callbacks; + 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; VkAllocationCallbacks alloc_callbacks; diff --git a/loader/trampoline.c b/loader/trampoline.c index 7915006d..6b0464d4 100644 --- a/loader/trampoline.c +++ b/loader/trampoline.c @@ -28,7 +28,7 @@ #include "vk_loader_platform.h" #include "loader.h" -#include "debug_report.h" +#include "debug_utils.h" #include "wsi.h" #include "vk_loader_extensions.h" #include "gpa_helper.h" @@ -324,23 +324,42 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCr ptr_instance->app_api_minor_version = VK_VERSION_MINOR(pCreateInfo->pApplicationInfo->apiVersion); } - // Look for one or more debug report create info structures + // 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_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: + 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; goto out; - } else if (ptr_instance->num_tmp_callbacks > 0) { + } 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; + 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_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: + 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; } @@ -404,7 +423,7 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCr memset(ptr_instance->enabled_known_extensions.padding, 0, sizeof(uint64_t) * 4); wsi_create_instance(ptr_instance, &ici); - debug_report_create_instance(ptr_instance, &ici); + debug_utils_CreateInstance(ptr_instance, &ici); extensions_create_instance(ptr_instance, &ici); *pInstance = created_instance; @@ -426,10 +445,19 @@ out: if (NULL != ptr_instance->disp) { loader_instance_heap_free(ptr_instance, ptr_instance->disp); } - if (ptr_instance->num_tmp_callbacks > 0) { - 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); + 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); } if (NULL != ptr_instance->expanded_activated_layer_list.list) { @@ -445,9 +473,11 @@ out: loader_instance_heap_free(ptr_instance, ptr_instance); } else { - // Remove temporary debug_report callback - util_DestroyDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_callbacks, - ptr_instance->tmp_callbacks); + // 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) { @@ -462,6 +492,7 @@ LOADER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkLayerInstanceDispatchTable *disp; struct loader_instance *ptr_instance = NULL; bool callback_setup = false; + bool messenger_setup = false; if (instance == VK_NULL_HANDLE) { return; @@ -477,10 +508,18 @@ LOADER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, ptr_instance->alloc_callbacks = *pAllocator; } - 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)) { + 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; + } + } + + 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; } } @@ -508,9 +547,15 @@ LOADER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_tramp); } + if (messenger_setup) { + 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) { - 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); + 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); } loader_instance_heap_free(ptr_instance, ptr_instance->disp); loader_instance_heap_free(ptr_instance, ptr_instance); diff --git a/loader/vk_loader_layer.h b/loader/vk_loader_layer.h index 425154d8..dfcf5b2a 100644 --- a/loader/vk_loader_layer.h +++ b/loader/vk_loader_layer.h @@ -21,11 +21,26 @@ */ #pragma once -// Linked list node for tree of debug callback functions -typedef struct VkLayerDbgFunctionNode_ { +// Linked list node for tree of debug callbacks +typedef struct VkDebugReportContent { VkDebugReportCallbackEXT msgCallback; PFN_vkDebugReportCallbackEXT pfnMsgCallback; VkFlags msgFlags; +} VkDebugReportContent; + +typedef struct VkDebugUtilsMessengerContent { + VkDebugUtilsMessengerEXT messenger; + VkDebugUtilsMessageSeverityFlagsEXT messageSeverity; + VkDebugUtilsMessageTypeFlagsEXT messageType; + PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback; +} VkDebugUtilsMessengerContent; + +typedef struct VkLayerDbgFunctionNode_ { + bool is_messenger; + union { + VkDebugReportContent report; + VkDebugUtilsMessengerContent messenger; + }; void *pUserData; struct VkLayerDbgFunctionNode_ *pNext; } VkLayerDbgFunctionNode; |
