1/* 2 * Copyright (c) 2015-2021 The Khronos Group Inc. 3 * Copyright (c) 2015-2021 Valve Corporation 4 * Copyright (c) 2015-2021 LunarG, Inc. 5 * Copyright (C) 2015-2016 Google Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> 20 * Author: Jon Ashburn <jon@LunarG.com> 21 * Author: Mark Young <marky@lunarg.com> 22 * Author: Charles Giessen <charles@lunarg.com> 23 * 24 */ 25 26#include <inttypes.h> 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30#if !defined(WIN32) 31#include <signal.h> 32#endif 33 34#include "vulkan/vk_layer.h" 35#include "vk_object_types.h" 36 37#include "allocation.h" 38#include "debug_utils.h" 39#include "log.h" 40#include "loader.h" 41#include "vk_loader_platform.h" 42 43// VK_EXT_debug_report related items 44 45VkResult util_CreateDebugUtilsMessenger(struct loader_instance *inst, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, 46 const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT messenger) { 47 VkLayerDbgFunctionNode *new_dbg_function_node = NULL; 48 49 new_dbg_function_node = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback( 50 pAllocator, inst, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 51 52 if (!new_dbg_function_node) { 53 return VK_ERROR_OUT_OF_HOST_MEMORY; 54 } 55 56 new_dbg_function_node->is_messenger = true; 57 new_dbg_function_node->messenger.messenger = messenger; 58 new_dbg_function_node->messenger.pfnUserCallback = pCreateInfo->pfnUserCallback; 59 new_dbg_function_node->messenger.messageSeverity = pCreateInfo->messageSeverity; 60 new_dbg_function_node->messenger.messageType = pCreateInfo->messageType; 61 new_dbg_function_node->pUserData = pCreateInfo->pUserData; 62 new_dbg_function_node->pNext = inst->instance_only_dbg_function_head; 63 inst->instance_only_dbg_function_head = new_dbg_function_node; 64 inst->current_dbg_function_head = inst->instance_only_dbg_function_head; 65 66 return VK_SUCCESS; 67} 68 69VKAPI_ATTR VkResult VKAPI_CALL debug_utils_CreateDebugUtilsMessengerEXT(VkInstance instance, 70 const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, 71 const VkAllocationCallbacks *pAllocator, 72 VkDebugUtilsMessengerEXT *pMessenger) { 73 struct loader_instance *inst = loader_get_instance(instance); 74 loader_platform_thread_lock_mutex(&loader_lock); 75 VkResult result = inst->disp->layer_inst_disp.CreateDebugUtilsMessengerEXT(inst->instance, pCreateInfo, pAllocator, pMessenger); 76 loader_platform_thread_unlock_mutex(&loader_lock); 77 return result; 78} 79 80VkBool32 util_SubmitDebugUtilsMessageEXT(const struct loader_instance *inst, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, 81 VkDebugUtilsMessageTypeFlagsEXT messageTypes, 82 const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) { 83 VkBool32 bail = false; 84 85 if (NULL != pCallbackData) { 86 VkLayerDbgFunctionNode *pTrav = inst->current_dbg_function_head; 87 VkDebugReportObjectTypeEXT object_type = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT; 88 VkDebugReportFlagsEXT object_flags = 0; 89 uint64_t object_handle = 0; 90 91 debug_utils_AnnotFlagsToReportFlags(messageSeverity, messageTypes, &object_flags); 92 if (0 < pCallbackData->objectCount) { 93 debug_utils_AnnotObjectToDebugReportObject(pCallbackData->pObjects, &object_type, &object_handle); 94 } 95 96 while (pTrav) { 97 if (pTrav->is_messenger && (pTrav->messenger.messageSeverity & messageSeverity) && 98 (pTrav->messenger.messageType & messageTypes)) { 99 if (pTrav->messenger.pfnUserCallback(messageSeverity, messageTypes, pCallbackData, pTrav->pUserData)) { 100 bail = true; 101 } 102 } 103 if (!pTrav->is_messenger && pTrav->report.msgFlags & object_flags) { 104 if (pTrav->report.pfnMsgCallback(object_flags, object_type, object_handle, 0, pCallbackData->messageIdNumber, 105 pCallbackData->pMessageIdName, pCallbackData->pMessage, pTrav->pUserData)) { 106 bail = true; 107 } 108 } 109 110 pTrav = pTrav->pNext; 111 } 112 } 113 114 return bail; 115} 116 117void util_DestroyDebugUtilsMessenger(struct loader_instance *inst, VkDebugUtilsMessengerEXT messenger, 118 const VkAllocationCallbacks *pAllocator) { 119 VkLayerDbgFunctionNode *pTrav = inst->current_dbg_function_head; 120 VkLayerDbgFunctionNode *pPrev = pTrav; 121 122 while (pTrav) { 123 if (pTrav->is_messenger && pTrav->messenger.messenger == messenger) { 124 pPrev->pNext = pTrav->pNext; 125 if (inst->current_dbg_function_head == pTrav) inst->current_dbg_function_head = pTrav->pNext; 126 if (inst->instance_only_dbg_function_head == pTrav) inst->instance_only_dbg_function_head = pTrav->pNext; 127 loader_free_with_instance_fallback(pAllocator, inst, pTrav); 128 break; 129 } 130 pPrev = pTrav; 131 pTrav = pTrav->pNext; 132 } 133} 134 135VkResult util_CreateDebugUtilsMessengers(struct loader_instance *inst, const void *pChain, 136 const VkAllocationCallbacks *pAllocator) { 137 const void *pNext = pChain; 138 while (pNext) { 139 if (((const VkBaseInStructure *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) { 140 // Assign a unique handle to each messenger (just use the address of the VkDebugUtilsMessengerCreateInfoEXT) 141 // This is only being used this way due to it being for an 'anonymous' callback during instance creation 142 VkDebugUtilsMessengerEXT messenger_handle = (VkDebugUtilsMessengerEXT)(uintptr_t)pNext; 143 VkResult ret = util_CreateDebugUtilsMessenger(inst, (const VkDebugUtilsMessengerCreateInfoEXT *)pNext, pAllocator, 144 messenger_handle); 145 if (ret != VK_SUCCESS) { 146 return ret; 147 } 148 } 149 pNext = (void *)((VkBaseInStructure *)pNext)->pNext; 150 } 151 return VK_SUCCESS; 152} 153 154VKAPI_ATTR void VKAPI_CALL debug_utils_SubmitDebugUtilsMessageEXT(VkInstance instance, 155 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, 156 VkDebugUtilsMessageTypeFlagsEXT messageTypes, 157 const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) { 158 struct loader_instance *inst = loader_get_instance(instance); 159 160 inst->disp->layer_inst_disp.SubmitDebugUtilsMessageEXT(inst->instance, messageSeverity, messageTypes, pCallbackData); 161} 162 163VKAPI_ATTR void VKAPI_CALL debug_utils_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger, 164 const VkAllocationCallbacks *pAllocator) { 165 struct loader_instance *inst = loader_get_instance(instance); 166 loader_platform_thread_lock_mutex(&loader_lock); 167 168 inst->disp->layer_inst_disp.DestroyDebugUtilsMessengerEXT(inst->instance, messenger, pAllocator); 169 170 loader_platform_thread_unlock_mutex(&loader_lock); 171} 172 173// This is the instance chain terminator function for CreateDebugUtilsMessenger 174VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugUtilsMessengerEXT(VkInstance instance, 175 const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, 176 const VkAllocationCallbacks *pAllocator, 177 VkDebugUtilsMessengerEXT *pMessenger) { 178 VkDebugUtilsMessengerEXT *icd_info = NULL; 179 const struct loader_icd_term *icd_term; 180 struct loader_instance *inst = (struct loader_instance *)instance; 181 VkResult res = VK_SUCCESS; 182 uint32_t storage_idx; 183 VkLayerDbgFunctionNode *new_dbg_func_node = NULL; 184 185 icd_info = (VkDebugUtilsMessengerEXT *)loader_calloc_with_instance_fallback( 186 pAllocator, inst, inst->total_icd_count * sizeof(VkDebugUtilsMessengerEXT), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 187 188 if (!icd_info) { 189 res = VK_ERROR_OUT_OF_HOST_MEMORY; 190 goto out; 191 } 192 193 storage_idx = 0; 194 for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { 195 if (!icd_term->dispatch.CreateDebugUtilsMessengerEXT) { 196 continue; 197 } 198 199 res = icd_term->dispatch.CreateDebugUtilsMessengerEXT(icd_term->instance, pCreateInfo, pAllocator, &icd_info[storage_idx]); 200 201 if (res != VK_SUCCESS) { 202 goto out; 203 } 204 storage_idx++; 205 } 206 207 // Setup the debug report callback in the terminator since a layer may want 208 // to grab the information itself (RenderDoc) and then return back to the 209 // user callback a sub-set of the messages. 210 new_dbg_func_node = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback( 211 pAllocator, inst, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 212 if (!new_dbg_func_node) { 213 res = VK_ERROR_OUT_OF_HOST_MEMORY; 214 goto out; 215 } 216 217 new_dbg_func_node->is_messenger = true; 218 new_dbg_func_node->messenger.pfnUserCallback = pCreateInfo->pfnUserCallback; 219 new_dbg_func_node->messenger.messageSeverity = pCreateInfo->messageSeverity; 220 new_dbg_func_node->messenger.messageType = pCreateInfo->messageType; 221 new_dbg_func_node->pUserData = pCreateInfo->pUserData; 222 new_dbg_func_node->pNext = inst->current_dbg_function_head; 223 inst->current_dbg_function_head = new_dbg_func_node; 224 225 *pMessenger = (VkDebugUtilsMessengerEXT)(uintptr_t)icd_info; 226 new_dbg_func_node->messenger.messenger = *pMessenger; 227 228out: 229 230 // Roll back on errors 231 if (VK_SUCCESS != res) { 232 storage_idx = 0; 233 for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { 234 if (NULL == icd_term->dispatch.DestroyDebugUtilsMessengerEXT) { 235 continue; 236 } 237 238 if (icd_info && icd_info[storage_idx]) { 239 icd_term->dispatch.DestroyDebugUtilsMessengerEXT(icd_term->instance, icd_info[storage_idx], pAllocator); 240 } 241 storage_idx++; 242 } 243 loader_free_with_instance_fallback(pAllocator, inst, new_dbg_func_node); 244 loader_free_with_instance_fallback(pAllocator, inst, icd_info); 245 } 246 247 return res; 248} 249 250// This is the instance chain terminator function for DestroyDebugUtilsMessenger 251VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger, 252 const VkAllocationCallbacks *pAllocator) { 253 uint32_t storage_idx; 254 VkDebugUtilsMessengerEXT *icd_info; 255 const struct loader_icd_term *icd_term; 256 257 struct loader_instance *inst = (struct loader_instance *)instance; 258 icd_info = (VkDebugUtilsMessengerEXT *)(uintptr_t)messenger; 259 storage_idx = 0; 260 for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { 261 if (NULL == icd_term->dispatch.DestroyDebugUtilsMessengerEXT) { 262 continue; 263 } 264 265 if (icd_info && icd_info[storage_idx]) { 266 icd_term->dispatch.DestroyDebugUtilsMessengerEXT(icd_term->instance, icd_info[storage_idx], pAllocator); 267 } 268 storage_idx++; 269 } 270 271 util_DestroyDebugUtilsMessenger(inst, messenger, pAllocator); 272 273 loader_free_with_instance_fallback(pAllocator, inst, icd_info); 274} 275 276// This is the instance chain terminator function for SubmitDebugUtilsMessageEXT 277VKAPI_ATTR void VKAPI_CALL terminator_SubmitDebugUtilsMessageEXT(VkInstance instance, 278 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, 279 VkDebugUtilsMessageTypeFlagsEXT messageTypes, 280 const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) { 281 loader_platform_thread_lock_mutex(&loader_lock); 282 // NOTE: Just make the callback ourselves because there could be one or more ICDs that support this extension 283 // and each one will trigger the callback to the user. This would result in multiple callback triggers 284 // per message. Instead, if we get a messaged up to here, then just trigger the message ourselves and 285 // return. This would still allow the ICDs to trigger their own messages, but won't get any external ones. 286 struct loader_instance *inst = (struct loader_instance *)instance; 287 util_SubmitDebugUtilsMessageEXT(inst, messageSeverity, messageTypes, pCallbackData); 288 loader_platform_thread_unlock_mutex(&loader_lock); 289} 290 291// VK_EXT_debug_report related items 292 293VkResult util_CreateDebugReportCallback(struct loader_instance *inst, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, 294 const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT callback) { 295 VkLayerDbgFunctionNode *new_dbg_func_node = NULL; 296 297 new_dbg_func_node = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback( 298 pAllocator, inst, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 299 if (!new_dbg_func_node) { 300 return VK_ERROR_OUT_OF_HOST_MEMORY; 301 } 302 303 new_dbg_func_node->is_messenger = false; 304 new_dbg_func_node->report.msgCallback = callback; 305 new_dbg_func_node->report.pfnMsgCallback = pCreateInfo->pfnCallback; 306 new_dbg_func_node->report.msgFlags = pCreateInfo->flags; 307 new_dbg_func_node->pUserData = pCreateInfo->pUserData; 308 new_dbg_func_node->pNext = inst->instance_only_dbg_function_head; 309 inst->instance_only_dbg_function_head = new_dbg_func_node; 310 inst->current_dbg_function_head = inst->instance_only_dbg_function_head; 311 312 return VK_SUCCESS; 313} 314 315VKAPI_ATTR VkResult VKAPI_CALL debug_utils_CreateDebugReportCallbackEXT(VkInstance instance, 316 const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, 317 const VkAllocationCallbacks *pAllocator, 318 VkDebugReportCallbackEXT *pCallback) { 319 struct loader_instance *inst = loader_get_instance(instance); 320 loader_platform_thread_lock_mutex(&loader_lock); 321 VkResult result = inst->disp->layer_inst_disp.CreateDebugReportCallbackEXT(inst->instance, pCreateInfo, pAllocator, pCallback); 322 loader_platform_thread_unlock_mutex(&loader_lock); 323 return result; 324} 325 326// Utility function to handle reporting 327VkBool32 util_DebugReportMessage(const struct loader_instance *inst, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType, 328 uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) { 329 VkBool32 bail = false; 330 VkLayerDbgFunctionNode *pTrav = inst->current_dbg_function_head; 331 VkDebugUtilsMessageSeverityFlagBitsEXT severity; 332 VkDebugUtilsMessageTypeFlagsEXT types; 333 VkDebugUtilsMessengerCallbackDataEXT callback_data; 334 VkDebugUtilsObjectNameInfoEXT object_name; 335 336 debug_utils_ReportFlagsToAnnotFlags(msgFlags, false, &severity, &types); 337 debug_utils_ReportObjectToAnnotObject(objectType, srcObject, &object_name); 338 339 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT; 340 callback_data.pNext = NULL; 341 callback_data.flags = 0; 342 callback_data.pMessageIdName = pLayerPrefix; 343 callback_data.messageIdNumber = msgCode; 344 callback_data.pMessage = pMsg; 345 callback_data.cmdBufLabelCount = 0; 346 callback_data.pCmdBufLabels = NULL; 347 callback_data.queueLabelCount = 0; 348 callback_data.pQueueLabels = NULL; 349 callback_data.objectCount = 1; 350 callback_data.pObjects = &object_name; 351 352 while (pTrav) { 353 if (!pTrav->is_messenger && pTrav->report.msgFlags & msgFlags) { 354 if (pTrav->report.pfnMsgCallback(msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, pMsg, 355 pTrav->pUserData)) { 356 bail = true; 357 } 358 } 359 if (pTrav->is_messenger && (pTrav->messenger.messageSeverity & severity) && (pTrav->messenger.messageType & types)) { 360 if (pTrav->messenger.pfnUserCallback(severity, types, &callback_data, pTrav->pUserData)) { 361 bail = true; 362 } 363 } 364 365 pTrav = pTrav->pNext; 366 } 367 368 return bail; 369} 370 371void util_DestroyDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackEXT callback, 372 const VkAllocationCallbacks *pAllocator) { 373 VkLayerDbgFunctionNode *pTrav = inst->current_dbg_function_head; 374 VkLayerDbgFunctionNode *pPrev = pTrav; 375 376 while (pTrav) { 377 if (!pTrav->is_messenger && pTrav->report.msgCallback == callback) { 378 pPrev->pNext = pTrav->pNext; 379 if (inst->current_dbg_function_head == pTrav) inst->current_dbg_function_head = pTrav->pNext; 380 if (inst->instance_only_dbg_function_head == pTrav) inst->instance_only_dbg_function_head = pTrav->pNext; 381 if (inst->current_dbg_function_head == pTrav) inst->current_dbg_function_head = pTrav->pNext; 382 loader_free_with_instance_fallback(pAllocator, inst, pTrav); 383 break; 384 } 385 pPrev = pTrav; 386 pTrav = pTrav->pNext; 387 } 388} 389 390VkResult util_CreateDebugReportCallbacks(struct loader_instance *inst, const void *pChain, 391 const VkAllocationCallbacks *pAllocator) { 392 const void *pNext = pChain; 393 while (pNext) { 394 if (((VkBaseInStructure *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) { 395 // Assign a unique handle to each callback (just use the address of the VkDebugReportCallbackCreateInfoEXT): 396 // This is only being used this way due to it being for an 'anonymous' callback during instance creation 397 VkDebugReportCallbackEXT report_handle = (VkDebugReportCallbackEXT)(uintptr_t)pNext; 398 VkResult ret = 399 util_CreateDebugReportCallback(inst, (const VkDebugReportCallbackCreateInfoEXT *)pNext, pAllocator, report_handle); 400 if (ret != VK_SUCCESS) { 401 return ret; 402 } 403 } 404 pNext = (void *)((VkBaseInStructure *)pNext)->pNext; 405 } 406 return VK_SUCCESS; 407} 408 409VKAPI_ATTR void VKAPI_CALL debug_utils_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, 410 const VkAllocationCallbacks *pAllocator) { 411 struct loader_instance *inst = loader_get_instance(instance); 412 loader_platform_thread_lock_mutex(&loader_lock); 413 414 inst->disp->layer_inst_disp.DestroyDebugReportCallbackEXT(inst->instance, callback, pAllocator); 415 416 loader_platform_thread_unlock_mutex(&loader_lock); 417} 418 419VKAPI_ATTR void VKAPI_CALL debug_utils_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, 420 VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location, 421 int32_t msgCode, const char *pLayerPrefix, const char *pMsg) { 422 struct loader_instance *inst = loader_get_instance(instance); 423 424 inst->disp->layer_inst_disp.DebugReportMessageEXT(inst->instance, flags, objType, object, location, msgCode, pLayerPrefix, 425 pMsg); 426} 427 428// This is the instance chain terminator function 429// for CreateDebugReportCallback 430VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallbackEXT(VkInstance instance, 431 const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, 432 const VkAllocationCallbacks *pAllocator, 433 VkDebugReportCallbackEXT *pCallback) { 434 VkDebugReportCallbackEXT *icd_info = NULL; 435 const struct loader_icd_term *icd_term; 436 struct loader_instance *inst = (struct loader_instance *)instance; 437 VkResult res = VK_SUCCESS; 438 uint32_t storage_idx; 439 VkLayerDbgFunctionNode *new_dbg_func_node = NULL; 440 441 icd_info = ((VkDebugReportCallbackEXT *)loader_calloc_with_instance_fallback( 442 pAllocator, inst, inst->total_icd_count * sizeof(VkDebugReportCallbackEXT), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); 443 if (!icd_info) { 444 res = VK_ERROR_OUT_OF_HOST_MEMORY; 445 goto out; 446 } 447 448 storage_idx = 0; 449 for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { 450 if (!icd_term->dispatch.CreateDebugReportCallbackEXT) { 451 continue; 452 } 453 454 res = icd_term->dispatch.CreateDebugReportCallbackEXT(icd_term->instance, pCreateInfo, pAllocator, &icd_info[storage_idx]); 455 456 if (res != VK_SUCCESS) { 457 goto out; 458 } 459 storage_idx++; 460 } 461 462 // Setup the debug report callback in the terminator since a layer may want 463 // to grab the information itself (RenderDoc) and then return back to the 464 // user callback a sub-set of the messages. 465 new_dbg_func_node = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback( 466 pAllocator, inst, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 467 468 if (!new_dbg_func_node) { 469 res = VK_ERROR_OUT_OF_HOST_MEMORY; 470 goto out; 471 } 472 473 new_dbg_func_node->is_messenger = false; 474 new_dbg_func_node->report.pfnMsgCallback = pCreateInfo->pfnCallback; 475 new_dbg_func_node->report.msgFlags = pCreateInfo->flags; 476 new_dbg_func_node->pUserData = pCreateInfo->pUserData; 477 new_dbg_func_node->pNext = inst->current_dbg_function_head; 478 inst->current_dbg_function_head = new_dbg_func_node; 479 480 *pCallback = (VkDebugReportCallbackEXT)(uintptr_t)icd_info; 481 new_dbg_func_node->report.msgCallback = *pCallback; 482 483out: 484 485 // Roll back on errors 486 if (VK_SUCCESS != res) { 487 storage_idx = 0; 488 for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { 489 if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) { 490 continue; 491 } 492 493 if (icd_info && icd_info[storage_idx]) { 494 icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator); 495 } 496 storage_idx++; 497 } 498 loader_free_with_instance_fallback(pAllocator, inst, new_dbg_func_node); 499 loader_free_with_instance_fallback(pAllocator, inst, icd_info); 500 } 501 502 return res; 503} 504 505// This is the instance chain terminator function for DestroyDebugReportCallback 506VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, 507 const VkAllocationCallbacks *pAllocator) { 508 uint32_t storage_idx; 509 VkDebugReportCallbackEXT *icd_info; 510 const struct loader_icd_term *icd_term; 511 512 struct loader_instance *inst = (struct loader_instance *)instance; 513 icd_info = (VkDebugReportCallbackEXT *)(uintptr_t)callback; 514 storage_idx = 0; 515 for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { 516 if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) { 517 continue; 518 } 519 520 if (icd_info[storage_idx]) { 521 icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator); 522 } 523 storage_idx++; 524 } 525 526 util_DestroyDebugReportCallback(inst, callback, pAllocator); 527 528 loader_free_with_instance_fallback(pAllocator, inst, icd_info); 529} 530 531// This is the instance chain terminator function for DebugReportMessage 532VKAPI_ATTR void VKAPI_CALL terminator_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, 533 VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location, 534 int32_t msgCode, const char *pLayerPrefix, const char *pMsg) { 535 const struct loader_icd_term *icd_term; 536 537 struct loader_instance *inst = (struct loader_instance *)instance; 538 539 loader_platform_thread_lock_mutex(&loader_lock); 540 for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { 541 if (icd_term->dispatch.DebugReportMessageEXT != NULL) { 542 icd_term->dispatch.DebugReportMessageEXT(icd_term->instance, flags, objType, object, location, msgCode, pLayerPrefix, 543 pMsg); 544 } 545 } 546 547 // Now that all ICDs have seen the message, call the necessary callbacks. Ignoring "bail" return value 548 // as there is nothing to bail from at this point. 549 550 util_DebugReportMessage(inst, flags, objType, object, location, msgCode, pLayerPrefix, pMsg); 551 552 loader_platform_thread_unlock_mutex(&loader_lock); 553} 554 555// General utilities 556 557const VkExtensionProperties debug_utils_extension_info[] = { 558 {VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}, 559 {VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION}, 560}; 561 562void destroy_debug_callbacks_chain(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator) { 563 VkLayerDbgFunctionNode *pTrav = inst->current_dbg_function_head; 564 VkLayerDbgFunctionNode *pNext = NULL; 565 while (pTrav) { 566 pNext = pTrav->pNext; 567 loader_free_with_instance_fallback(pAllocator, inst, pTrav); 568 pTrav = pNext; 569 } 570 inst->current_dbg_function_head = NULL; 571} 572 573VkResult add_debug_extensions_to_ext_list(const struct loader_instance *inst, struct loader_extension_list *ext_list) { 574 return loader_add_to_ext_list(inst, ext_list, sizeof(debug_utils_extension_info) / sizeof(VkExtensionProperties), 575 debug_utils_extension_info); 576} 577 578void check_for_enabled_debug_extensions(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) { 579 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { 580 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) { 581 ptr_instance->enabled_known_extensions.ext_debug_report = 1; 582 } else if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) { 583 ptr_instance->enabled_known_extensions.ext_debug_utils = 1; 584 } 585 } 586} 587 588bool debug_extensions_InstanceGpa(struct loader_instance *ptr_instance, const char *name, void **addr) { 589 bool ret_type = false; 590 591 *addr = NULL; 592 593 if (!strcmp("vkCreateDebugReportCallbackEXT", name)) { 594 *addr = 595 ptr_instance->enabled_known_extensions.ext_debug_report == 1 ? (void *)debug_utils_CreateDebugReportCallbackEXT : NULL; 596 ret_type = true; 597 } else if (!strcmp("vkDestroyDebugReportCallbackEXT", name)) { 598 *addr = 599 ptr_instance->enabled_known_extensions.ext_debug_report == 1 ? (void *)debug_utils_DestroyDebugReportCallbackEXT : NULL; 600 ret_type = true; 601 } else if (!strcmp("vkDebugReportMessageEXT", name)) { 602 *addr = ptr_instance->enabled_known_extensions.ext_debug_report == 1 ? (void *)debug_utils_DebugReportMessageEXT : NULL; 603 return true; 604 } 605 if (!strcmp("vkCreateDebugUtilsMessengerEXT", name)) { 606 *addr = 607 ptr_instance->enabled_known_extensions.ext_debug_utils == 1 ? (void *)debug_utils_CreateDebugUtilsMessengerEXT : NULL; 608 ret_type = true; 609 } else if (!strcmp("vkDestroyDebugUtilsMessengerEXT", name)) { 610 *addr = 611 ptr_instance->enabled_known_extensions.ext_debug_utils == 1 ? (void *)debug_utils_DestroyDebugUtilsMessengerEXT : NULL; 612 ret_type = true; 613 } else if (!strcmp("vkSubmitDebugUtilsMessageEXT", name)) { 614 *addr = ptr_instance->enabled_known_extensions.ext_debug_utils == 1 ? (void *)debug_utils_SubmitDebugUtilsMessageEXT : NULL; 615 ret_type = true; 616 } 617 618 return ret_type; 619} 620 621bool debug_utils_ReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec, 622 VkDebugUtilsMessageSeverityFlagBitsEXT *da_severity, 623 VkDebugUtilsMessageTypeFlagsEXT *da_type) { 624 bool type_set = false; 625 if (NULL == da_severity || NULL == da_type) { 626 return false; 627 } 628 *da_type = 0; 629 *da_severity = 0; 630 631 if ((dr_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0) { 632 *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; 633 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; 634 type_set = true; 635 } else if ((dr_flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)) != 0) { 636 *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; 637 } else if ((dr_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) { 638 *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; 639 } else if ((dr_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0) { 640 *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; 641 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; 642 type_set = true; 643 } 644 645 if ((dr_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0) { 646 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; 647 } else if (!type_set) { 648 if (default_flag_is_spec) { 649 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; 650 } else { 651 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; 652 } 653 } 654 655 return true; 656} 657 658bool debug_utils_AnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity, 659 VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags) { 660 if (NULL == dr_flags) { 661 return false; 662 } 663 664 *dr_flags = 0; 665 666 if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) { 667 *dr_flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT; 668 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) { 669 if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) { 670 *dr_flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; 671 } else { 672 *dr_flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT; 673 } 674 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) { 675 *dr_flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT; 676 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) { 677 *dr_flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT; 678 } 679 680 return true; 681} 682 683bool debug_utils_ReportObjectToAnnotObject(VkDebugReportObjectTypeEXT dr_object_type, uint64_t object_handle, 684 VkDebugUtilsObjectNameInfoEXT *da_object_name_info) { 685 if (NULL == da_object_name_info) { 686 return false; 687 } 688 da_object_name_info->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 689 da_object_name_info->pNext = NULL; 690 da_object_name_info->objectHandle = (uint64_t)(uintptr_t)object_handle; 691 da_object_name_info->pObjectName = NULL; 692 da_object_name_info->objectType = convertDebugReportObjectToCoreObject(dr_object_type); 693 return true; 694} 695 696bool debug_utils_AnnotObjectToDebugReportObject(const VkDebugUtilsObjectNameInfoEXT *da_object_name_info, 697 VkDebugReportObjectTypeEXT *dr_object_type, uint64_t *dr_object_handle) { 698 if (NULL == da_object_name_info || NULL == dr_object_type || NULL == dr_object_handle) { 699 return false; 700 } 701 *dr_object_type = convertCoreObjectToDebugReportObject(da_object_name_info->objectType); 702 *dr_object_handle = da_object_name_info->objectHandle; 703 return true; 704} 705