1 /* Copyright (c) 2015-2019 The Khronos Group Inc. 2 * Copyright (c) 2015-2019 Valve Corporation 3 * Copyright (c) 2015-2019 LunarG, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 * Author: Courtney Goeltzenleuchter <courtney (at) LunarG.com> 18 * Author: Tobin Ehlis <tobin (at) lunarg.com> 19 * Author: Mark Young <marky (at) lunarg.com> 20 * Author: Dave Houlton <daveh (at) lunarg.com> 21 * 22 */ 23 24 #ifndef LAYER_LOGGING_H 25 #define LAYER_LOGGING_H 26 27 #include "vk_loader_layer.h" 28 #include "vk_layer_config.h" 29 #include "vk_layer_data.h" 30 #include "vk_loader_platform.h" 31 #include "vulkan/vk_layer.h" 32 #include "vk_object_types.h" 33 #include "vk_validation_error_messages.h" 34 #include "vk_layer_dispatch_table.h" 35 #include <mutex> 36 #include <signal.h> 37 #include <cinttypes> 38 #include <stdarg.h> 39 #include <stdbool.h> 40 #include <stdio.h> 41 #include <unordered_map> 42 #include <vector> 43 #include <sstream> 44 #include <string> 45 46 // Suppress unused warning on Linux 47 #if defined(__GNUC__) 48 #define DECORATE_UNUSED __attribute__((unused)) 49 #else 50 #define DECORATE_UNUSED 51 #endif 52 53 #if defined __ANDROID__ 54 #include <android/log.h> 55 #define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "VALIDATION", __VA_ARGS__)) 56 #else 57 #define LOGCONSOLE(...) \ 58 { \ 59 printf(__VA_ARGS__); \ 60 printf("\n"); \ 61 } 62 #endif 63 64 static const char DECORATE_UNUSED *kVUIDUndefined = "VUID_Undefined"; 65 66 #undef DECORATE_UNUSED 67 68 // TODO: Could be autogenerated for the specific handles for extra type safety... 69 template <typename HANDLE_T> 70 static inline uint64_t HandleToUint64(HANDLE_T *h) { 71 return reinterpret_cast<uint64_t>(h); 72 } 73 74 static inline uint64_t HandleToUint64(uint64_t h) { return h; } 75 76 // Data we store per label for logging 77 typedef struct _LoggingLabelData { 78 std::string name; 79 float color[4]; 80 } LoggingLabelData; 81 82 typedef struct _debug_report_data { 83 VkLayerDbgFunctionNode *debug_callback_list{nullptr}; 84 VkLayerDbgFunctionNode *default_debug_callback_list{nullptr}; 85 VkDebugUtilsMessageSeverityFlagsEXT active_severities{0}; 86 VkDebugUtilsMessageTypeFlagsEXT active_types{0}; 87 bool g_DEBUG_REPORT{false}; 88 bool g_DEBUG_UTILS{false}; 89 bool queueLabelHasInsert{false}; 90 bool cmdBufLabelHasInsert{false}; 91 std::unordered_map<uint64_t, std::string> debugObjectNameMap; 92 std::unordered_map<uint64_t, std::string> debugUtilsObjectNameMap; 93 std::unordered_map<VkQueue, std::vector<LoggingLabelData>> debugUtilsQueueLabels; 94 std::unordered_map<VkCommandBuffer, std::vector<LoggingLabelData>> debugUtilsCmdBufLabels; 95 // This mutex is defined as mutable since the normal usage for a debug report object is as 'const'. The mutable keyword allows 96 // the layers to continue this pattern, but also allows them to use/change this specific member for synchronization purposes. 97 mutable std::mutex debug_report_mutex; 98 99 void DebugReportSetUtilsObjectName(const VkDebugUtilsObjectNameInfoEXT *pNameInfo) { 100 std::unique_lock<std::mutex> lock(debug_report_mutex); 101 if (pNameInfo->pObjectName) { 102 debugUtilsObjectNameMap[pNameInfo->objectHandle] = pNameInfo->pObjectName; 103 } else { 104 debugUtilsObjectNameMap.erase(pNameInfo->objectHandle); 105 } 106 } 107 108 void DebugReportSetMarkerObjectName(const VkDebugMarkerObjectNameInfoEXT *pNameInfo) { 109 std::unique_lock<std::mutex> lock(debug_report_mutex); 110 if (pNameInfo->pObjectName) { 111 debugObjectNameMap[pNameInfo->object] = pNameInfo->pObjectName; 112 } else { 113 debugObjectNameMap.erase(pNameInfo->object); 114 } 115 } 116 117 std::string DebugReportGetUtilsObjectName(const uint64_t object) const { 118 std::string label = ""; 119 const auto utils_name_iter = debugUtilsObjectNameMap.find(object); 120 if (utils_name_iter != debugUtilsObjectNameMap.end()) { 121 label = utils_name_iter->second; 122 } 123 return label; 124 } 125 126 std::string DebugReportGetMarkerObjectName(const uint64_t object) const { 127 std::string label = ""; 128 const auto marker_name_iter = debugObjectNameMap.find(object); 129 if (marker_name_iter != debugObjectNameMap.end()) { 130 label = marker_name_iter->second; 131 } 132 return label; 133 } 134 135 template <typename HANDLE_T> 136 std::string FormatHandle(HANDLE_T *h) const { 137 return FormatHandle(HandleToUint64(h)); 138 } 139 140 std::string FormatHandle(uint64_t h) const { 141 char uint64_string[64]; 142 sprintf(uint64_string, "0x%" PRIxLEAST64, h); 143 std::string ret = uint64_string; 144 145 std::string name = DebugReportGetUtilsObjectName(h); 146 if (name.empty()) { 147 name = DebugReportGetMarkerObjectName(h); 148 } 149 if (!name.empty()) { 150 ret.append("["); 151 ret.append(name); 152 ret.append("]"); 153 } 154 return ret; 155 } 156 157 } debug_report_data; 158 159 template debug_report_data *GetLayerDataPtr<debug_report_data>(void *data_key, 160 std::unordered_map<void *, debug_report_data *> &data_map); 161 162 static inline void DebugReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec, 163 VkDebugUtilsMessageSeverityFlagsEXT *da_severity, 164 VkDebugUtilsMessageTypeFlagsEXT *da_type) { 165 *da_severity = 0; 166 *da_type = 0; 167 // If it's explicitly listed as a performance warning, treat it as a performance message. 168 // Otherwise, treat it as a validation issue. 169 if ((dr_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0) { 170 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; 171 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; 172 } 173 if ((dr_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0) { 174 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; 175 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; 176 } 177 if ((dr_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0) { 178 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; 179 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; 180 } 181 if ((dr_flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) != 0) { 182 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; 183 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; 184 } 185 if ((dr_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) { 186 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; 187 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; 188 } 189 } 190 191 // Forward Declarations 192 static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type, 193 uint64_t src_object, size_t location, const char *layer_prefix, const char *message, 194 const char *text_vuid); 195 196 // Add a debug message callback node structure to the specified callback linked list 197 static inline void AddDebugCallbackNode(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head, 198 VkLayerDbgFunctionNode *new_node) { 199 new_node->pNext = *list_head; 200 *list_head = new_node; 201 } 202 203 // Remove specified debug messenger node structure from the specified linked list 204 static inline void RemoveDebugUtilsMessenger(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head, 205 VkDebugUtilsMessengerEXT messenger) { 206 VkLayerDbgFunctionNode *cur_callback = *list_head; 207 VkLayerDbgFunctionNode *prev_callback = nullptr; 208 bool matched = false; 209 VkFlags local_severities = 0; 210 VkFlags local_types = 0; 211 212 while (cur_callback) { 213 if (cur_callback->is_messenger) { 214 // If it's actually a messenger, then set it up for deletion. 215 if (cur_callback->messenger.messenger == messenger) { 216 matched = true; 217 if (*list_head == cur_callback) { 218 *list_head = cur_callback->pNext; 219 } else { 220 assert(nullptr != prev_callback); 221 prev_callback->pNext = cur_callback->pNext; 222 } 223 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, 224 reinterpret_cast<uint64_t &>(cur_callback->messenger.messenger), 0, "DebugUtilsMessenger", 225 "Destroyed messenger\n", kVUIDUndefined); 226 } else { 227 // If it's not the one we're looking for, just keep the types/severities 228 local_severities |= cur_callback->messenger.messageSeverity; 229 local_types |= cur_callback->messenger.messageType; 230 } 231 } else { 232 // If it's not a messenger, just keep the types/severities 233 VkFlags this_severities = 0; 234 VkFlags this_types = 0; 235 DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types); 236 local_severities |= this_severities; 237 local_types |= this_types; 238 } 239 if (matched) { 240 free(cur_callback); 241 matched = false; 242 // Intentionally keep the last prev_callback, but select the proper cur_callback 243 if (nullptr != prev_callback) { 244 cur_callback = prev_callback->pNext; 245 } else { 246 cur_callback = *list_head; 247 } 248 } else { 249 prev_callback = cur_callback; 250 cur_callback = cur_callback->pNext; 251 } 252 } 253 debug_data->active_severities = local_severities; 254 debug_data->active_types = local_types; 255 } 256 257 // Remove specified debug message callback node structure from the specified callback linked list 258 static inline void RemoveDebugUtilsMessageCallback(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head, 259 VkDebugReportCallbackEXT callback) { 260 VkLayerDbgFunctionNode *cur_callback = *list_head; 261 VkLayerDbgFunctionNode *prev_callback = nullptr; 262 bool matched = false; 263 VkFlags local_severities = 0; 264 VkFlags local_types = 0; 265 266 while (cur_callback) { 267 if (!cur_callback->is_messenger) { 268 // If it's actually a callback, then set it up for deletion. 269 if (cur_callback->report.msgCallback == callback) { 270 matched = true; 271 if (*list_head == cur_callback) { 272 *list_head = cur_callback->pNext; 273 } else { 274 assert(nullptr != prev_callback); 275 prev_callback->pNext = cur_callback->pNext; 276 } 277 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, 278 reinterpret_cast<uint64_t &>(cur_callback->report.msgCallback), 0, "DebugReport", 279 "Destroyed callback\n", kVUIDUndefined); 280 } else { 281 // If it's not the one we're looking for, just keep the types/severities 282 VkFlags this_severities = 0; 283 VkFlags this_types = 0; 284 DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types); 285 local_severities |= this_severities; 286 local_types |= this_types; 287 } 288 } else { 289 // If it's not a callback, just keep the types/severities 290 local_severities |= cur_callback->messenger.messageSeverity; 291 local_types |= cur_callback->messenger.messageType; 292 } 293 if (matched) { 294 free(cur_callback); 295 matched = false; 296 // Intentionally keep the last prev_callback, but select the proper cur_callback 297 if (nullptr != prev_callback) { 298 cur_callback = prev_callback->pNext; 299 } else { 300 cur_callback = *list_head; 301 } 302 } else { 303 prev_callback = cur_callback; 304 cur_callback = cur_callback->pNext; 305 } 306 } 307 debug_data->active_severities = local_severities; 308 debug_data->active_types = local_types; 309 } 310 311 // Removes all debug callback function nodes from the specified callback linked lists and frees their resources 312 static inline void RemoveAllMessageCallbacks(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head) { 313 VkLayerDbgFunctionNode *current_callback = *list_head; 314 VkLayerDbgFunctionNode *prev_callback = current_callback; 315 316 while (current_callback) { 317 prev_callback = current_callback->pNext; 318 if (!current_callback->is_messenger) { 319 debug_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, 320 (uint64_t)current_callback->report.msgCallback, 0, "DebugReport", 321 "Debug Report callbacks not removed before DestroyInstance", kVUIDUndefined); 322 } else { 323 debug_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, 324 (uint64_t)current_callback->messenger.messenger, 0, "Messenger", 325 "Debug messengers not removed before DestroyInstance", kVUIDUndefined); 326 } 327 free(current_callback); 328 current_callback = prev_callback; 329 } 330 *list_head = NULL; 331 } 332 333 static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type, 334 uint64_t src_object, size_t location, const char *layer_prefix, const char *message, 335 const char *text_vuid) { 336 bool bail = false; 337 VkLayerDbgFunctionNode *layer_dbg_node = NULL; 338 339 if (debug_data->debug_callback_list != NULL) { 340 layer_dbg_node = debug_data->debug_callback_list; 341 } else { 342 layer_dbg_node = debug_data->default_debug_callback_list; 343 } 344 345 VkDebugUtilsMessageSeverityFlagsEXT severity; 346 VkDebugUtilsMessageTypeFlagsEXT types; 347 VkDebugUtilsMessengerCallbackDataEXT callback_data; 348 VkDebugUtilsObjectNameInfoEXT object_name_info; 349 350 // Convert the info to the VK_EXT_debug_utils form in case we need it. 351 DebugReportFlagsToAnnotFlags(msg_flags, true, &severity, &types); 352 object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 353 object_name_info.pNext = NULL; 354 object_name_info.objectType = convertDebugReportObjectToCoreObject(object_type); 355 object_name_info.objectHandle = (uint64_t)(uintptr_t)src_object; 356 object_name_info.pObjectName = NULL; 357 358 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT; 359 callback_data.pNext = NULL; 360 callback_data.flags = 0; 361 callback_data.pMessageIdName = text_vuid; 362 callback_data.messageIdNumber = 0; // deprecated, validation layers use only the pMessageIdName 363 callback_data.pMessage = message; 364 callback_data.queueLabelCount = 0; 365 callback_data.pQueueLabels = NULL; 366 callback_data.cmdBufLabelCount = 0; 367 callback_data.pCmdBufLabels = NULL; 368 callback_data.objectCount = 1; 369 callback_data.pObjects = &object_name_info; 370 371 VkDebugUtilsLabelEXT *queue_labels = nullptr; 372 VkDebugUtilsLabelEXT *cmd_buf_labels = nullptr; 373 std::string new_debug_report_message = ""; 374 std::ostringstream oss; 375 376 if (0 != src_object) { 377 oss << "Object: 0x" << std::hex << src_object; 378 // If this is a queue, add any queue labels to the callback data. 379 if (VK_OBJECT_TYPE_QUEUE == object_name_info.objectType) { 380 auto label_iter = debug_data->debugUtilsQueueLabels.find(reinterpret_cast<VkQueue>(src_object)); 381 if (label_iter != debug_data->debugUtilsQueueLabels.end()) { 382 queue_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()]; 383 if (nullptr != queue_labels) { 384 // Record the labels, but record them in reverse order since we want the 385 // most recent at the top. 386 uint32_t label_size = static_cast<uint32_t>(label_iter->second.size()); 387 uint32_t last_index = label_size - 1; 388 for (uint32_t label = 0; label < label_size; ++label) { 389 queue_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; 390 queue_labels[last_index - label].pNext = nullptr; 391 queue_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str(); 392 queue_labels[last_index - label].color[0] = label_iter->second[label].color[0]; 393 queue_labels[last_index - label].color[1] = label_iter->second[label].color[1]; 394 queue_labels[last_index - label].color[2] = label_iter->second[label].color[2]; 395 queue_labels[last_index - label].color[3] = label_iter->second[label].color[3]; 396 } 397 callback_data.queueLabelCount = label_size; 398 callback_data.pQueueLabels = queue_labels; 399 } 400 } 401 // If this is a command buffer, add any command buffer labels to the callback data. 402 } else if (VK_OBJECT_TYPE_COMMAND_BUFFER == object_name_info.objectType) { 403 auto label_iter = debug_data->debugUtilsCmdBufLabels.find(reinterpret_cast<VkCommandBuffer>(src_object)); 404 if (label_iter != debug_data->debugUtilsCmdBufLabels.end()) { 405 cmd_buf_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()]; 406 if (nullptr != cmd_buf_labels) { 407 // Record the labels, but record them in reverse order since we want the 408 // most recent at the top. 409 uint32_t label_size = static_cast<uint32_t>(label_iter->second.size()); 410 uint32_t last_index = label_size - 1; 411 for (uint32_t label = 0; label < label_size; ++label) { 412 cmd_buf_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; 413 cmd_buf_labels[last_index - label].pNext = nullptr; 414 cmd_buf_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str(); 415 cmd_buf_labels[last_index - label].color[0] = label_iter->second[label].color[0]; 416 cmd_buf_labels[last_index - label].color[1] = label_iter->second[label].color[1]; 417 cmd_buf_labels[last_index - label].color[2] = label_iter->second[label].color[2]; 418 cmd_buf_labels[last_index - label].color[3] = label_iter->second[label].color[3]; 419 } 420 callback_data.cmdBufLabelCount = label_size; 421 callback_data.pCmdBufLabels = cmd_buf_labels; 422 } 423 } 424 } 425 426 // Look for any debug utils or marker names to use for this object 427 std::string label = debug_data->DebugReportGetUtilsObjectName(src_object); 428 if (label.empty()) { 429 label = debug_data->DebugReportGetMarkerObjectName(src_object); 430 } 431 if (!label.empty()) { 432 object_name_info.pObjectName = label.c_str(); 433 oss << " (Name = " << label << " : Type = "; 434 } else { 435 oss << " (Type = "; 436 } 437 oss << std::to_string(object_type) << ")"; 438 } else { 439 oss << "Object: VK_NULL_HANDLE (Type = " << std::to_string(object_type) << ")"; 440 } 441 new_debug_report_message += oss.str(); 442 new_debug_report_message += " | "; 443 new_debug_report_message += message; 444 445 while (layer_dbg_node) { 446 // If the app uses the VK_EXT_debug_report extension, call all of those registered callbacks. 447 if (!layer_dbg_node->is_messenger && (layer_dbg_node->report.msgFlags & msg_flags)) { 448 if (text_vuid != nullptr) { 449 // If a text vuid is supplied for the old debug report extension, prepend it to the message string 450 new_debug_report_message.insert(0, " ] "); 451 new_debug_report_message.insert(0, text_vuid); 452 new_debug_report_message.insert(0, " [ "); 453 } 454 455 if (layer_dbg_node->report.pfnMsgCallback(msg_flags, object_type, src_object, location, 0, layer_prefix, 456 new_debug_report_message.c_str(), layer_dbg_node->pUserData)) { 457 bail = true; 458 } 459 // If the app uses the VK_EXT_debug_utils extension, call all of those registered callbacks. 460 } else if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & severity) && 461 (layer_dbg_node->messenger.messageType & types)) { 462 if (layer_dbg_node->messenger.pfnUserCallback(static_cast<VkDebugUtilsMessageSeverityFlagBitsEXT>(severity), types, 463 &callback_data, layer_dbg_node->pUserData)) { 464 bail = true; 465 } 466 } 467 layer_dbg_node = layer_dbg_node->pNext; 468 } 469 470 if (nullptr != queue_labels) { 471 delete[] queue_labels; 472 } 473 if (nullptr != cmd_buf_labels) { 474 delete[] cmd_buf_labels; 475 } 476 477 return bail; 478 } 479 480 static inline void DebugAnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity, 481 VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags) { 482 *dr_flags = 0; 483 484 if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) { 485 *dr_flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT; 486 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) { 487 if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) { 488 *dr_flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; 489 } else { 490 *dr_flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT; 491 } 492 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) { 493 *dr_flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT; 494 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) { 495 *dr_flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT; 496 } 497 } 498 499 static inline bool debug_messenger_log_msg(const debug_report_data *debug_data, 500 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, 501 VkDebugUtilsMessageTypeFlagsEXT message_type, 502 VkDebugUtilsMessengerCallbackDataEXT *callback_data, 503 const VkDebugUtilsMessengerEXT *messenger) { 504 bool bail = false; 505 VkLayerDbgFunctionNode *layer_dbg_node = NULL; 506 507 if (debug_data->debug_callback_list != NULL) { 508 layer_dbg_node = debug_data->debug_callback_list; 509 } else { 510 layer_dbg_node = debug_data->default_debug_callback_list; 511 } 512 513 VkDebugReportFlagsEXT object_flags = 0; 514 515 DebugAnnotFlagsToReportFlags(message_severity, message_type, &object_flags); 516 517 VkDebugUtilsObjectNameInfoEXT object_name_info; 518 object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 519 object_name_info.pNext = NULL; 520 object_name_info.objectType = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT; 521 object_name_info.objectHandle = HandleToUint64(*messenger); 522 object_name_info.pObjectName = NULL; 523 callback_data->pObjects = &object_name_info; 524 callback_data->objectCount = 1; 525 526 while (layer_dbg_node) { 527 if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & message_severity) && 528 (layer_dbg_node->messenger.messageType & message_type)) { 529 std::string messenger_label = debug_data->DebugReportGetUtilsObjectName(object_name_info.objectHandle); 530 if (!messenger_label.empty()) { 531 object_name_info.pObjectName = messenger_label.c_str(); 532 } 533 if (layer_dbg_node->messenger.pfnUserCallback(message_severity, message_type, callback_data, 534 layer_dbg_node->pUserData)) { 535 bail = true; 536 } 537 } else if (!layer_dbg_node->is_messenger && layer_dbg_node->report.msgFlags & object_flags) { 538 VkDebugReportObjectTypeEXT object_type = convertCoreObjectToDebugReportObject(callback_data->pObjects[0].objectType); 539 std::string marker_label = debug_data->DebugReportGetMarkerObjectName(object_name_info.objectHandle); 540 if (marker_label.empty()) { 541 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0, 542 callback_data->messageIdNumber, callback_data->pMessageIdName, 543 callback_data->pMessage, layer_dbg_node->pUserData)) { 544 bail = true; 545 } 546 } else { 547 std::string newMsg = "SrcObject name = " + marker_label; 548 newMsg.append(" "); 549 newMsg.append(callback_data->pMessage); 550 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0, 551 callback_data->messageIdNumber, callback_data->pMessageIdName, 552 newMsg.c_str(), layer_dbg_node->pUserData)) { 553 bail = true; 554 } 555 } 556 } 557 layer_dbg_node = layer_dbg_node->pNext; 558 } 559 560 return bail; 561 } 562 563 static inline debug_report_data *debug_utils_create_instance( 564 VkLayerInstanceDispatchTable *table, VkInstance inst, uint32_t extension_count, 565 const char *const *enabled_extensions) // layer or extension name to be enabled 566 { 567 debug_report_data *debug_data = new debug_report_data; 568 for (uint32_t i = 0; i < extension_count; i++) { 569 if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) { 570 debug_data->g_DEBUG_REPORT = true; 571 } else if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) { 572 debug_data->g_DEBUG_UTILS = true; 573 } 574 } 575 return debug_data; 576 } 577 578 static inline void layer_debug_utils_destroy_instance(debug_report_data *debug_data) { 579 if (debug_data) { 580 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex); 581 RemoveAllMessageCallbacks(debug_data, &debug_data->default_debug_callback_list); 582 RemoveAllMessageCallbacks(debug_data, &debug_data->debug_callback_list); 583 lock.unlock(); 584 delete (debug_data); 585 } 586 } 587 588 static inline debug_report_data *layer_debug_utils_create_device(debug_report_data *instance_debug_data, VkDevice device) { 589 // DEBUG_REPORT shares data between Instance and Device, 590 // so just return instance's data pointer 591 return instance_debug_data; 592 } 593 594 static inline void layer_debug_utils_destroy_device(VkDevice device) { 595 // Nothing to do since we're using instance data record 596 } 597 598 static inline void layer_destroy_messenger_callback(debug_report_data *debug_data, VkDebugUtilsMessengerEXT messenger, 599 const VkAllocationCallbacks *allocator) { 600 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex); 601 RemoveDebugUtilsMessenger(debug_data, &debug_data->debug_callback_list, messenger); 602 RemoveDebugUtilsMessenger(debug_data, &debug_data->default_debug_callback_list, messenger); 603 } 604 605 static inline VkResult layer_create_messenger_callback(debug_report_data *debug_data, bool default_callback, 606 const VkDebugUtilsMessengerCreateInfoEXT *create_info, 607 const VkAllocationCallbacks *allocator, 608 VkDebugUtilsMessengerEXT *messenger) { 609 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex); 610 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode)); 611 if (!pNewDbgFuncNode) return VK_ERROR_OUT_OF_HOST_MEMORY; 612 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode)); 613 pNewDbgFuncNode->is_messenger = true; 614 615 // Handle of 0 is logging_callback so use allocated Node address as unique handle 616 if (!(*messenger)) *messenger = (VkDebugUtilsMessengerEXT)pNewDbgFuncNode; 617 pNewDbgFuncNode->messenger.messenger = *messenger; 618 pNewDbgFuncNode->messenger.pfnUserCallback = create_info->pfnUserCallback; 619 pNewDbgFuncNode->messenger.messageSeverity = create_info->messageSeverity; 620 pNewDbgFuncNode->messenger.messageType = create_info->messageType; 621 pNewDbgFuncNode->pUserData = create_info->pUserData; 622 623 debug_data->active_severities |= create_info->messageSeverity; 624 debug_data->active_types |= create_info->messageType; 625 if (default_callback) { 626 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode); 627 } else { 628 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode); 629 } 630 631 VkDebugUtilsMessengerCallbackDataEXT callback_data = {}; 632 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT; 633 callback_data.pNext = NULL; 634 callback_data.flags = 0; 635 callback_data.pMessageIdName = "Layer Internal Message"; 636 callback_data.messageIdNumber = 0; 637 callback_data.pMessage = "Added messenger"; 638 callback_data.queueLabelCount = 0; 639 callback_data.pQueueLabels = NULL; 640 callback_data.cmdBufLabelCount = 0; 641 callback_data.pCmdBufLabels = NULL; 642 callback_data.objectCount = 0; 643 callback_data.pObjects = NULL; 644 debug_messenger_log_msg(debug_data, VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, 645 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, &callback_data, messenger); 646 return VK_SUCCESS; 647 } 648 649 static inline void layer_destroy_report_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback, 650 const VkAllocationCallbacks *allocator) { 651 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex); 652 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->debug_callback_list, callback); 653 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->default_debug_callback_list, callback); 654 } 655 656 static inline VkResult layer_create_report_callback(debug_report_data *debug_data, bool default_callback, 657 const VkDebugReportCallbackCreateInfoEXT *create_info, 658 const VkAllocationCallbacks *allocator, VkDebugReportCallbackEXT *callback) { 659 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex); 660 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode)); 661 if (!pNewDbgFuncNode) { 662 return VK_ERROR_OUT_OF_HOST_MEMORY; 663 } 664 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode)); 665 pNewDbgFuncNode->is_messenger = false; 666 667 // Handle of 0 is logging_callback so use allocated Node address as unique handle 668 if (!(*callback)) *callback = (VkDebugReportCallbackEXT)pNewDbgFuncNode; 669 pNewDbgFuncNode->report.msgCallback = *callback; 670 pNewDbgFuncNode->report.pfnMsgCallback = create_info->pfnCallback; 671 pNewDbgFuncNode->report.msgFlags = create_info->flags; 672 pNewDbgFuncNode->pUserData = create_info->pUserData; 673 674 VkFlags local_severity = 0; 675 VkFlags local_type = 0; 676 DebugReportFlagsToAnnotFlags(create_info->flags, true, &local_severity, &local_type); 677 debug_data->active_severities |= local_severity; 678 debug_data->active_types |= local_type; 679 if (default_callback) { 680 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode); 681 } else { 682 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode); 683 } 684 685 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, (uint64_t)*callback, 0, 686 "DebugReport", "Added callback", kVUIDUndefined); 687 return VK_SUCCESS; 688 } 689 690 static inline PFN_vkVoidFunction debug_utils_get_instance_proc_addr(debug_report_data *debug_data, const char *func_name) { 691 if (!debug_data) { 692 return NULL; 693 } 694 if (debug_data->g_DEBUG_REPORT) { 695 if (!strcmp(func_name, "vkCreateDebugReportCallbackEXT")) { 696 return (PFN_vkVoidFunction)vkCreateDebugReportCallbackEXT; 697 } 698 if (!strcmp(func_name, "vkDestroyDebugReportCallbackEXT")) { 699 return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT; 700 } 701 if (!strcmp(func_name, "vkDebugReportMessageEXT")) { 702 return (PFN_vkVoidFunction)vkDebugReportMessageEXT; 703 } 704 } 705 if (debug_data->g_DEBUG_UTILS) { 706 if (!strcmp(func_name, "vkCreateDebugUtilsMessengerEXT")) { 707 return (PFN_vkVoidFunction)vkCreateDebugUtilsMessengerEXT; 708 } 709 if (!strcmp(func_name, "vkDestroyDebugUtilsMessengerEXT")) { 710 return (PFN_vkVoidFunction)vkDestroyDebugUtilsMessengerEXT; 711 } 712 if (!strcmp(func_name, "vkSubmitDebugUtilsMessageEXT")) { 713 return (PFN_vkVoidFunction)vkSubmitDebugUtilsMessageEXT; 714 } 715 } 716 return NULL; 717 } 718 719 // This utility (called at vkCreateInstance() time), looks at a pNext chain. 720 // It counts any VkDebugReportCallbackCreateInfoEXT structs that it finds. It 721 // then allocates an array that can hold that many structs, as well as that 722 // many VkDebugReportCallbackEXT handles. It then copies each 723 // VkDebugReportCallbackCreateInfoEXT, and initializes each handle. 724 static inline VkResult layer_copy_tmp_report_callbacks(const void *pChain, uint32_t *num_callbacks, 725 VkDebugReportCallbackCreateInfoEXT **infos, 726 VkDebugReportCallbackEXT **callbacks) { 727 uint32_t n = *num_callbacks = 0; 728 729 const void *pNext = pChain; 730 while (pNext) { 731 // 1st, count the number VkDebugReportCallbackCreateInfoEXT: 732 if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) { 733 n++; 734 } 735 pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext; 736 } 737 if (n == 0) { 738 return VK_SUCCESS; 739 } 740 741 // 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT: 742 VkDebugReportCallbackCreateInfoEXT *pInfos = *infos = 743 ((VkDebugReportCallbackCreateInfoEXT *)malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT))); 744 if (!pInfos) { 745 return VK_ERROR_OUT_OF_HOST_MEMORY; 746 } 747 // 3rd, allocate memory for a unique handle for each callback: 748 VkDebugReportCallbackEXT *pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)malloc(n * sizeof(VkDebugReportCallbackEXT))); 749 if (!pCallbacks) { 750 free(pInfos); 751 return VK_ERROR_OUT_OF_HOST_MEMORY; 752 } 753 // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by 754 // vkDestroyInstance, and assign a unique handle to each callback (just 755 // use the address of the copied VkDebugReportCallbackCreateInfoEXT): 756 pNext = pChain; 757 while (pNext) { 758 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) { 759 memcpy(pInfos, pNext, sizeof(VkDebugReportCallbackCreateInfoEXT)); 760 *pCallbacks++ = (VkDebugReportCallbackEXT)pInfos++; 761 } 762 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext; 763 } 764 765 *num_callbacks = n; 766 return VK_SUCCESS; 767 } 768 769 // This utility frees the arrays allocated by layer_copy_tmp_report_callbacks() 770 static inline void layer_free_tmp_report_callbacks(VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) { 771 free(infos); 772 free(callbacks); 773 } 774 775 // This utility enables all of the VkDebugReportCallbackCreateInfoEXT structs 776 // that were copied by layer_copy_tmp_report_callbacks() 777 static inline VkResult layer_enable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks, 778 VkDebugReportCallbackCreateInfoEXT *infos, 779 VkDebugReportCallbackEXT *callbacks) { 780 VkResult rtn = VK_SUCCESS; 781 for (uint32_t i = 0; i < num_callbacks; i++) { 782 rtn = layer_create_report_callback(debug_data, false, &infos[i], NULL, &callbacks[i]); 783 if (rtn != VK_SUCCESS) { 784 for (uint32_t j = 0; j < i; j++) { 785 layer_destroy_report_callback(debug_data, callbacks[j], NULL); 786 } 787 return rtn; 788 } 789 } 790 return rtn; 791 } 792 793 // This utility disables all of the VkDebugReportCallbackCreateInfoEXT structs 794 // that were copied by layer_copy_tmp_report_callbacks() 795 static inline void layer_disable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks, 796 VkDebugReportCallbackEXT *callbacks) { 797 for (uint32_t i = 0; i < num_callbacks; i++) { 798 layer_destroy_report_callback(debug_data, callbacks[i], NULL); 799 } 800 } 801 802 // This utility (called at vkCreateInstance() time), looks at a pNext chain. 803 // It counts any VkDebugUtilsMessengerCreateInfoEXT structs that it finds. It 804 // then allocates an array that can hold that many structs, as well as that 805 // many VkDebugUtilsMessengerEXT handles. It then copies each 806 // VkDebugUtilsMessengerCreateInfoEXT, and initializes each handle. 807 static inline VkResult layer_copy_tmp_debug_messengers(const void *pChain, uint32_t *num_messengers, 808 VkDebugUtilsMessengerCreateInfoEXT **infos, 809 VkDebugUtilsMessengerEXT **messengers) { 810 uint32_t n = *num_messengers = 0; 811 812 const void *pNext = pChain; 813 while (pNext) { 814 // 1st, count the number VkDebugUtilsMessengerCreateInfoEXT: 815 if (((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) { 816 n++; 817 } 818 pNext = (void *)((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->pNext; 819 } 820 if (n == 0) { 821 return VK_SUCCESS; 822 } 823 824 // 2nd, allocate memory for each VkDebugUtilsMessengerCreateInfoEXT: 825 VkDebugUtilsMessengerCreateInfoEXT *pInfos = *infos = 826 ((VkDebugUtilsMessengerCreateInfoEXT *)malloc(n * sizeof(VkDebugUtilsMessengerCreateInfoEXT))); 827 if (!pInfos) { 828 return VK_ERROR_OUT_OF_HOST_MEMORY; 829 } 830 // 3rd, allocate memory for a unique handle for each messenger: 831 VkDebugUtilsMessengerEXT *pMessengers = *messengers = 832 ((VkDebugUtilsMessengerEXT *)malloc(n * sizeof(VkDebugUtilsMessengerEXT))); 833 if (!pMessengers) { 834 free(pInfos); 835 return VK_ERROR_OUT_OF_HOST_MEMORY; 836 } 837 // 4th, copy each VkDebugUtilsMessengerCreateInfoEXT for use by 838 // vkDestroyInstance, and assign a unique handle to each callback (just 839 // use the address of the copied VkDebugUtilsMessengerCreateInfoEXT): 840 pNext = pChain; 841 while (pNext) { 842 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) { 843 memcpy(pInfos, pNext, sizeof(VkDebugUtilsMessengerCreateInfoEXT)); 844 *pMessengers++ = (VkDebugUtilsMessengerEXT)pInfos++; 845 } 846 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext; 847 } 848 849 *num_messengers = n; 850 return VK_SUCCESS; 851 } 852 853 // This utility frees the arrays allocated by layer_copy_tmp_debug_messengers() 854 static inline void layer_free_tmp_debug_messengers(VkDebugUtilsMessengerCreateInfoEXT *infos, 855 VkDebugUtilsMessengerEXT *messengers) { 856 free(infos); 857 free(messengers); 858 } 859 860 // This utility enables all of the VkDebugUtilsMessengerCreateInfoEXT structs 861 // that were copied by layer_copy_tmp_debug_messengers() 862 static inline VkResult layer_enable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers, 863 VkDebugUtilsMessengerCreateInfoEXT *infos, 864 VkDebugUtilsMessengerEXT *messengers) { 865 VkResult rtn = VK_SUCCESS; 866 for (uint32_t i = 0; i < num_messengers; i++) { 867 rtn = layer_create_messenger_callback(debug_data, false, &infos[i], NULL, &messengers[i]); 868 if (rtn != VK_SUCCESS) { 869 for (uint32_t j = 0; j < i; j++) { 870 layer_destroy_messenger_callback(debug_data, messengers[j], NULL); 871 } 872 return rtn; 873 } 874 } 875 return rtn; 876 } 877 878 // This utility disables all of the VkDebugUtilsMessengerCreateInfoEXT structs 879 // that were copied by layer_copy_tmp_debug_messengers() 880 static inline void layer_disable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers, 881 VkDebugUtilsMessengerEXT *messengers) { 882 for (uint32_t i = 0; i < num_messengers; i++) { 883 layer_destroy_messenger_callback(debug_data, messengers[i], NULL); 884 } 885 } 886 887 // Checks if the message will get logged. 888 // Allows layer to defer collecting & formating data if the 889 // message will be discarded. 890 static inline bool will_log_msg(debug_report_data *debug_data, VkFlags msg_flags) { 891 VkFlags local_severity = 0; 892 VkFlags local_type = 0; 893 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type); 894 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) { 895 // Message is not wanted 896 return false; 897 } 898 899 return true; 900 } 901 #ifndef WIN32 902 static inline int string_sprintf(std::string *output, const char *fmt, ...) __attribute__((format(printf, 2, 3))); 903 #endif 904 static inline int string_sprintf(std::string *output, const char *fmt, ...) { 905 std::string &formatted = *output; 906 va_list argptr; 907 va_start(argptr, fmt); 908 int reserve = vsnprintf(nullptr, 0, fmt, argptr); 909 va_end(argptr); 910 formatted.reserve(reserve + 1); // Set the storage length long enough to hold the output + null 911 formatted.resize(reserve); // Set the *logical* length to be what vsprintf will write 912 va_start(argptr, fmt); 913 int result = vsnprintf((char *)formatted.data(), formatted.capacity(), fmt, argptr); 914 va_end(argptr); 915 assert(result == reserve); 916 assert((formatted.size() == strlen(formatted.c_str()))); 917 return result; 918 } 919 920 #ifdef WIN32 921 static inline int vasprintf(char **strp, char const *fmt, va_list ap) { 922 *strp = nullptr; 923 int size = _vscprintf(fmt, ap); 924 if (size >= 0) { 925 *strp = (char *)malloc(size + 1); 926 if (!*strp) { 927 return -1; 928 } 929 _vsnprintf(*strp, size + 1, fmt, ap); 930 } 931 return size; 932 } 933 #endif 934 935 // Output log message via DEBUG_REPORT. Takes format and variable arg list so that output string is only computed if a message 936 // needs to be logged 937 #ifndef WIN32 938 static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type, 939 uint64_t src_object, std::string vuid_text, const char *format, ...) 940 __attribute__((format(printf, 6, 7))); 941 #endif 942 static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type, 943 uint64_t src_object, std::string vuid_text, const char *format, ...) { 944 if (!debug_data) return false; 945 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex); 946 VkFlags local_severity = 0; 947 VkFlags local_type = 0; 948 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type); 949 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) { 950 // Message is not wanted 951 return false; 952 } 953 954 va_list argptr; 955 va_start(argptr, format); 956 char *str; 957 if (-1 == vasprintf(&str, format, argptr)) { 958 // On failure, glibc vasprintf leaves str undefined 959 str = nullptr; 960 } 961 va_end(argptr); 962 963 std::string str_plus_spec_text(str ? str : "Allocation failure"); 964 965 // Append the spec error text to the error message, unless it's an UNASSIGNED or UNDEFINED vuid 966 if ((vuid_text.find("UNASSIGNED-") == std::string::npos) && (vuid_text.find(kVUIDUndefined) == std::string::npos)) { 967 // Linear search makes no assumptions about the layout of the string table 968 // This is not fast, but it does not need to be at this point in the error reporting path 969 uint32_t num_vuids = sizeof(vuid_spec_text) / sizeof(vuid_spec_text_pair); 970 const char *spec_text = nullptr; 971 for (uint32_t i = 0; i < num_vuids; i++) { 972 if (0 == strcmp(vuid_text.c_str(), vuid_spec_text[i].vuid)) { 973 spec_text = vuid_spec_text[i].spec_text; 974 break; 975 } 976 } 977 978 if (nullptr == spec_text) { 979 // If this happens, you've hit a VUID string that isn't defined in the spec's json file 980 // Try running 'vk_validation_stats -c' to look for invalid VUID strings in the repo code 981 assert(0); 982 } else { 983 str_plus_spec_text += " The Vulkan spec states: "; 984 str_plus_spec_text += spec_text; 985 } 986 } 987 988 // Append layer prefix with VUID string, pass in recovered legacy numerical VUID 989 bool result = debug_log_msg(debug_data, msg_flags, object_type, src_object, 0, "Validation", str_plus_spec_text.c_str(), 990 vuid_text.c_str()); 991 992 free(str); 993 return result; 994 } 995 996 static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_log_callback(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type, 997 uint64_t src_object, size_t location, int32_t msg_code, 998 const char *layer_prefix, const char *message, void *user_data) { 999 std::ostringstream msg_buffer; 1000 char msg_flag_string[30]; 1001 1002 PrintMessageFlags(msg_flags, msg_flag_string); 1003 1004 msg_buffer << layer_prefix << "(" << msg_flag_string << "): msg_code: " << msg_code << ": " << message << "\n"; 1005 const std::string tmp = msg_buffer.str(); 1006 const char *cstr = tmp.c_str(); 1007 1008 fprintf((FILE *)user_data, "%s", cstr); 1009 fflush((FILE *)user_data); 1010 1011 #if defined __ANDROID__ 1012 LOGCONSOLE("%s", cstr); 1013 #endif 1014 1015 return false; 1016 } 1017 1018 static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_win32_debug_output_msg(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type, 1019 uint64_t src_object, size_t location, int32_t msg_code, 1020 const char *layer_prefix, const char *message, 1021 void *user_data) { 1022 #ifdef WIN32 1023 char msg_flag_string[30]; 1024 char buf[2048]; 1025 1026 PrintMessageFlags(msg_flags, msg_flag_string); 1027 _snprintf(buf, sizeof(buf) - 1, "%s (%s): msg_code: %d: %s\n", layer_prefix, msg_flag_string, msg_code, message); 1028 1029 OutputDebugString(buf); 1030 #endif 1031 1032 return false; 1033 } 1034 1035 static inline VKAPI_ATTR VkBool32 VKAPI_CALL DebugBreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT obj_type, 1036 uint64_t src_object, size_t location, int32_t msg_code, 1037 const char *layer_prefix, const char *message, void *user_data) { 1038 #ifdef WIN32 1039 DebugBreak(); 1040 #else 1041 raise(SIGTRAP); 1042 #endif 1043 1044 return false; 1045 } 1046 1047 static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_log_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, 1048 VkDebugUtilsMessageTypeFlagsEXT message_type, 1049 const VkDebugUtilsMessengerCallbackDataEXT *callback_data, 1050 void *user_data) { 1051 std::ostringstream msg_buffer; 1052 char msg_severity[30]; 1053 char msg_type[30]; 1054 1055 PrintMessageSeverity(message_severity, msg_severity); 1056 PrintMessageType(message_type, msg_type); 1057 1058 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type 1059 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n"; 1060 msg_buffer << " Objects: " << callback_data->objectCount << "\n"; 1061 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) { 1062 msg_buffer << " [" << obj << "] " << std::hex << std::showbase 1063 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase 1064 << callback_data->pObjects[obj].objectType 1065 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL") 1066 << "\n"; 1067 } 1068 const std::string tmp = msg_buffer.str(); 1069 const char *cstr = tmp.c_str(); 1070 fprintf((FILE *)user_data, "%s", cstr); 1071 fflush((FILE *)user_data); 1072 1073 #if defined __ANDROID__ 1074 LOGCONSOLE("%s", cstr); 1075 #endif 1076 1077 return false; 1078 } 1079 1080 static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_win32_debug_output_msg( 1081 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type, 1082 const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data) { 1083 #ifdef WIN32 1084 std::ostringstream msg_buffer; 1085 char msg_severity[30]; 1086 char msg_type[30]; 1087 1088 PrintMessageSeverity(message_severity, msg_severity); 1089 PrintMessageType(message_type, msg_type); 1090 1091 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type 1092 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n"; 1093 msg_buffer << " Objects: " << callback_data->objectCount << "\n"; 1094 1095 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) { 1096 msg_buffer << " [" << obj << "] " << std::hex << std::showbase 1097 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase 1098 << callback_data->pObjects[obj].objectType 1099 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL") 1100 << "\n"; 1101 } 1102 const std::string tmp = msg_buffer.str(); 1103 const char *cstr = tmp.c_str(); 1104 OutputDebugString(cstr); 1105 #endif 1106 1107 return false; 1108 } 1109 1110 // This utility converts from the VkDebugUtilsLabelEXT structure into the logging version of the structure. 1111 // In the logging version, we only record what we absolutely need to convey back to the callbacks. 1112 static inline void InsertLabelIntoLog(const VkDebugUtilsLabelEXT *utils_label, std::vector<LoggingLabelData> &log_vector) { 1113 LoggingLabelData log_label_data = {}; 1114 log_label_data.name = utils_label->pLabelName; 1115 log_label_data.color[0] = utils_label->color[0]; 1116 log_label_data.color[1] = utils_label->color[1]; 1117 log_label_data.color[2] = utils_label->color[2]; 1118 log_label_data.color[3] = utils_label->color[3]; 1119 log_vector.push_back(log_label_data); 1120 } 1121 1122 static inline void BeginQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue, 1123 const VkDebugUtilsLabelEXT *label_info) { 1124 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex); 1125 if (nullptr != label_info && nullptr != label_info->pLabelName) { 1126 auto label_iter = report_data->debugUtilsQueueLabels.find(queue); 1127 if (label_iter == report_data->debugUtilsQueueLabels.end()) { 1128 std::vector<LoggingLabelData> new_queue_labels; 1129 InsertLabelIntoLog(label_info, new_queue_labels); 1130 report_data->debugUtilsQueueLabels.insert({queue, new_queue_labels}); 1131 } else { 1132 // If the last thing was a label insert, we need to pop it off of the label vector before any 1133 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a 1134 // temporary location that exists until the next operation occurs. In this case, a new 1135 // "vkQueueBeginDebugUtilsLabelEXT" has occurred erasing the previous inserted label. 1136 if (report_data->queueLabelHasInsert) { 1137 report_data->queueLabelHasInsert = false; 1138 label_iter->second.pop_back(); 1139 } 1140 InsertLabelIntoLog(label_info, label_iter->second); 1141 } 1142 } 1143 } 1144 1145 static inline void EndQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue) { 1146 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex); 1147 auto label_iter = report_data->debugUtilsQueueLabels.find(queue); 1148 if (label_iter != report_data->debugUtilsQueueLabels.end()) { 1149 // If the last thing was a label insert, we need to pop it off of the label vector before any 1150 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a 1151 // temporary location that exists until the next operation occurs. In this case, a 1152 // "vkQueueEndDebugUtilsLabelEXT" has occurred erasing the inserted label. 1153 if (report_data->queueLabelHasInsert) { 1154 report_data->queueLabelHasInsert = false; 1155 label_iter->second.pop_back(); 1156 } 1157 // Now pop the normal item 1158 label_iter->second.pop_back(); 1159 } 1160 } 1161 1162 static inline void InsertQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue, 1163 const VkDebugUtilsLabelEXT *label_info) { 1164 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex); 1165 if (nullptr != label_info && nullptr != label_info->pLabelName) { 1166 auto label_iter = report_data->debugUtilsQueueLabels.find(queue); 1167 if (label_iter == report_data->debugUtilsQueueLabels.end()) { 1168 std::vector<LoggingLabelData> new_queue_labels; 1169 InsertLabelIntoLog(label_info, new_queue_labels); 1170 report_data->debugUtilsQueueLabels.insert({queue, new_queue_labels}); 1171 } else { 1172 // If the last thing was a label insert, we need to pop it off of the label vector before any 1173 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a 1174 // temporary location that exists until the next operation occurs. In this case, a new 1175 // "vkQueueInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label. 1176 if (report_data->queueLabelHasInsert) { 1177 label_iter->second.pop_back(); 1178 } 1179 // Insert this new label and mark it as one that has been "inserted" so we can remove it on 1180 // the next queue label operation. 1181 InsertLabelIntoLog(label_info, label_iter->second); 1182 report_data->queueLabelHasInsert = true; 1183 } 1184 } 1185 } 1186 1187 static inline void BeginCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer, 1188 const VkDebugUtilsLabelEXT *label_info) { 1189 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex); 1190 if (nullptr != label_info && nullptr != label_info->pLabelName) { 1191 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer); 1192 if (label_iter == report_data->debugUtilsCmdBufLabels.end()) { 1193 std::vector<LoggingLabelData> new_cmdbuf_labels; 1194 InsertLabelIntoLog(label_info, new_cmdbuf_labels); 1195 report_data->debugUtilsCmdBufLabels.insert({command_buffer, new_cmdbuf_labels}); 1196 } else { 1197 // If the last thing was a label insert, we need to pop it off of the label vector before any 1198 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a 1199 // temporary location that exists until the next operation occurs. In this case, a 1200 // "vkCmdBeginDebugUtilsLabelEXT" has occurred erasing the inserted label. 1201 if (report_data->cmdBufLabelHasInsert) { 1202 report_data->cmdBufLabelHasInsert = false; 1203 label_iter->second.pop_back(); 1204 } 1205 InsertLabelIntoLog(label_info, label_iter->second); 1206 } 1207 } 1208 } 1209 1210 static inline void EndCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) { 1211 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex); 1212 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer); 1213 if (label_iter != report_data->debugUtilsCmdBufLabels.end()) { 1214 // If the last thing was a label insert, we need to pop it off of the label vector before any 1215 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a 1216 // temporary location that exists until the next operation occurs. In this case, a 1217 // "vkCmdEndDebugUtilsLabelEXT" has occurred erasing the inserted label. 1218 if (report_data->cmdBufLabelHasInsert) { 1219 report_data->cmdBufLabelHasInsert = false; 1220 label_iter->second.pop_back(); 1221 } 1222 // Guard against unbalanced markers. 1223 if (label_iter->second.size() > 0) { 1224 // Now pop the normal item 1225 label_iter->second.pop_back(); 1226 } 1227 } 1228 } 1229 1230 static inline void InsertCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer, 1231 const VkDebugUtilsLabelEXT *label_info) { 1232 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex); 1233 if (nullptr != label_info && nullptr != label_info->pLabelName) { 1234 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer); 1235 if (label_iter == report_data->debugUtilsCmdBufLabels.end()) { 1236 std::vector<LoggingLabelData> new_cmdbuf_labels; 1237 InsertLabelIntoLog(label_info, new_cmdbuf_labels); 1238 report_data->debugUtilsCmdBufLabels.insert({command_buffer, new_cmdbuf_labels}); 1239 } else { 1240 // If the last thing was a label insert, we need to pop it off of the label vector before any 1241 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a 1242 // temporary location that exists until the next operation occurs. In this case, a new 1243 // "vkCmdInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label. 1244 if (report_data->cmdBufLabelHasInsert) { 1245 label_iter->second.pop_back(); 1246 } 1247 // Insert this new label and mark it as one that has been "inserted" so we can remove it on 1248 // the next command buffer label operation. 1249 InsertLabelIntoLog(label_info, label_iter->second); 1250 report_data->cmdBufLabelHasInsert = true; 1251 } 1252 } 1253 } 1254 1255 #endif // LAYER_LOGGING_H 1256