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