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