| /* |
| * Vulkan |
| * |
| * Copyright (C) 2014 LunarG, Inc. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| * |
| * Authors: |
| * Courtney Goeltzenleuchter <courtney@lunarg.com> |
| */ |
| |
| #ifndef LAYER_LOGGING_H |
| #define LAYER_LOGGING_H |
| |
| #include <stdio.h> |
| #include <stdbool.h> |
| #include <unordered_map> |
| #include "vkLayer.h" |
| #include "layers_table.h" |
| |
| struct debug_report_data { |
| VkLayerDbgFunctionNode *g_pDbgFunctionHead; |
| bool g_DEBUG_REPORT; |
| }; |
| |
| static std::unordered_map<void *, struct debug_report_data *> debug_report_data_map; |
| |
| static struct debug_report_data *get_debug_data_ptr( |
| void *data_key) |
| { |
| struct debug_report_data *debug_data; |
| std::unordered_map<void *, struct debug_report_data *>::const_iterator got; |
| |
| got = debug_report_data_map.find(data_key); |
| |
| if ( got == debug_report_data_map.end() ) { |
| debug_data = new struct debug_report_data; |
| memset(debug_data, 0, sizeof(*debug_data)); |
| debug_report_data_map[(void *) data_key] = debug_data; |
| } else { |
| debug_data = got->second; |
| } |
| |
| return debug_data; |
| } |
| |
| static struct debug_report_data *get_device_debug_data_ptr( |
| VkLayerDispatchTable *device_dispatch_ptr) |
| { |
| return get_debug_data_ptr((void *) device_dispatch_ptr); |
| } |
| |
| static struct debug_report_data *get_instance_debug_data_ptr( |
| VkLayerInstanceDispatchTable *instance_dispatch_ptr) |
| { |
| return get_debug_data_ptr((void *) instance_dispatch_ptr); |
| } |
| |
| static inline void debug_report_init_instance_extension_dispatch_table( |
| VkLayerInstanceDispatchTable *table, |
| PFN_vkGetInstanceProcAddr gpa, |
| VkInstance inst) |
| { |
| table->DbgCreateMsgCallback = (PFN_vkDbgCreateMsgCallback) gpa(inst, "vkDbgCreateMsgCallback"); |
| table->DbgDestroyMsgCallback = (PFN_vkDbgDestroyMsgCallback) gpa(inst, "vkDbgDestroyMsgCallback"); |
| } |
| |
| // Utility function to handle reporting |
| static void debug_report_log_msg( |
| struct debug_report_data *debug_data, |
| VkFlags msgFlags, |
| VkObjectType objectType, |
| VkObject srcObject, |
| size_t location, |
| int32_t msgCode, |
| const char* pLayerPrefix, |
| const char* pMsg) |
| { |
| VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead; |
| while (pTrav) { |
| if (pTrav->msgFlags & msgFlags) { |
| pTrav->pfnMsgCallback(msgFlags, |
| objectType, srcObject, |
| location, |
| msgCode, |
| pLayerPrefix, |
| pMsg, |
| (void *) pTrav->pUserData); |
| } |
| pTrav = pTrav->pNext; |
| } |
| } |
| |
| static inline void debug_report_create_instance( |
| VkLayerInstanceDispatchTable *instance_dispatch_ptr, |
| uint32_t extension_count, |
| const VkExtensionProperties* pEnabledExtensions) // layer or extension name to be enabled |
| { |
| struct debug_report_data *debug_data = get_debug_data_ptr(instance_dispatch_ptr); |
| |
| for (uint32_t i = 0; i < extension_count; i++) { |
| /* TODO: Check other property fields */ |
| if (strcmp(pEnabledExtensions[i].name, DEBUG_REPORT_EXTENSION_NAME) == 0) { |
| debug_data->g_DEBUG_REPORT = true; |
| } |
| } |
| } |
| |
| static inline void layer_debug_report_destroy_instance(VkInstance instance) |
| { |
| VkLayerInstanceDispatchTable *instance_key = instance_dispatch_table(instance); |
| struct debug_report_data *debug_data = |
| get_debug_data_ptr(instance_dispatch_table(instance)); |
| VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead; |
| VkLayerDbgFunctionNode *pTravNext; |
| |
| /* Clear out any leftover callbacks */ |
| while (pTrav) { |
| pTravNext = pTrav->pNext; |
| |
| debug_report_log_msg( |
| debug_data, VK_DBG_REPORT_WARN_BIT, |
| VK_OBJECT_TYPE_INSTANCE, instance, |
| 0, DEBUG_REPORT_CALLBACK_REF, |
| "DebugReport", |
| "Debug Report callbacks not removed before DestroyInstance"); |
| |
| free(pTrav); |
| pTrav = pTravNext; |
| } |
| debug_data->g_pDbgFunctionHead = NULL; |
| debug_report_data_map.erase((void *) instance_key); |
| tableInstanceMap.erase((void *) instance); |
| } |
| |
| static inline void layer_debug_report_create_device( |
| VkLayerInstanceDispatchTable *instance_dispatch_ptr, |
| VkDevice device) |
| { |
| std::unordered_map<void *, struct debug_report_data *>::const_iterator got; |
| |
| got = debug_report_data_map.find((void *) instance_dispatch_ptr); |
| |
| if ( got == debug_report_data_map.end() ) { |
| // If we get here something is wrong |
| // We should always be able to find the instance key |
| assert(true); |
| } else { |
| VkLayerDispatchTable *device_key = device_dispatch_table(device); |
| debug_report_data_map[(void *) device_key ] = got->second; |
| } |
| } |
| |
| static inline void layer_debug_report_destroy_device(VkDevice device) |
| { |
| VkLayerDispatchTable *device_key = device_dispatch_table(device); |
| debug_report_data_map.erase((void *) device_key); |
| tableMap.erase((void *) device); |
| } |
| |
| static inline VkResult layer_create_msg_callback( |
| VkInstance instance, |
| VkLayerInstanceDispatchTable *nextTable, |
| VkFlags msgFlags, |
| const PFN_vkDbgMsgCallback pfnMsgCallback, |
| void *pUserData, |
| VkDbgMsgCallback *pMsgCallback) |
| { |
| VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode*)malloc(sizeof(VkLayerDbgFunctionNode)); |
| if (!pNewDbgFuncNode) |
| return VK_ERROR_OUT_OF_HOST_MEMORY; |
| |
| VkResult result = nextTable->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback); |
| |
| if (result == VK_SUCCESS) { |
| struct debug_report_data *debug_data = |
| get_debug_data_ptr(instance_dispatch_table(instance)); |
| |
| pNewDbgFuncNode->msgCallback = *pMsgCallback; |
| pNewDbgFuncNode->pfnMsgCallback = pfnMsgCallback; |
| pNewDbgFuncNode->msgFlags = msgFlags; |
| pNewDbgFuncNode->pUserData = pUserData; |
| pNewDbgFuncNode->pNext = debug_data->g_pDbgFunctionHead; |
| |
| debug_data->g_pDbgFunctionHead = pNewDbgFuncNode; |
| |
| debug_report_log_msg( |
| debug_data, VK_DBG_REPORT_DEBUG_BIT, |
| VK_OBJECT_TYPE_INSTANCE, instance, |
| 0, DEBUG_REPORT_CALLBACK_REF, |
| "DebugReport", |
| "Added callback"); |
| } else { |
| free(pNewDbgFuncNode); |
| } |
| return result; |
| } |
| |
| static VkResult layer_destroy_msg_callback( |
| VkInstance instance, |
| VkLayerInstanceDispatchTable *nextTable, |
| VkDbgMsgCallback msg_callback) |
| { |
| struct debug_report_data *debug_data = |
| get_debug_data_ptr(instance_dispatch_table(instance)); |
| VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead; |
| VkLayerDbgFunctionNode *pPrev = pTrav; |
| |
| VkResult result = nextTable->DbgDestroyMsgCallback(instance, msg_callback); |
| |
| while (pTrav) { |
| if (pTrav->msgCallback == msg_callback) { |
| pPrev->pNext = pTrav->pNext; |
| if (debug_data->g_pDbgFunctionHead == pTrav) { |
| debug_data->g_pDbgFunctionHead = pTrav->pNext; |
| } |
| free(pTrav); |
| debug_report_log_msg( |
| debug_data, VK_DBG_REPORT_DEBUG_BIT, |
| VK_OBJECT_TYPE_INSTANCE, instance, |
| 0, DEBUG_REPORT_CALLBACK_REF, |
| "DebugReport", |
| "Removed callback"); |
| break; |
| } |
| pPrev = pTrav; |
| pTrav = pTrav->pNext; |
| } |
| |
| return result; |
| } |
| |
| static void* debug_report_get_instance_proc_addr( |
| VkInstance instance, |
| const char *funcName) |
| { |
| struct debug_report_data *debug_data = |
| get_debug_data_ptr(instance_dispatch_table(instance)); |
| if (!debug_data->g_DEBUG_REPORT) { |
| return NULL; |
| } |
| |
| if (!strcmp(funcName, "vkDbgCreateMsgCallback")) { |
| return (void *) vkDbgCreateMsgCallback; |
| } |
| if (!strcmp(funcName, "vkDbgDestroyMsgCallback")) { |
| return (void *) vkDbgDestroyMsgCallback; |
| } |
| |
| return NULL; |
| } |
| |
| /* |
| * Devices, Queue, SwapChain and Command buffers all |
| * use the same device dispatch table. |
| */ |
| static void device_log_msg( |
| VkObject object, |
| VkFlags msgFlags, |
| VkObjectType objectType, |
| VkObject srcObject, |
| size_t location, |
| int32_t msgCode, |
| const char* pLayerPrefix, |
| const char* pMsg) |
| { |
| struct debug_report_data *debug_data; |
| debug_data = get_device_debug_data_ptr(device_dispatch_table(object)); |
| debug_report_log_msg(debug_data, msgFlags, objectType, |
| srcObject, location, msgCode, |
| pLayerPrefix, pMsg); |
| } |
| |
| static void instance_log_msg( |
| VkInstance instance, |
| VkFlags msgFlags, |
| VkObjectType objectType, |
| VkObject srcObject, |
| size_t location, |
| int32_t msgCode, |
| const char* pLayerPrefix, |
| const char* pMsg) |
| { |
| struct debug_report_data *debug_data; |
| |
| debug_data = get_instance_debug_data_ptr(instance_dispatch_table(instance)); |
| debug_report_log_msg(debug_data, msgFlags, objectType, |
| srcObject, location, msgCode, |
| pLayerPrefix, pMsg); |
| } |
| |
| #endif // LAYER_LOGGING_H |
| |