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