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