1 /*
2  * Copyright (c) 2015-2017 The Khronos Group Inc.
3  * Copyright (c) 2015-2017 Valve Corporation
4  * Copyright (c) 2015-2017 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  *
23  */
24 
25 #ifndef _GNU_SOURCE
26 #define _GNU_SOURCE
27 #endif
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <inttypes.h>
32 #ifndef WIN32
33 #include <signal.h>
34 #else
35 #endif
36 #include "vk_loader_platform.h"
37 #include "debug_utils.h"
38 #include "vulkan/vk_layer.h"
39 #include "vk_object_types.h"
40 
41 // VK_EXT_debug_report related items
42 
util_CreateDebugUtilsMessenger(struct loader_instance * inst,const VkDebugUtilsMessengerCreateInfoEXT * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDebugUtilsMessengerEXT messenger)43 VkResult util_CreateDebugUtilsMessenger(struct loader_instance *inst, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
44                                         const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT messenger) {
45     VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
46 
47 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
48     {
49 #else
50     if (pAllocator != NULL) {
51         pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode),
52                                                                               sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
53     } else {
54 #endif
55         pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode),
56                                                                                VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
57     }
58     if (!pNewDbgFuncNode) {
59         return VK_ERROR_OUT_OF_HOST_MEMORY;
60     }
61     memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
62 
63     pNewDbgFuncNode->is_messenger = true;
64     pNewDbgFuncNode->messenger.messenger = messenger;
65     pNewDbgFuncNode->messenger.pfnUserCallback = pCreateInfo->pfnUserCallback;
66     pNewDbgFuncNode->messenger.messageSeverity = pCreateInfo->messageSeverity;
67     pNewDbgFuncNode->messenger.messageType = pCreateInfo->messageType;
68     pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
69     pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
70     inst->DbgFunctionHead = pNewDbgFuncNode;
71 
72     return VK_SUCCESS;
73 }
74 
75 static VKAPI_ATTR VkResult VKAPI_CALL
76 debug_utils_CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
77                                          const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pMessenger) {
78     struct loader_instance *inst = loader_get_instance(instance);
79     loader_platform_thread_lock_mutex(&loader_lock);
80     VkResult result = inst->disp->layer_inst_disp.CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
81     loader_platform_thread_unlock_mutex(&loader_lock);
82     return result;
83 }
84 
85 VkBool32 util_SubmitDebugUtilsMessageEXT(const struct loader_instance *inst, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
86                                          VkDebugUtilsMessageTypeFlagsEXT messageTypes,
87                                          const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
88     VkBool32 bail = false;
89 
90     if (NULL != pCallbackData) {
91         VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
92         VkDebugReportObjectTypeEXT object_type = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;
93         VkDebugReportFlagsEXT object_flags = 0;
94         uint64_t object_handle = 0;
95 
96         debug_utils_AnnotFlagsToReportFlags(messageSeverity, messageTypes, &object_flags);
97         if (0 < pCallbackData->objectCount) {
98             debug_utils_AnnotObjectToDebugReportObject(pCallbackData->pObjects, &object_type, &object_handle);
99         }
100 
101         while (pTrav) {
102             if (pTrav->is_messenger && (pTrav->messenger.messageSeverity & messageSeverity) &&
103                 (pTrav->messenger.messageType & messageTypes)) {
104                 if (pTrav->messenger.pfnUserCallback(messageSeverity, messageTypes, pCallbackData, pTrav->pUserData)) {
105                     bail = true;
106                 }
107             }
108             if (!pTrav->is_messenger && pTrav->report.msgFlags & object_flags) {
109                 if (pTrav->report.pfnMsgCallback(object_flags, object_type, object_handle, 0, pCallbackData->messageIdNumber,
110                                                  pCallbackData->pMessageIdName, pCallbackData->pMessage, pTrav->pUserData)) {
111                     bail = true;
112                 }
113             }
114 
115             pTrav = pTrav->pNext;
116         }
117     }
118 
119     return bail;
120 }
121 
122 void util_DestroyDebugUtilsMessenger(struct loader_instance *inst, VkDebugUtilsMessengerEXT messenger,
123                                      const VkAllocationCallbacks *pAllocator) {
124     VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
125     VkLayerDbgFunctionNode *pPrev = pTrav;
126 
127     while (pTrav) {
128         if (pTrav->is_messenger && pTrav->messenger.messenger == messenger) {
129             pPrev->pNext = pTrav->pNext;
130             if (inst->DbgFunctionHead == pTrav) inst->DbgFunctionHead = pTrav->pNext;
131 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
132             {
133 #else
134             if (pAllocator != NULL) {
135                 pAllocator->pfnFree(pAllocator->pUserData, pTrav);
136             } else {
137 #endif
138                 loader_instance_heap_free(inst, pTrav);
139             }
140             break;
141         }
142         pPrev = pTrav;
143         pTrav = pTrav->pNext;
144     }
145 }
146 
147 // This utility (used by vkInstanceCreateInfo(), looks at a pNext chain.  It
148 // counts any VkDebugUtilsMessengerCreateInfoEXT structs that it finds.  It
149 // then allocates array that can hold that many structs, as well as that many
150 // VkDebugUtilsMessengerEXT handles.  It then copies each
151 // VkDebugUtilsMessengerCreateInfoEXT, and initializes each handle.
152 VkResult util_CopyDebugUtilsMessengerCreateInfos(const void *pChain, const VkAllocationCallbacks *pAllocator,
153                                                  uint32_t *num_messengers, VkDebugUtilsMessengerCreateInfoEXT **infos,
154                                                  VkDebugUtilsMessengerEXT **messengers) {
155     uint32_t n = *num_messengers = 0;
156     VkDebugUtilsMessengerCreateInfoEXT *pInfos = NULL;
157     VkDebugUtilsMessengerEXT *pMessengers = NULL;
158 
159     const void *pNext = pChain;
160     while (pNext) {
161         // 1st, count the number VkDebugUtilsMessengerCreateInfoEXT:
162         if (((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
163             n++;
164         }
165         pNext = (void *)((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->pNext;
166     }
167     if (n == 0) {
168         return VK_SUCCESS;
169     }
170 
171 // 2nd, allocate memory for each VkDebugUtilsMessengerCreateInfoEXT:
172 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
173     {
174 #else
175     if (pAllocator != NULL) {
176         pInfos = *infos = ((VkDebugUtilsMessengerCreateInfoEXT *)pAllocator->pfnAllocation(
177             pAllocator->pUserData, n * sizeof(VkDebugUtilsMessengerCreateInfoEXT), sizeof(void *),
178             VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
179     } else {
180 #endif
181         pInfos = *infos = ((VkDebugUtilsMessengerCreateInfoEXT *)malloc(n * sizeof(VkDebugUtilsMessengerCreateInfoEXT)));
182     }
183     if (!pInfos) {
184         return VK_ERROR_OUT_OF_HOST_MEMORY;
185     }
186 // 3rd, allocate memory for a unique handle for each callback:
187 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
188     {
189 #else
190     if (pAllocator != NULL) {
191         pMessengers = *messengers = ((VkDebugUtilsMessengerEXT *)pAllocator->pfnAllocation(
192             pAllocator->pUserData, n * sizeof(VkDebugUtilsMessengerEXT), sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
193         if (NULL == pMessengers) {
194             pAllocator->pfnFree(pAllocator->pUserData, pInfos);
195             return VK_ERROR_OUT_OF_HOST_MEMORY;
196         }
197     } else {
198 #endif
199         pMessengers = *messengers = ((VkDebugUtilsMessengerEXT *)malloc(n * sizeof(VkDebugUtilsMessengerEXT)));
200         if (NULL == pMessengers) {
201             free(pInfos);
202             return VK_ERROR_OUT_OF_HOST_MEMORY;
203         }
204     }
205     // 4th, copy each VkDebugUtilsMessengerCreateInfoEXT for use by
206     // vkDestroyInstance, and assign a unique handle to each messenger (just
207     // use the address of the copied VkDebugUtilsMessengerCreateInfoEXT):
208     pNext = pChain;
209     while (pNext) {
210         if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
211             memcpy(pInfos, pNext, sizeof(VkDebugUtilsMessengerCreateInfoEXT));
212             *pMessengers++ = (VkDebugUtilsMessengerEXT)(uintptr_t)pInfos++;
213         }
214         pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
215     }
216 
217     *num_messengers = n;
218     return VK_SUCCESS;
219 }
220 
221 void util_FreeDebugUtilsMessengerCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerCreateInfoEXT *infos,
222                                              VkDebugUtilsMessengerEXT *messengers) {
223 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
224     {
225 #else
226     if (pAllocator != NULL) {
227         pAllocator->pfnFree(pAllocator->pUserData, infos);
228         pAllocator->pfnFree(pAllocator->pUserData, messengers);
229     } else {
230 #endif
231         free(infos);
232         free(messengers);
233     }
234 }
235 
236 VkResult util_CreateDebugUtilsMessengers(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
237                                          uint32_t num_messengers, VkDebugUtilsMessengerCreateInfoEXT *infos,
238                                          VkDebugUtilsMessengerEXT *messengers) {
239     VkResult rtn = VK_SUCCESS;
240     for (uint32_t i = 0; i < num_messengers; i++) {
241         rtn = util_CreateDebugUtilsMessenger(inst, &infos[i], pAllocator, messengers[i]);
242         if (rtn != VK_SUCCESS) {
243             for (uint32_t j = 0; j < i; j++) {
244                 util_DestroyDebugUtilsMessenger(inst, messengers[j], pAllocator);
245             }
246             return rtn;
247         }
248     }
249     return rtn;
250 }
251 
252 void util_DestroyDebugUtilsMessengers(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
253                                       uint32_t num_messengers, VkDebugUtilsMessengerEXT *messengers) {
254     for (uint32_t i = 0; i < num_messengers; i++) {
255         util_DestroyDebugUtilsMessenger(inst, messengers[i], pAllocator);
256     }
257 }
258 
259 static VKAPI_ATTR void VKAPI_CALL debug_utils_SubmitDebugUtilsMessageEXT(
260     VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes,
261     const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
262     struct loader_instance *inst = loader_get_instance(instance);
263 
264     inst->disp->layer_inst_disp.SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, pCallbackData);
265 }
266 
267 static VKAPI_ATTR void VKAPI_CALL debug_utils_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
268                                                                             const VkAllocationCallbacks *pAllocator) {
269     struct loader_instance *inst = loader_get_instance(instance);
270     loader_platform_thread_lock_mutex(&loader_lock);
271 
272     inst->disp->layer_inst_disp.DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
273 
274     loader_platform_thread_unlock_mutex(&loader_lock);
275 }
276 
277 // This is the instance chain terminator function for CreateDebugUtilsMessenger
278 VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugUtilsMessengerEXT(VkInstance instance,
279                                                                        const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
280                                                                        const VkAllocationCallbacks *pAllocator,
281                                                                        VkDebugUtilsMessengerEXT *pMessenger) {
282     VkDebugUtilsMessengerEXT *icd_info = NULL;
283     const struct loader_icd_term *icd_term;
284     struct loader_instance *inst = (struct loader_instance *)instance;
285     VkResult res = VK_SUCCESS;
286     uint32_t storage_idx;
287     VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
288 
289 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
290     {
291 #else
292     if (pAllocator != NULL) {
293         icd_info = ((VkDebugUtilsMessengerEXT *)pAllocator->pfnAllocation(pAllocator->pUserData,
294                                                                           inst->total_icd_count * sizeof(VkDebugUtilsMessengerEXT),
295                                                                           sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
296         if (icd_info) {
297             memset(icd_info, 0, inst->total_icd_count * sizeof(VkDebugUtilsMessengerEXT));
298         }
299     } else {
300 #endif
301         icd_info = calloc(sizeof(VkDebugUtilsMessengerEXT), inst->total_icd_count);
302     }
303     if (!icd_info) {
304         res = VK_ERROR_OUT_OF_HOST_MEMORY;
305         goto out;
306     }
307 
308     storage_idx = 0;
309     for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
310         if (!icd_term->dispatch.CreateDebugUtilsMessengerEXT) {
311             continue;
312         }
313 
314         res = icd_term->dispatch.CreateDebugUtilsMessengerEXT(icd_term->instance, pCreateInfo, pAllocator, &icd_info[storage_idx]);
315 
316         if (res != VK_SUCCESS) {
317             goto out;
318         }
319         storage_idx++;
320     }
321 
322 // Setup the debug report callback in the terminator since a layer may want
323 // to grab the information itself (RenderDoc) and then return back to the
324 // user callback a sub-set of the messages.
325 #if (DEBUG_DISABLE_APP_ALLOCATORS == 0)
326     if (pAllocator != NULL) {
327         pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode),
328                                                                               sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
329     } else {
330 #else
331     {
332 #endif
333         pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode),
334                                                                                VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
335     }
336     if (!pNewDbgFuncNode) {
337         res = VK_ERROR_OUT_OF_HOST_MEMORY;
338         goto out;
339     }
340     memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
341 
342     pNewDbgFuncNode->is_messenger = true;
343     pNewDbgFuncNode->messenger.pfnUserCallback = pCreateInfo->pfnUserCallback;
344     pNewDbgFuncNode->messenger.messageSeverity = pCreateInfo->messageSeverity;
345     pNewDbgFuncNode->messenger.messageType = pCreateInfo->messageType;
346     pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
347     pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
348     inst->DbgFunctionHead = pNewDbgFuncNode;
349 
350     *(VkDebugUtilsMessengerEXT **)pMessenger = icd_info;
351     pNewDbgFuncNode->messenger.messenger = *pMessenger;
352 
353 out:
354 
355     // Roll back on errors
356     if (VK_SUCCESS != res) {
357         storage_idx = 0;
358         for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
359             if (NULL == icd_term->dispatch.DestroyDebugUtilsMessengerEXT) {
360                 continue;
361             }
362 
363             if (icd_info && icd_info[storage_idx]) {
364                 icd_term->dispatch.DestroyDebugUtilsMessengerEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
365             }
366             storage_idx++;
367         }
368 
369 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
370         {
371 #else
372         if (pAllocator != NULL) {
373             if (NULL != pNewDbgFuncNode) {
374                 pAllocator->pfnFree(pAllocator->pUserData, pNewDbgFuncNode);
375             }
376             if (NULL != icd_info) {
377                 pAllocator->pfnFree(pAllocator->pUserData, icd_info);
378             }
379         } else {
380 #endif
381             if (NULL != pNewDbgFuncNode) {
382                 free(pNewDbgFuncNode);
383             }
384             if (NULL != icd_info) {
385                 free(icd_info);
386             }
387         }
388     }
389 
390     return res;
391 }
392 
393 // This is the instance chain terminator function for DestroyDebugUtilsMessenger
394 VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
395                                                                     const VkAllocationCallbacks *pAllocator) {
396     uint32_t storage_idx;
397     VkDebugUtilsMessengerEXT *icd_info;
398     const struct loader_icd_term *icd_term;
399 
400     struct loader_instance *inst = (struct loader_instance *)instance;
401     icd_info = *(VkDebugUtilsMessengerEXT **)&messenger;
402     storage_idx = 0;
403     for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
404         if (NULL == icd_term->dispatch.DestroyDebugUtilsMessengerEXT) {
405             continue;
406         }
407 
408         if (icd_info[storage_idx]) {
409             icd_term->dispatch.DestroyDebugUtilsMessengerEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
410         }
411         storage_idx++;
412     }
413 
414     util_DestroyDebugUtilsMessenger(inst, messenger, pAllocator);
415 
416 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
417     {
418 #else
419     if (pAllocator != NULL) {
420         pAllocator->pfnFree(pAllocator->pUserData, icd_info);
421     } else {
422 #endif
423         free(icd_info);
424     }
425 }
426 
427 // This is the instance chain terminator function for SubmitDebugUtilsMessageEXT
428 VKAPI_ATTR void VKAPI_CALL terminator_SubmitDebugUtilsMessageEXT(VkInstance instance,
429                                                                  VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
430                                                                  VkDebugUtilsMessageTypeFlagsEXT messageTypes,
431                                                                  const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
432     loader_platform_thread_lock_mutex(&loader_lock);
433     // NOTE: Just make the callback ourselves because there could be one or more ICDs that support this extension
434     //       and each one will trigger the callback to the user.  This would result in multiple callback triggers
435     //       per message.  Instead, if we get a messaged up to here, then just trigger the message ourselves and
436     //       return.  This would still allow the ICDs to trigger their own messages, but won't get any external ones.
437     struct loader_instance *inst = (struct loader_instance *)instance;
438     util_SubmitDebugUtilsMessageEXT(inst, messageSeverity, messageTypes, pCallbackData);
439     loader_platform_thread_unlock_mutex(&loader_lock);
440 }
441 
442 // VK_EXT_debug_report related items
443 
444 VkResult util_CreateDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
445                                         const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT callback) {
446     VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
447 
448 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
449     {
450 #else
451     if (pAllocator != NULL) {
452         pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode),
453                                                                               sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
454     } else {
455 #endif
456         pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode),
457                                                                                VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
458     }
459     if (!pNewDbgFuncNode) {
460         return VK_ERROR_OUT_OF_HOST_MEMORY;
461     }
462     memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
463 
464     pNewDbgFuncNode->is_messenger = false;
465     pNewDbgFuncNode->report.msgCallback = callback;
466     pNewDbgFuncNode->report.pfnMsgCallback = pCreateInfo->pfnCallback;
467     pNewDbgFuncNode->report.msgFlags = pCreateInfo->flags;
468     pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
469     pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
470     inst->DbgFunctionHead = pNewDbgFuncNode;
471 
472     return VK_SUCCESS;
473 }
474 
475 static VKAPI_ATTR VkResult VKAPI_CALL
476 debug_utils_CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
477                                          const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback) {
478     struct loader_instance *inst = loader_get_instance(instance);
479     loader_platform_thread_lock_mutex(&loader_lock);
480     VkResult result = inst->disp->layer_inst_disp.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
481     loader_platform_thread_unlock_mutex(&loader_lock);
482     return result;
483 }
484 
485 // Utility function to handle reporting
486 VkBool32 util_DebugReportMessage(const struct loader_instance *inst, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
487                                  uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
488     VkBool32 bail = false;
489     VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
490     VkDebugUtilsMessageSeverityFlagBitsEXT severity;
491     VkDebugUtilsMessageTypeFlagsEXT types;
492     VkDebugUtilsMessengerCallbackDataEXT callback_data;
493     VkDebugUtilsObjectNameInfoEXT object_name;
494 
495     debug_utils_ReportFlagsToAnnotFlags(msgFlags, false, &severity, &types);
496     debug_utils_ReportObjectToAnnotObject(objectType, srcObject, &object_name);
497 
498     callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
499     callback_data.pNext = NULL;
500     callback_data.flags = 0;
501     callback_data.pMessageIdName = pLayerPrefix;
502     callback_data.messageIdNumber = msgCode;
503     callback_data.pMessage = pMsg;
504     callback_data.cmdBufLabelCount = 0;
505     callback_data.pCmdBufLabels = NULL;
506     callback_data.queueLabelCount = 0;
507     callback_data.pQueueLabels = NULL;
508     callback_data.objectCount = 1;
509     callback_data.pObjects = &object_name;
510 
511     while (pTrav) {
512         if (!pTrav->is_messenger && pTrav->report.msgFlags & msgFlags) {
513             if (pTrav->report.pfnMsgCallback(msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, pMsg,
514                                              pTrav->pUserData)) {
515                 bail = true;
516             }
517         }
518         if (pTrav->is_messenger && (pTrav->messenger.messageSeverity & severity) && (pTrav->messenger.messageType & types)) {
519             if (pTrav->messenger.pfnUserCallback(severity, types, &callback_data, pTrav->pUserData)) {
520                 bail = true;
521             }
522         }
523 
524         pTrav = pTrav->pNext;
525     }
526 
527     return bail;
528 }
529 
530 void util_DestroyDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackEXT callback,
531                                      const VkAllocationCallbacks *pAllocator) {
532     VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
533     VkLayerDbgFunctionNode *pPrev = pTrav;
534 
535     while (pTrav) {
536         if (!pTrav->is_messenger && pTrav->report.msgCallback == callback) {
537             pPrev->pNext = pTrav->pNext;
538             if (inst->DbgFunctionHead == pTrav) inst->DbgFunctionHead = pTrav->pNext;
539 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
540             {
541 #else
542             if (pAllocator != NULL) {
543                 pAllocator->pfnFree(pAllocator->pUserData, pTrav);
544             } else {
545 #endif
546                 loader_instance_heap_free(inst, pTrav);
547             }
548             break;
549         }
550         pPrev = pTrav;
551         pTrav = pTrav->pNext;
552     }
553 }
554 
555 // This utility (used by vkInstanceCreateInfo(), looks at a pNext chain.  It
556 // counts any VkDebugReportCallbackCreateInfoEXT structs that it finds.  It
557 // then allocates array that can hold that many structs, as well as that many
558 // VkDebugReportCallbackEXT handles.  It then copies each
559 // VkDebugReportCallbackCreateInfoEXT, and initializes each handle.
560 VkResult util_CopyDebugReportCreateInfos(const void *pChain, const VkAllocationCallbacks *pAllocator, uint32_t *num_callbacks,
561                                          VkDebugReportCallbackCreateInfoEXT **infos, VkDebugReportCallbackEXT **callbacks) {
562     uint32_t n = *num_callbacks = 0;
563     VkDebugReportCallbackCreateInfoEXT *pInfos = NULL;
564     VkDebugReportCallbackEXT *pCallbacks = NULL;
565 
566     const void *pNext = pChain;
567     while (pNext) {
568         // 1st, count the number VkDebugReportCallbackCreateInfoEXT:
569         if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
570             n++;
571         }
572         pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext;
573     }
574     if (n == 0) {
575         return VK_SUCCESS;
576     }
577 
578 // 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT:
579 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
580     {
581 #else
582     if (pAllocator != NULL) {
583         pInfos = *infos = ((VkDebugReportCallbackCreateInfoEXT *)pAllocator->pfnAllocation(
584             pAllocator->pUserData, n * sizeof(VkDebugReportCallbackCreateInfoEXT), sizeof(void *),
585             VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
586     } else {
587 #endif
588         pInfos = *infos = ((VkDebugReportCallbackCreateInfoEXT *)malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT)));
589     }
590     if (!pInfos) {
591         return VK_ERROR_OUT_OF_HOST_MEMORY;
592     }
593 // 3rd, allocate memory for a unique handle for each callback:
594 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
595     {
596 #else
597     if (pAllocator != NULL) {
598         pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)pAllocator->pfnAllocation(
599             pAllocator->pUserData, n * sizeof(VkDebugReportCallbackEXT), sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
600         if (!pCallbacks) {
601             pAllocator->pfnFree(pAllocator->pUserData, pInfos);
602             return VK_ERROR_OUT_OF_HOST_MEMORY;
603         }
604     } else {
605 #endif
606         pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)malloc(n * sizeof(VkDebugReportCallbackEXT)));
607         if (!pCallbacks) {
608             free(pInfos);
609             return VK_ERROR_OUT_OF_HOST_MEMORY;
610         }
611     }
612     // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by
613     // vkDestroyInstance, and assign a unique handle to each callback (just
614     // use the address of the copied VkDebugReportCallbackCreateInfoEXT):
615     pNext = pChain;
616     while (pNext) {
617         if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
618             memcpy(pInfos, pNext, sizeof(VkDebugReportCallbackCreateInfoEXT));
619             *pCallbacks++ = (VkDebugReportCallbackEXT)(uintptr_t)pInfos++;
620         }
621         pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
622     }
623 
624     *num_callbacks = n;
625     return VK_SUCCESS;
626 }
627 
628 void util_FreeDebugReportCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackCreateInfoEXT *infos,
629                                      VkDebugReportCallbackEXT *callbacks) {
630 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
631     {
632 #else
633     if (pAllocator != NULL) {
634         pAllocator->pfnFree(pAllocator->pUserData, infos);
635         pAllocator->pfnFree(pAllocator->pUserData, callbacks);
636     } else {
637 #endif
638         free(infos);
639         free(callbacks);
640     }
641 }
642 
643 VkResult util_CreateDebugReportCallbacks(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
644                                          uint32_t num_callbacks, VkDebugReportCallbackCreateInfoEXT *infos,
645                                          VkDebugReportCallbackEXT *callbacks) {
646     VkResult rtn = VK_SUCCESS;
647     for (uint32_t i = 0; i < num_callbacks; i++) {
648         rtn = util_CreateDebugReportCallback(inst, &infos[i], pAllocator, callbacks[i]);
649         if (rtn != VK_SUCCESS) {
650             for (uint32_t j = 0; j < i; j++) {
651                 util_DestroyDebugReportCallback(inst, callbacks[j], pAllocator);
652             }
653             return rtn;
654         }
655     }
656     return rtn;
657 }
658 
659 void util_DestroyDebugReportCallbacks(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator, uint32_t num_callbacks,
660                                       VkDebugReportCallbackEXT *callbacks) {
661     for (uint32_t i = 0; i < num_callbacks; i++) {
662         util_DestroyDebugReportCallback(inst, callbacks[i], pAllocator);
663     }
664 }
665 
666 static VKAPI_ATTR void VKAPI_CALL debug_utils_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
667                                                                             const VkAllocationCallbacks *pAllocator) {
668     struct loader_instance *inst = loader_get_instance(instance);
669     loader_platform_thread_lock_mutex(&loader_lock);
670 
671     inst->disp->layer_inst_disp.DestroyDebugReportCallbackEXT(instance, callback, pAllocator);
672 
673     loader_platform_thread_unlock_mutex(&loader_lock);
674 }
675 
676 static VKAPI_ATTR void VKAPI_CALL debug_utils_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
677                                                                     VkDebugReportObjectTypeEXT objType, uint64_t object,
678                                                                     size_t location, int32_t msgCode, const char *pLayerPrefix,
679                                                                     const char *pMsg) {
680     struct loader_instance *inst = loader_get_instance(instance);
681 
682     inst->disp->layer_inst_disp.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
683 }
684 
685 // This is the instance chain terminator function
686 // for CreateDebugReportCallback
687 VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallbackEXT(VkInstance instance,
688                                                                        const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
689                                                                        const VkAllocationCallbacks *pAllocator,
690                                                                        VkDebugReportCallbackEXT *pCallback) {
691     VkDebugReportCallbackEXT *icd_info = NULL;
692     const struct loader_icd_term *icd_term;
693     struct loader_instance *inst = (struct loader_instance *)instance;
694     VkResult res = VK_SUCCESS;
695     uint32_t storage_idx;
696     VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
697 
698 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
699     {
700 #else
701     if (pAllocator != NULL) {
702         icd_info = ((VkDebugReportCallbackEXT *)pAllocator->pfnAllocation(pAllocator->pUserData,
703                                                                           inst->total_icd_count * sizeof(VkDebugReportCallbackEXT),
704                                                                           sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
705         if (icd_info) {
706             memset(icd_info, 0, inst->total_icd_count * sizeof(VkDebugReportCallbackEXT));
707         }
708     } else {
709 #endif
710         icd_info = calloc(sizeof(VkDebugReportCallbackEXT), inst->total_icd_count);
711     }
712     if (!icd_info) {
713         res = VK_ERROR_OUT_OF_HOST_MEMORY;
714         goto out;
715     }
716 
717     storage_idx = 0;
718     for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
719         if (!icd_term->dispatch.CreateDebugReportCallbackEXT) {
720             continue;
721         }
722 
723         res = icd_term->dispatch.CreateDebugReportCallbackEXT(icd_term->instance, pCreateInfo, pAllocator, &icd_info[storage_idx]);
724 
725         if (res != VK_SUCCESS) {
726             goto out;
727         }
728         storage_idx++;
729     }
730 
731 // Setup the debug report callback in the terminator since a layer may want
732 // to grab the information itself (RenderDoc) and then return back to the
733 // user callback a sub-set of the messages.
734 #if (DEBUG_DISABLE_APP_ALLOCATORS == 0)
735     if (pAllocator != NULL) {
736         pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode),
737                                                                               sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
738     } else {
739 #else
740     {
741 #endif
742         pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode),
743                                                                                VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
744     }
745     if (!pNewDbgFuncNode) {
746         res = VK_ERROR_OUT_OF_HOST_MEMORY;
747         goto out;
748     }
749     memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
750 
751     pNewDbgFuncNode->is_messenger = false;
752     pNewDbgFuncNode->report.pfnMsgCallback = pCreateInfo->pfnCallback;
753     pNewDbgFuncNode->report.msgFlags = pCreateInfo->flags;
754     pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
755     pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
756     inst->DbgFunctionHead = pNewDbgFuncNode;
757 
758     *(VkDebugReportCallbackEXT **)pCallback = icd_info;
759     pNewDbgFuncNode->report.msgCallback = *pCallback;
760 
761 out:
762 
763     // Roll back on errors
764     if (VK_SUCCESS != res) {
765         storage_idx = 0;
766         for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
767             if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) {
768                 continue;
769             }
770 
771             if (icd_info && icd_info[storage_idx]) {
772                 icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
773             }
774             storage_idx++;
775         }
776 
777 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
778         {
779 #else
780         if (pAllocator != NULL) {
781             if (NULL != pNewDbgFuncNode) {
782                 pAllocator->pfnFree(pAllocator->pUserData, pNewDbgFuncNode);
783             }
784             if (NULL != icd_info) {
785                 pAllocator->pfnFree(pAllocator->pUserData, icd_info);
786             }
787         } else {
788 #endif
789             if (NULL != pNewDbgFuncNode) {
790                 free(pNewDbgFuncNode);
791             }
792             if (NULL != icd_info) {
793                 free(icd_info);
794             }
795         }
796     }
797 
798     return res;
799 }
800 
801 // This is the instance chain terminator function for DestroyDebugReportCallback
802 VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
803                                                                     const VkAllocationCallbacks *pAllocator) {
804     uint32_t storage_idx;
805     VkDebugReportCallbackEXT *icd_info;
806     const struct loader_icd_term *icd_term;
807 
808     struct loader_instance *inst = (struct loader_instance *)instance;
809     icd_info = *(VkDebugReportCallbackEXT **)&callback;
810     storage_idx = 0;
811     for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
812         if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) {
813             continue;
814         }
815 
816         if (icd_info[storage_idx]) {
817             icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
818         }
819         storage_idx++;
820     }
821 
822     util_DestroyDebugReportCallback(inst, callback, pAllocator);
823 
824 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
825     {
826 #else
827     if (pAllocator != NULL) {
828         pAllocator->pfnFree(pAllocator->pUserData, icd_info);
829     } else {
830 #endif
831         free(icd_info);
832     }
833 }
834 
835 // This is the instance chain terminator function for DebugReportMessage
836 VKAPI_ATTR void VKAPI_CALL terminator_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
837                                                             VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
838                                                             int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
839     const struct loader_icd_term *icd_term;
840 
841     struct loader_instance *inst = (struct loader_instance *)instance;
842 
843     loader_platform_thread_lock_mutex(&loader_lock);
844     for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
845         if (icd_term->dispatch.DebugReportMessageEXT != NULL) {
846             icd_term->dispatch.DebugReportMessageEXT(icd_term->instance, flags, objType, object, location, msgCode, pLayerPrefix,
847                                                      pMsg);
848         }
849     }
850 
851     // Now that all ICDs have seen the message, call the necessary callbacks.  Ignoring "bail" return value
852     // as there is nothing to bail from at this point.
853 
854     util_DebugReportMessage(inst, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
855 
856     loader_platform_thread_unlock_mutex(&loader_lock);
857 }
858 
859 // General utilities
860 
861 static const VkExtensionProperties debug_utils_extension_info[] = {
862     {VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION},
863     {VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION},
864 };
865 
866 void debug_utils_AddInstanceExtensions(const struct loader_instance *inst, struct loader_extension_list *ext_list) {
867     loader_add_to_ext_list(inst, ext_list, sizeof(debug_utils_extension_info) / sizeof(VkExtensionProperties),
868                            debug_utils_extension_info);
869 }
870 
871 void debug_utils_CreateInstance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) {
872     ptr_instance->enabled_known_extensions.ext_debug_report = 0;
873     ptr_instance->enabled_known_extensions.ext_debug_utils = 0;
874 
875     for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
876         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
877             ptr_instance->enabled_known_extensions.ext_debug_report = 1;
878         } else if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
879             ptr_instance->enabled_known_extensions.ext_debug_utils = 1;
880         }
881     }
882 }
883 
884 bool debug_utils_InstanceGpa(struct loader_instance *ptr_instance, const char *name, void **addr) {
885     bool ret_type = false;
886 
887     *addr = NULL;
888 
889     if (!strcmp("vkCreateDebugReportCallbackEXT", name)) {
890         *addr = ptr_instance->enabled_known_extensions.ext_debug_report == 1 ? (void *)debug_utils_CreateDebugReportCallbackEXT : NULL;
891         ret_type = true;
892     } else if (!strcmp("vkDestroyDebugReportCallbackEXT", name)) {
893         *addr = ptr_instance->enabled_known_extensions.ext_debug_report == 1 ? (void *)debug_utils_DestroyDebugReportCallbackEXT : NULL;
894         ret_type = true;
895     } else if (!strcmp("vkDebugReportMessageEXT", name)) {
896         *addr = ptr_instance->enabled_known_extensions.ext_debug_report == 1 ? (void *)debug_utils_DebugReportMessageEXT : NULL;
897         return true;
898     }
899     if (!strcmp("vkCreateDebugUtilsMessengerEXT", name)) {
900         *addr = ptr_instance->enabled_known_extensions.ext_debug_utils == 1 ? (void *)debug_utils_CreateDebugUtilsMessengerEXT : NULL;
901         ret_type = true;
902     } else if (!strcmp("vkDestroyDebugUtilsMessengerEXT", name)) {
903         *addr = ptr_instance->enabled_known_extensions.ext_debug_utils == 1 ? (void *)debug_utils_DestroyDebugUtilsMessengerEXT : NULL;
904         ret_type = true;
905     } else if (!strcmp("vkSubmitDebugUtilsMessageEXT", name)) {
906         *addr = ptr_instance->enabled_known_extensions.ext_debug_utils == 1 ? (void *)debug_utils_SubmitDebugUtilsMessageEXT : NULL;
907         ret_type = true;
908     }
909 
910     return ret_type;
911 }
912 
913 bool debug_utils_ReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec,
914                                          VkDebugUtilsMessageSeverityFlagBitsEXT *da_severity,
915                                          VkDebugUtilsMessageTypeFlagsEXT *da_type) {
916     bool type_set = false;
917     if (NULL == da_severity || NULL == da_type) {
918         return false;
919     }
920     *da_type = 0;
921     *da_severity = 0;
922 
923     if ((dr_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0) {
924         *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
925         *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
926         type_set = true;
927     } else if ((dr_flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)) != 0) {
928         *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
929     } else if ((dr_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) {
930         *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
931     } else if ((dr_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0) {
932         *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
933         *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
934         type_set = true;
935     }
936 
937     if ((dr_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0) {
938         *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
939     } else if (!type_set) {
940         if (default_flag_is_spec) {
941             *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
942         } else {
943             *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
944         }
945     }
946 
947     return true;
948 }
949 
950 bool debug_utils_AnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,
951                                          VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags) {
952     if (NULL == dr_flags) {
953         return false;
954     }
955 
956     *dr_flags = 0;
957 
958     if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) {
959         *dr_flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
960     } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) {
961         if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) {
962             *dr_flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
963         } else {
964             *dr_flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
965         }
966     } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) {
967         *dr_flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
968     } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) {
969         *dr_flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
970     }
971 
972     return true;
973 }
974 
975 bool debug_utils_ReportObjectToAnnotObject(VkDebugReportObjectTypeEXT dr_object_type, uint64_t object_handle,
976                                            VkDebugUtilsObjectNameInfoEXT *da_object_name_info) {
977     if (NULL == da_object_name_info) {
978         return false;
979     }
980     da_object_name_info->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
981     da_object_name_info->pNext = NULL;
982     da_object_name_info->objectHandle = (uint64_t)(uintptr_t)object_handle;
983     da_object_name_info->pObjectName = NULL;
984     da_object_name_info->objectType = convertDebugReportObjectToCoreObject(dr_object_type);
985     return true;
986 }
987 
988 bool debug_utils_AnnotObjectToDebugReportObject(const VkDebugUtilsObjectNameInfoEXT *da_object_name_info,
989                                                 VkDebugReportObjectTypeEXT *dr_object_type, uint64_t *dr_object_handle) {
990     if (NULL == da_object_name_info || NULL == dr_object_type || NULL == dr_object_handle) {
991         return false;
992     }
993     *dr_object_type = convertCoreObjectToDebugReportObject(da_object_name_info->objectType);
994     *dr_object_handle = da_object_name_info->objectHandle;
995     return true;
996 }
997