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