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 
util_CreateDebugUtilsMessenger(struct loader_instance *inst, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT messenger)45 VkResult 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 
debug_utils_CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pMessenger)69 VKAPI_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 
util_SubmitDebugUtilsMessageEXT(const struct loader_instance *inst, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData)80 VkBool32 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 
util_DestroyDebugUtilsMessenger(struct loader_instance *inst, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks *pAllocator)117 void 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 
util_CreateDebugUtilsMessengers(struct loader_instance *inst, const void *pChain, const VkAllocationCallbacks *pAllocator)135 VkResult 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 
debug_utils_SubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData)154 VKAPI_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 
debug_utils_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks *pAllocator)163 VKAPI_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
terminator_CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pMessenger)174 VKAPI_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 
228 out:
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
terminator_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks *pAllocator)251 VKAPI_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
terminator_SubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData)277 VKAPI_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 
util_CreateDebugReportCallback(struct loader_instance *inst, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT callback)293 VkResult 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 
debug_utils_CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback)315 VKAPI_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
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)327 VkBool32 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 
util_DestroyDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks *pAllocator)371 void 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 
util_CreateDebugReportCallbacks(struct loader_instance *inst, const void *pChain, const VkAllocationCallbacks *pAllocator)390 VkResult 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 
debug_utils_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks *pAllocator)409 VKAPI_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 
debug_utils_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg)419 VKAPI_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
terminator_CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback)430 VKAPI_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 
483 out:
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
terminator_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks *pAllocator)506 VKAPI_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
terminator_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg)532 VKAPI_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 
557 const 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 
destroy_debug_callbacks_chain(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator)562 void 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 
add_debug_extensions_to_ext_list(const struct loader_instance *inst, struct loader_extension_list *ext_list)573 VkResult 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 
check_for_enabled_debug_extensions(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo)578 void 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 
debug_extensions_InstanceGpa(struct loader_instance *ptr_instance, const char *name, void **addr)588 bool 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 
debug_utils_ReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec, VkDebugUtilsMessageSeverityFlagBitsEXT *da_severity, VkDebugUtilsMessageTypeFlagsEXT *da_type)621 bool 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 
debug_utils_AnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity, VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags)658 bool 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 
debug_utils_ReportObjectToAnnotObject(VkDebugReportObjectTypeEXT dr_object_type, uint64_t object_handle, VkDebugUtilsObjectNameInfoEXT *da_object_name_info)683 bool 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 
debug_utils_AnnotObjectToDebugReportObject(const VkDebugUtilsObjectNameInfoEXT *da_object_name_info, VkDebugReportObjectTypeEXT *dr_object_type, uint64_t *dr_object_handle)696 bool 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