From 05710abce080c2665c6095c5faf8f6c47af66cf6 Mon Sep 17 00:00:00 2001 From: Courtney Goeltzenleuchter Date: Thu, 11 Jun 2015 15:58:51 -0600 Subject: debug_report: Utilities for layers to use This header is intended to be used by all validation layers and provides the necessary functions to process DEBUG_REPORT messages and generate callbacks. This is intended for layers implementing per instance / device storage. --- layers/layer_logging.h | 309 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 layers/layer_logging.h diff --git a/layers/layer_logging.h b/layers/layer_logging.h new file mode 100644 index 00000000..b7f77c4a --- /dev/null +++ b/layers/layer_logging.h @@ -0,0 +1,309 @@ +/* + * 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 + */ + +#ifndef LAYER_LOGGING_H +#define LAYER_LOGGING_H + +#include +#include +#include +#include "vkLayer.h" +#include "layers_table.h" + +struct debug_report_data { + VkLayerDbgFunctionNode *g_pDbgFunctionHead; + bool g_DEBUG_REPORT; +}; + +static std::unordered_map 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::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::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 + -- cgit v1.2.3