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