vk_layer_logging.h revision 5c13d4d87fd0356003a3441e887a172b991e880f
1/* Copyright (c) 2015-2016 The Khronos Group Inc. 2 * Copyright (c) 2015-2016 Valve Corporation 3 * Copyright (c) 2015-2016 LunarG, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and/or associated documentation files (the "Materials"), to 7 * deal in the Materials without restriction, including without limitation the 8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9 * sell copies of the Materials, and to permit persons to whom the Materials 10 * are furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice(s) and this permission notice shall be included 13 * in all copies or substantial portions of the Materials. 14 * 15 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 * 19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE 22 * USE OR OTHER DEALINGS IN THE MATERIALS 23 * 24 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> 25 * Author: Tobin Ehlis <tobin@lunarg.com> 26 * 27 */ 28 29#ifndef LAYER_LOGGING_H 30#define LAYER_LOGGING_H 31 32#include <stdio.h> 33#include <stdarg.h> 34#include <stdbool.h> 35#include <unordered_map> 36#include <inttypes.h> 37#include "vk_loader_platform.h" 38#include "vulkan/vk_layer.h" 39#include "vk_layer_data.h" 40#include "vk_layer_table.h" 41 42typedef struct _debug_report_data { 43 VkLayerDbgFunctionNode *g_pDbgFunctionHead; 44 VkFlags active_flags; 45 bool g_DEBUG_REPORT; 46} debug_report_data; 47 48template debug_report_data *get_my_data_ptr<debug_report_data>( 49 void *data_key, 50 std::unordered_map<void *, debug_report_data *> &data_map); 51 52// Utility function to handle reporting 53static inline VkBool32 debug_report_log_msg( 54 debug_report_data *debug_data, 55 VkFlags msgFlags, 56 VkDebugReportObjectTypeEXT objectType, 57 uint64_t srcObject, 58 size_t location, 59 int32_t msgCode, 60 const char* pLayerPrefix, 61 const char* pMsg) 62{ 63 VkBool32 bail = false; 64 VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead; 65 while (pTrav) { 66 if (pTrav->msgFlags & msgFlags) { 67 if (pTrav->pfnMsgCallback(msgFlags, 68 objectType, srcObject, 69 location, 70 msgCode, 71 pLayerPrefix, 72 pMsg, 73 pTrav->pUserData)) { 74 bail = true; 75 } 76 } 77 pTrav = pTrav->pNext; 78 } 79 80 return bail; 81} 82 83static inline debug_report_data *debug_report_create_instance( 84 VkLayerInstanceDispatchTable *table, 85 VkInstance inst, 86 uint32_t extension_count, 87 const char*const* ppEnabledExtensions) // layer or extension name to be enabled 88{ 89 debug_report_data *debug_data; 90 PFN_vkGetInstanceProcAddr gpa = table->GetInstanceProcAddr; 91 92 table->CreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT) gpa(inst, "vkCreateDebugReportCallbackEXT"); 93 table->DestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT) gpa(inst, "vkDestroyDebugReportCallbackEXT"); 94 table->DebugReportMessageEXT = (PFN_vkDebugReportMessageEXT) gpa(inst, "vkDebugReportMessageEXT"); 95 96 debug_data = (debug_report_data *) malloc(sizeof(debug_report_data)); 97 if (!debug_data) return NULL; 98 99 memset(debug_data, 0, sizeof(debug_report_data)); 100 for (uint32_t i = 0; i < extension_count; i++) { 101 /* TODO: Check other property fields */ 102 if (strcmp(ppEnabledExtensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) { 103 debug_data->g_DEBUG_REPORT = true; 104 } 105 } 106 return debug_data; 107} 108 109static inline void layer_debug_report_destroy_instance(debug_report_data *debug_data) 110{ 111 VkLayerDbgFunctionNode *pTrav; 112 VkLayerDbgFunctionNode *pTravNext; 113 114 if (!debug_data) { 115 return; 116 } 117 118 pTrav = debug_data->g_pDbgFunctionHead; 119 /* Clear out any leftover callbacks */ 120 while (pTrav) { 121 pTravNext = pTrav->pNext; 122 123 debug_report_log_msg( 124 debug_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, 125 VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, (uint64_t) pTrav->msgCallback, 126 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, 127 "DebugReport", 128 "Debug Report callbacks not removed before DestroyInstance"); 129 130 free(pTrav); 131 pTrav = pTravNext; 132 } 133 debug_data->g_pDbgFunctionHead = NULL; 134 135 free(debug_data); 136} 137 138static inline debug_report_data *layer_debug_report_create_device( 139 debug_report_data *instance_debug_data, 140 VkDevice device) 141{ 142 /* DEBUG_REPORT shares data between Instance and Device, 143 * so just return instance's data pointer */ 144 return instance_debug_data; 145} 146 147static inline void layer_debug_report_destroy_device(VkDevice device) 148{ 149 /* Nothing to do since we're using instance data record */ 150} 151 152static inline VkResult layer_create_msg_callback( 153 debug_report_data *debug_data, 154 const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, 155 const VkAllocationCallbacks *pAllocator, 156 VkDebugReportCallbackEXT *pCallback) 157{ 158 /* TODO: Use app allocator */ 159 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode*)malloc(sizeof(VkLayerDbgFunctionNode)); 160 if (!pNewDbgFuncNode) 161 return VK_ERROR_OUT_OF_HOST_MEMORY; 162 163 // Handle of 0 is logging_callback so use allocated Node address as unique handle 164 if (!(*pCallback)) 165 *pCallback = (VkDebugReportCallbackEXT) pNewDbgFuncNode; 166 pNewDbgFuncNode->msgCallback = *pCallback; 167 pNewDbgFuncNode->pfnMsgCallback = pCreateInfo->pfnCallback; 168 pNewDbgFuncNode->msgFlags = pCreateInfo->flags; 169 pNewDbgFuncNode->pUserData = pCreateInfo->pUserData; 170 pNewDbgFuncNode->pNext = debug_data->g_pDbgFunctionHead; 171 172 debug_data->g_pDbgFunctionHead = pNewDbgFuncNode; 173 debug_data->active_flags |= pCreateInfo->flags; 174 175 debug_report_log_msg( 176 debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 177 VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, (uint64_t) *pCallback, 178 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, 179 "DebugReport", 180 "Added callback"); 181 return VK_SUCCESS; 182} 183 184static inline void layer_destroy_msg_callback( 185 debug_report_data *debug_data, 186 VkDebugReportCallbackEXT callback, 187 const VkAllocationCallbacks *pAllocator) 188{ 189 VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead; 190 VkLayerDbgFunctionNode *pPrev = pTrav; 191 bool matched; 192 193 debug_data->active_flags = 0; 194 while (pTrav) { 195 if (pTrav->msgCallback == callback) { 196 matched = true; 197 pPrev->pNext = pTrav->pNext; 198 if (debug_data->g_pDbgFunctionHead == pTrav) { 199 debug_data->g_pDbgFunctionHead = pTrav->pNext; 200 } 201 debug_report_log_msg( 202 debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 203 VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, (uint64_t) pTrav->msgCallback, 204 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, 205 "DebugReport", 206 "Destroyed callback"); 207 } else { 208 matched = false; 209 debug_data->active_flags |= pTrav->msgFlags; 210 } 211 pPrev = pTrav; 212 pTrav = pTrav->pNext; 213 if (matched) { 214 /* TODO: Use pAllocator */ 215 free(pPrev); 216 } 217 } 218} 219 220static inline PFN_vkVoidFunction debug_report_get_instance_proc_addr( 221 debug_report_data *debug_data, 222 const char *funcName) 223{ 224 if (!debug_data || !debug_data->g_DEBUG_REPORT) { 225 return NULL; 226 } 227 228 if (!strcmp(funcName, "vkCreateDebugReportCallbackEXT")) { 229 return (PFN_vkVoidFunction) vkCreateDebugReportCallbackEXT; 230 } 231 if (!strcmp(funcName, "vkDestroyDebugReportCallbackEXT")) { 232 return (PFN_vkVoidFunction) vkDestroyDebugReportCallbackEXT; 233 } 234 235 if (!strcmp(funcName, "vkDebugReportMessageEXT")) { 236 return (PFN_vkVoidFunction) vkDebugReportMessageEXT; 237 } 238 239 return NULL; 240} 241 242/* 243 * Checks if the message will get logged. 244 * Allows layer to defer collecting & formating data if the 245 * message will be discarded. 246 */ 247static inline VkBool32 will_log_msg( 248 debug_report_data *debug_data, 249 VkFlags msgFlags) 250{ 251 if (!debug_data || !(debug_data->active_flags & msgFlags)) { 252 /* message is not wanted */ 253 return false; 254 } 255 256 return true; 257} 258 259/* 260 * Output log message via DEBUG_REPORT 261 * Takes format and variable arg list so that output string 262 * is only computed if a message needs to be logged 263 */ 264#ifndef WIN32 265static inline VkBool32 log_msg( 266 debug_report_data *debug_data, 267 VkFlags msgFlags, 268 VkDebugReportObjectTypeEXT objectType, 269 uint64_t srcObject, 270 size_t location, 271 int32_t msgCode, 272 const char* pLayerPrefix, 273 const char* format, 274 ...) __attribute__ ((format (printf, 8, 9))); 275#endif 276static inline VkBool32 log_msg( 277 debug_report_data *debug_data, 278 VkFlags msgFlags, 279 VkDebugReportObjectTypeEXT objectType, 280 uint64_t srcObject, 281 size_t location, 282 int32_t msgCode, 283 const char* pLayerPrefix, 284 const char* format, 285 ...) 286{ 287 if (!debug_data || !(debug_data->active_flags & msgFlags)) { 288 /* message is not wanted */ 289 return false; 290 } 291 292 char str[1024]; 293 va_list argptr; 294 va_start(argptr, format); 295 vsnprintf(str, 1024, format, argptr); 296 va_end(argptr); 297 return debug_report_log_msg( 298 debug_data, msgFlags, objectType, 299 srcObject, location, msgCode, 300 pLayerPrefix, str); 301} 302 303static inline VKAPI_ATTR VkBool32 VKAPI_CALL log_callback( 304 VkFlags msgFlags, 305 VkDebugReportObjectTypeEXT objType, 306 uint64_t srcObject, 307 size_t location, 308 int32_t msgCode, 309 const char* pLayerPrefix, 310 const char* pMsg, 311 void* pUserData) 312{ 313 char msg_flags[30]; 314 315 print_msg_flags(msgFlags, msg_flags); 316 317 fprintf((FILE *) pUserData, "%s(%s): object: %#" PRIx64 " type: %d location: %lu msgCode: %d: %s\n", 318 pLayerPrefix, msg_flags, srcObject, objType, (unsigned long)location, msgCode, pMsg); 319 fflush((FILE *) pUserData); 320 321 return false; 322} 323 324static inline VKAPI_ATTR VkBool32 VKAPI_CALL win32_debug_output_msg( 325 VkFlags msgFlags, 326 VkDebugReportObjectTypeEXT objType, 327 uint64_t srcObject, 328 size_t location, 329 int32_t msgCode, 330 const char* pLayerPrefix, 331 const char* pMsg, 332 void* pUserData) 333{ 334#ifdef WIN32 335 char msg_flags[30]; 336 char buf[2048]; 337 338 print_msg_flags(msgFlags, msg_flags); 339 _snprintf(buf, sizeof(buf) - 1, "%s (%s): object: 0x%" PRIxPTR " type: %d location: " PRINTF_SIZE_T_SPECIFIER " msgCode: %d: %s\n", 340 pLayerPrefix, msg_flags, (size_t)srcObject, objType, location, msgCode, pMsg); 341 342 OutputDebugString(buf); 343#endif 344 345 return false; 346} 347 348#endif // LAYER_LOGGING_H 349