1 /* Copyright (c) 2015-2019 The Khronos Group Inc.
2 * Copyright (c) 2015-2019 Valve Corporation
3 * Copyright (c) 2015-2019 LunarG, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
18 * Author: Tobin Ehlis <tobin@lunarg.com>
19 * Author: Mark Young <marky@lunarg.com>
20 * Author: Dave Houlton <daveh@lunarg.com>
21 *
22 */
23
24 #ifndef LAYER_LOGGING_H
25 #define LAYER_LOGGING_H
26
27 #include "vk_loader_layer.h"
28 #include "vk_layer_config.h"
29 #include "vk_layer_data.h"
30 #include "vk_loader_platform.h"
31 #include "vulkan/vk_layer.h"
32 #include "vk_object_types.h"
33 #include "vk_validation_error_messages.h"
34 #include "vk_layer_dispatch_table.h"
35 #include <mutex>
36 #include <signal.h>
37 #include <cinttypes>
38 #include <stdarg.h>
39 #include <stdbool.h>
40 #include <stdio.h>
41 #include <unordered_map>
42 #include <vector>
43 #include <sstream>
44 #include <string>
45
46 // Suppress unused warning on Linux
47 #if defined(__GNUC__)
48 #define DECORATE_UNUSED __attribute__((unused))
49 #else
50 #define DECORATE_UNUSED
51 #endif
52
53 #if defined __ANDROID__
54 #include <android/log.h>
55 #define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "VALIDATION", __VA_ARGS__))
56 #else
57 #define LOGCONSOLE(...) \
58 { \
59 printf(__VA_ARGS__); \
60 printf("\n"); \
61 }
62 #endif
63
64 static const char DECORATE_UNUSED *kVUIDUndefined = "VUID_Undefined";
65
66 #undef DECORATE_UNUSED
67
68 // TODO: Could be autogenerated for the specific handles for extra type safety...
69 template <typename HANDLE_T>
HandleToUint64(HANDLE_T * h)70 static inline uint64_t HandleToUint64(HANDLE_T *h) {
71 return reinterpret_cast<uint64_t>(h);
72 }
73
HandleToUint64(uint64_t h)74 static inline uint64_t HandleToUint64(uint64_t h) { return h; }
75
76 // Data we store per label for logging
77 typedef struct _LoggingLabelData {
78 std::string name;
79 float color[4];
80 } LoggingLabelData;
81
82 typedef struct _debug_report_data {
83 VkLayerDbgFunctionNode *debug_callback_list{nullptr};
84 VkLayerDbgFunctionNode *default_debug_callback_list{nullptr};
85 VkDebugUtilsMessageSeverityFlagsEXT active_severities{0};
86 VkDebugUtilsMessageTypeFlagsEXT active_types{0};
87 bool g_DEBUG_REPORT{false};
88 bool g_DEBUG_UTILS{false};
89 bool queueLabelHasInsert{false};
90 bool cmdBufLabelHasInsert{false};
91 std::unordered_map<uint64_t, std::string> debugObjectNameMap;
92 std::unordered_map<uint64_t, std::string> debugUtilsObjectNameMap;
93 std::unordered_map<VkQueue, std::vector<LoggingLabelData>> debugUtilsQueueLabels;
94 std::unordered_map<VkCommandBuffer, std::vector<LoggingLabelData>> debugUtilsCmdBufLabels;
95 // This mutex is defined as mutable since the normal usage for a debug report object is as 'const'. The mutable keyword allows
96 // the layers to continue this pattern, but also allows them to use/change this specific member for synchronization purposes.
97 mutable std::mutex debug_report_mutex;
98
DebugReportSetUtilsObjectName_debug_report_data99 void DebugReportSetUtilsObjectName(const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
100 std::unique_lock<std::mutex> lock(debug_report_mutex);
101 if (pNameInfo->pObjectName) {
102 debugUtilsObjectNameMap[pNameInfo->objectHandle] = pNameInfo->pObjectName;
103 } else {
104 debugUtilsObjectNameMap.erase(pNameInfo->objectHandle);
105 }
106 }
107
DebugReportSetMarkerObjectName_debug_report_data108 void DebugReportSetMarkerObjectName(const VkDebugMarkerObjectNameInfoEXT *pNameInfo) {
109 std::unique_lock<std::mutex> lock(debug_report_mutex);
110 if (pNameInfo->pObjectName) {
111 debugObjectNameMap[pNameInfo->object] = pNameInfo->pObjectName;
112 } else {
113 debugObjectNameMap.erase(pNameInfo->object);
114 }
115 }
116
DebugReportGetUtilsObjectName_debug_report_data117 std::string DebugReportGetUtilsObjectName(const uint64_t object) const {
118 std::string label = "";
119 const auto utils_name_iter = debugUtilsObjectNameMap.find(object);
120 if (utils_name_iter != debugUtilsObjectNameMap.end()) {
121 label = utils_name_iter->second;
122 }
123 return label;
124 }
125
DebugReportGetMarkerObjectName_debug_report_data126 std::string DebugReportGetMarkerObjectName(const uint64_t object) const {
127 std::string label = "";
128 const auto marker_name_iter = debugObjectNameMap.find(object);
129 if (marker_name_iter != debugObjectNameMap.end()) {
130 label = marker_name_iter->second;
131 }
132 return label;
133 }
134
135 template <typename HANDLE_T>
FormatHandle_debug_report_data136 std::string FormatHandle(HANDLE_T *h) const {
137 return FormatHandle(HandleToUint64(h));
138 }
139
FormatHandle_debug_report_data140 std::string FormatHandle(uint64_t h) const {
141 char uint64_string[64];
142 sprintf(uint64_string, "0x%" PRIxLEAST64, h);
143 std::string ret = uint64_string;
144
145 std::string name = DebugReportGetUtilsObjectName(h);
146 if (name.empty()) {
147 name = DebugReportGetMarkerObjectName(h);
148 }
149 if (!name.empty()) {
150 ret.append("[");
151 ret.append(name);
152 ret.append("]");
153 }
154 return ret;
155 }
156
157 } debug_report_data;
158
159 template debug_report_data *GetLayerDataPtr<debug_report_data>(void *data_key,
160 std::unordered_map<void *, debug_report_data *> &data_map);
161
DebugReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags,bool default_flag_is_spec,VkDebugUtilsMessageSeverityFlagsEXT * da_severity,VkDebugUtilsMessageTypeFlagsEXT * da_type)162 static inline void DebugReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec,
163 VkDebugUtilsMessageSeverityFlagsEXT *da_severity,
164 VkDebugUtilsMessageTypeFlagsEXT *da_type) {
165 *da_severity = 0;
166 *da_type = 0;
167 // If it's explicitly listed as a performance warning, treat it as a performance message.
168 // Otherwise, treat it as a validation issue.
169 if ((dr_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0) {
170 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
171 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
172 }
173 if ((dr_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0) {
174 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
175 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
176 }
177 if ((dr_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0) {
178 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
179 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
180 }
181 if ((dr_flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) != 0) {
182 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
183 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
184 }
185 if ((dr_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) {
186 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
187 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
188 }
189 }
190
191 // Forward Declarations
192 static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
193 uint64_t src_object, size_t location, const char *layer_prefix, const char *message,
194 const char *text_vuid);
195
196 // Add a debug message callback node structure to the specified callback linked list
AddDebugCallbackNode(debug_report_data * debug_data,VkLayerDbgFunctionNode ** list_head,VkLayerDbgFunctionNode * new_node)197 static inline void AddDebugCallbackNode(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
198 VkLayerDbgFunctionNode *new_node) {
199 new_node->pNext = *list_head;
200 *list_head = new_node;
201 }
202
203 // Remove specified debug messenger node structure from the specified linked list
RemoveDebugUtilsMessenger(debug_report_data * debug_data,VkLayerDbgFunctionNode ** list_head,VkDebugUtilsMessengerEXT messenger)204 static inline void RemoveDebugUtilsMessenger(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
205 VkDebugUtilsMessengerEXT messenger) {
206 VkLayerDbgFunctionNode *cur_callback = *list_head;
207 VkLayerDbgFunctionNode *prev_callback = nullptr;
208 bool matched = false;
209 VkFlags local_severities = 0;
210 VkFlags local_types = 0;
211
212 while (cur_callback) {
213 if (cur_callback->is_messenger) {
214 // If it's actually a messenger, then set it up for deletion.
215 if (cur_callback->messenger.messenger == messenger) {
216 matched = true;
217 if (*list_head == cur_callback) {
218 *list_head = cur_callback->pNext;
219 } else {
220 assert(nullptr != prev_callback);
221 prev_callback->pNext = cur_callback->pNext;
222 }
223 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
224 reinterpret_cast<uint64_t &>(cur_callback->messenger.messenger), 0, "DebugUtilsMessenger",
225 "Destroyed messenger\n", kVUIDUndefined);
226 } else {
227 // If it's not the one we're looking for, just keep the types/severities
228 local_severities |= cur_callback->messenger.messageSeverity;
229 local_types |= cur_callback->messenger.messageType;
230 }
231 } else {
232 // If it's not a messenger, just keep the types/severities
233 VkFlags this_severities = 0;
234 VkFlags this_types = 0;
235 DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types);
236 local_severities |= this_severities;
237 local_types |= this_types;
238 }
239 if (matched) {
240 free(cur_callback);
241 matched = false;
242 // Intentionally keep the last prev_callback, but select the proper cur_callback
243 if (nullptr != prev_callback) {
244 cur_callback = prev_callback->pNext;
245 } else {
246 cur_callback = *list_head;
247 }
248 } else {
249 prev_callback = cur_callback;
250 cur_callback = cur_callback->pNext;
251 }
252 }
253 debug_data->active_severities = local_severities;
254 debug_data->active_types = local_types;
255 }
256
257 // Remove specified debug message callback node structure from the specified callback linked list
RemoveDebugUtilsMessageCallback(debug_report_data * debug_data,VkLayerDbgFunctionNode ** list_head,VkDebugReportCallbackEXT callback)258 static inline void RemoveDebugUtilsMessageCallback(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
259 VkDebugReportCallbackEXT callback) {
260 VkLayerDbgFunctionNode *cur_callback = *list_head;
261 VkLayerDbgFunctionNode *prev_callback = nullptr;
262 bool matched = false;
263 VkFlags local_severities = 0;
264 VkFlags local_types = 0;
265
266 while (cur_callback) {
267 if (!cur_callback->is_messenger) {
268 // If it's actually a callback, then set it up for deletion.
269 if (cur_callback->report.msgCallback == callback) {
270 matched = true;
271 if (*list_head == cur_callback) {
272 *list_head = cur_callback->pNext;
273 } else {
274 assert(nullptr != prev_callback);
275 prev_callback->pNext = cur_callback->pNext;
276 }
277 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
278 reinterpret_cast<uint64_t &>(cur_callback->report.msgCallback), 0, "DebugReport",
279 "Destroyed callback\n", kVUIDUndefined);
280 } else {
281 // If it's not the one we're looking for, just keep the types/severities
282 VkFlags this_severities = 0;
283 VkFlags this_types = 0;
284 DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types);
285 local_severities |= this_severities;
286 local_types |= this_types;
287 }
288 } else {
289 // If it's not a callback, just keep the types/severities
290 local_severities |= cur_callback->messenger.messageSeverity;
291 local_types |= cur_callback->messenger.messageType;
292 }
293 if (matched) {
294 free(cur_callback);
295 matched = false;
296 // Intentionally keep the last prev_callback, but select the proper cur_callback
297 if (nullptr != prev_callback) {
298 cur_callback = prev_callback->pNext;
299 } else {
300 cur_callback = *list_head;
301 }
302 } else {
303 prev_callback = cur_callback;
304 cur_callback = cur_callback->pNext;
305 }
306 }
307 debug_data->active_severities = local_severities;
308 debug_data->active_types = local_types;
309 }
310
311 // Removes all debug callback function nodes from the specified callback linked lists and frees their resources
RemoveAllMessageCallbacks(debug_report_data * debug_data,VkLayerDbgFunctionNode ** list_head)312 static inline void RemoveAllMessageCallbacks(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head) {
313 VkLayerDbgFunctionNode *current_callback = *list_head;
314 VkLayerDbgFunctionNode *prev_callback = current_callback;
315
316 while (current_callback) {
317 prev_callback = current_callback->pNext;
318 if (!current_callback->is_messenger) {
319 debug_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
320 (uint64_t)current_callback->report.msgCallback, 0, "DebugReport",
321 "Debug Report callbacks not removed before DestroyInstance", kVUIDUndefined);
322 } else {
323 debug_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
324 (uint64_t)current_callback->messenger.messenger, 0, "Messenger",
325 "Debug messengers not removed before DestroyInstance", kVUIDUndefined);
326 }
327 free(current_callback);
328 current_callback = prev_callback;
329 }
330 *list_head = NULL;
331 }
332
debug_log_msg(const debug_report_data * debug_data,VkFlags msg_flags,VkDebugReportObjectTypeEXT object_type,uint64_t src_object,size_t location,const char * layer_prefix,const char * message,const char * text_vuid)333 static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
334 uint64_t src_object, size_t location, const char *layer_prefix, const char *message,
335 const char *text_vuid) {
336 bool bail = false;
337 VkLayerDbgFunctionNode *layer_dbg_node = NULL;
338
339 if (debug_data->debug_callback_list != NULL) {
340 layer_dbg_node = debug_data->debug_callback_list;
341 } else {
342 layer_dbg_node = debug_data->default_debug_callback_list;
343 }
344
345 VkDebugUtilsMessageSeverityFlagsEXT severity;
346 VkDebugUtilsMessageTypeFlagsEXT types;
347 VkDebugUtilsMessengerCallbackDataEXT callback_data;
348 VkDebugUtilsObjectNameInfoEXT object_name_info;
349
350 // Convert the info to the VK_EXT_debug_utils form in case we need it.
351 DebugReportFlagsToAnnotFlags(msg_flags, true, &severity, &types);
352 object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
353 object_name_info.pNext = NULL;
354 object_name_info.objectType = convertDebugReportObjectToCoreObject(object_type);
355 object_name_info.objectHandle = (uint64_t)(uintptr_t)src_object;
356 object_name_info.pObjectName = NULL;
357
358 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
359 callback_data.pNext = NULL;
360 callback_data.flags = 0;
361 callback_data.pMessageIdName = text_vuid;
362 callback_data.messageIdNumber = 0; // deprecated, validation layers use only the pMessageIdName
363 callback_data.pMessage = message;
364 callback_data.queueLabelCount = 0;
365 callback_data.pQueueLabels = NULL;
366 callback_data.cmdBufLabelCount = 0;
367 callback_data.pCmdBufLabels = NULL;
368 callback_data.objectCount = 1;
369 callback_data.pObjects = &object_name_info;
370
371 VkDebugUtilsLabelEXT *queue_labels = nullptr;
372 VkDebugUtilsLabelEXT *cmd_buf_labels = nullptr;
373 std::string new_debug_report_message = "";
374 std::ostringstream oss;
375
376 if (0 != src_object) {
377 oss << "Object: 0x" << std::hex << src_object;
378 // If this is a queue, add any queue labels to the callback data.
379 if (VK_OBJECT_TYPE_QUEUE == object_name_info.objectType) {
380 auto label_iter = debug_data->debugUtilsQueueLabels.find(reinterpret_cast<VkQueue>(src_object));
381 if (label_iter != debug_data->debugUtilsQueueLabels.end()) {
382 queue_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
383 if (nullptr != queue_labels) {
384 // Record the labels, but record them in reverse order since we want the
385 // most recent at the top.
386 uint32_t label_size = static_cast<uint32_t>(label_iter->second.size());
387 uint32_t last_index = label_size - 1;
388 for (uint32_t label = 0; label < label_size; ++label) {
389 queue_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
390 queue_labels[last_index - label].pNext = nullptr;
391 queue_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
392 queue_labels[last_index - label].color[0] = label_iter->second[label].color[0];
393 queue_labels[last_index - label].color[1] = label_iter->second[label].color[1];
394 queue_labels[last_index - label].color[2] = label_iter->second[label].color[2];
395 queue_labels[last_index - label].color[3] = label_iter->second[label].color[3];
396 }
397 callback_data.queueLabelCount = label_size;
398 callback_data.pQueueLabels = queue_labels;
399 }
400 }
401 // If this is a command buffer, add any command buffer labels to the callback data.
402 } else if (VK_OBJECT_TYPE_COMMAND_BUFFER == object_name_info.objectType) {
403 auto label_iter = debug_data->debugUtilsCmdBufLabels.find(reinterpret_cast<VkCommandBuffer>(src_object));
404 if (label_iter != debug_data->debugUtilsCmdBufLabels.end()) {
405 cmd_buf_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
406 if (nullptr != cmd_buf_labels) {
407 // Record the labels, but record them in reverse order since we want the
408 // most recent at the top.
409 uint32_t label_size = static_cast<uint32_t>(label_iter->second.size());
410 uint32_t last_index = label_size - 1;
411 for (uint32_t label = 0; label < label_size; ++label) {
412 cmd_buf_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
413 cmd_buf_labels[last_index - label].pNext = nullptr;
414 cmd_buf_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
415 cmd_buf_labels[last_index - label].color[0] = label_iter->second[label].color[0];
416 cmd_buf_labels[last_index - label].color[1] = label_iter->second[label].color[1];
417 cmd_buf_labels[last_index - label].color[2] = label_iter->second[label].color[2];
418 cmd_buf_labels[last_index - label].color[3] = label_iter->second[label].color[3];
419 }
420 callback_data.cmdBufLabelCount = label_size;
421 callback_data.pCmdBufLabels = cmd_buf_labels;
422 }
423 }
424 }
425
426 // Look for any debug utils or marker names to use for this object
427 std::string label = debug_data->DebugReportGetUtilsObjectName(src_object);
428 if (label.empty()) {
429 label = debug_data->DebugReportGetMarkerObjectName(src_object);
430 }
431 if (!label.empty()) {
432 object_name_info.pObjectName = label.c_str();
433 oss << " (Name = " << label << " : Type = ";
434 } else {
435 oss << " (Type = ";
436 }
437 oss << std::to_string(object_type) << ")";
438 } else {
439 oss << "Object: VK_NULL_HANDLE (Type = " << std::to_string(object_type) << ")";
440 }
441 new_debug_report_message += oss.str();
442 new_debug_report_message += " | ";
443 new_debug_report_message += message;
444
445 while (layer_dbg_node) {
446 // If the app uses the VK_EXT_debug_report extension, call all of those registered callbacks.
447 if (!layer_dbg_node->is_messenger && (layer_dbg_node->report.msgFlags & msg_flags)) {
448 if (text_vuid != nullptr) {
449 // If a text vuid is supplied for the old debug report extension, prepend it to the message string
450 new_debug_report_message.insert(0, " ] ");
451 new_debug_report_message.insert(0, text_vuid);
452 new_debug_report_message.insert(0, " [ ");
453 }
454
455 if (layer_dbg_node->report.pfnMsgCallback(msg_flags, object_type, src_object, location, 0, layer_prefix,
456 new_debug_report_message.c_str(), layer_dbg_node->pUserData)) {
457 bail = true;
458 }
459 // If the app uses the VK_EXT_debug_utils extension, call all of those registered callbacks.
460 } else if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & severity) &&
461 (layer_dbg_node->messenger.messageType & types)) {
462 if (layer_dbg_node->messenger.pfnUserCallback(static_cast<VkDebugUtilsMessageSeverityFlagBitsEXT>(severity), types,
463 &callback_data, layer_dbg_node->pUserData)) {
464 bail = true;
465 }
466 }
467 layer_dbg_node = layer_dbg_node->pNext;
468 }
469
470 if (nullptr != queue_labels) {
471 delete[] queue_labels;
472 }
473 if (nullptr != cmd_buf_labels) {
474 delete[] cmd_buf_labels;
475 }
476
477 return bail;
478 }
479
DebugAnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,VkDebugUtilsMessageTypeFlagsEXT da_type,VkDebugReportFlagsEXT * dr_flags)480 static inline void DebugAnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,
481 VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags) {
482 *dr_flags = 0;
483
484 if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) {
485 *dr_flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
486 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) {
487 if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) {
488 *dr_flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
489 } else {
490 *dr_flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
491 }
492 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) {
493 *dr_flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
494 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) {
495 *dr_flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
496 }
497 }
498
debug_messenger_log_msg(const debug_report_data * debug_data,VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,VkDebugUtilsMessageTypeFlagsEXT message_type,VkDebugUtilsMessengerCallbackDataEXT * callback_data,const VkDebugUtilsMessengerEXT * messenger)499 static inline bool debug_messenger_log_msg(const debug_report_data *debug_data,
500 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
501 VkDebugUtilsMessageTypeFlagsEXT message_type,
502 VkDebugUtilsMessengerCallbackDataEXT *callback_data,
503 const VkDebugUtilsMessengerEXT *messenger) {
504 bool bail = false;
505 VkLayerDbgFunctionNode *layer_dbg_node = NULL;
506
507 if (debug_data->debug_callback_list != NULL) {
508 layer_dbg_node = debug_data->debug_callback_list;
509 } else {
510 layer_dbg_node = debug_data->default_debug_callback_list;
511 }
512
513 VkDebugReportFlagsEXT object_flags = 0;
514
515 DebugAnnotFlagsToReportFlags(message_severity, message_type, &object_flags);
516
517 VkDebugUtilsObjectNameInfoEXT object_name_info;
518 object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
519 object_name_info.pNext = NULL;
520 object_name_info.objectType = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT;
521 object_name_info.objectHandle = HandleToUint64(*messenger);
522 object_name_info.pObjectName = NULL;
523 callback_data->pObjects = &object_name_info;
524 callback_data->objectCount = 1;
525
526 while (layer_dbg_node) {
527 if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & message_severity) &&
528 (layer_dbg_node->messenger.messageType & message_type)) {
529 std::string messenger_label = debug_data->DebugReportGetUtilsObjectName(object_name_info.objectHandle);
530 if (!messenger_label.empty()) {
531 object_name_info.pObjectName = messenger_label.c_str();
532 }
533 if (layer_dbg_node->messenger.pfnUserCallback(message_severity, message_type, callback_data,
534 layer_dbg_node->pUserData)) {
535 bail = true;
536 }
537 } else if (!layer_dbg_node->is_messenger && layer_dbg_node->report.msgFlags & object_flags) {
538 VkDebugReportObjectTypeEXT object_type = convertCoreObjectToDebugReportObject(callback_data->pObjects[0].objectType);
539 std::string marker_label = debug_data->DebugReportGetMarkerObjectName(object_name_info.objectHandle);
540 if (marker_label.empty()) {
541 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
542 callback_data->messageIdNumber, callback_data->pMessageIdName,
543 callback_data->pMessage, layer_dbg_node->pUserData)) {
544 bail = true;
545 }
546 } else {
547 std::string newMsg = "SrcObject name = " + marker_label;
548 newMsg.append(" ");
549 newMsg.append(callback_data->pMessage);
550 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
551 callback_data->messageIdNumber, callback_data->pMessageIdName,
552 newMsg.c_str(), layer_dbg_node->pUserData)) {
553 bail = true;
554 }
555 }
556 }
557 layer_dbg_node = layer_dbg_node->pNext;
558 }
559
560 return bail;
561 }
562
debug_utils_create_instance(VkLayerInstanceDispatchTable * table,VkInstance inst,uint32_t extension_count,const char * const * enabled_extensions)563 static inline debug_report_data *debug_utils_create_instance(
564 VkLayerInstanceDispatchTable *table, VkInstance inst, uint32_t extension_count,
565 const char *const *enabled_extensions) // layer or extension name to be enabled
566 {
567 debug_report_data *debug_data = new debug_report_data;
568 for (uint32_t i = 0; i < extension_count; i++) {
569 if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
570 debug_data->g_DEBUG_REPORT = true;
571 } else if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
572 debug_data->g_DEBUG_UTILS = true;
573 }
574 }
575 return debug_data;
576 }
577
layer_debug_utils_destroy_instance(debug_report_data * debug_data)578 static inline void layer_debug_utils_destroy_instance(debug_report_data *debug_data) {
579 if (debug_data) {
580 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
581 RemoveAllMessageCallbacks(debug_data, &debug_data->default_debug_callback_list);
582 RemoveAllMessageCallbacks(debug_data, &debug_data->debug_callback_list);
583 lock.unlock();
584 delete (debug_data);
585 }
586 }
587
layer_debug_utils_create_device(debug_report_data * instance_debug_data,VkDevice device)588 static inline debug_report_data *layer_debug_utils_create_device(debug_report_data *instance_debug_data, VkDevice device) {
589 // DEBUG_REPORT shares data between Instance and Device,
590 // so just return instance's data pointer
591 return instance_debug_data;
592 }
593
layer_debug_utils_destroy_device(VkDevice device)594 static inline void layer_debug_utils_destroy_device(VkDevice device) {
595 // Nothing to do since we're using instance data record
596 }
597
layer_destroy_messenger_callback(debug_report_data * debug_data,VkDebugUtilsMessengerEXT messenger,const VkAllocationCallbacks * allocator)598 static inline void layer_destroy_messenger_callback(debug_report_data *debug_data, VkDebugUtilsMessengerEXT messenger,
599 const VkAllocationCallbacks *allocator) {
600 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
601 RemoveDebugUtilsMessenger(debug_data, &debug_data->debug_callback_list, messenger);
602 RemoveDebugUtilsMessenger(debug_data, &debug_data->default_debug_callback_list, messenger);
603 }
604
layer_create_messenger_callback(debug_report_data * debug_data,bool default_callback,const VkDebugUtilsMessengerCreateInfoEXT * create_info,const VkAllocationCallbacks * allocator,VkDebugUtilsMessengerEXT * messenger)605 static inline VkResult layer_create_messenger_callback(debug_report_data *debug_data, bool default_callback,
606 const VkDebugUtilsMessengerCreateInfoEXT *create_info,
607 const VkAllocationCallbacks *allocator,
608 VkDebugUtilsMessengerEXT *messenger) {
609 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
610 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
611 if (!pNewDbgFuncNode) return VK_ERROR_OUT_OF_HOST_MEMORY;
612 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
613 pNewDbgFuncNode->is_messenger = true;
614
615 // Handle of 0 is logging_callback so use allocated Node address as unique handle
616 if (!(*messenger)) *messenger = (VkDebugUtilsMessengerEXT)pNewDbgFuncNode;
617 pNewDbgFuncNode->messenger.messenger = *messenger;
618 pNewDbgFuncNode->messenger.pfnUserCallback = create_info->pfnUserCallback;
619 pNewDbgFuncNode->messenger.messageSeverity = create_info->messageSeverity;
620 pNewDbgFuncNode->messenger.messageType = create_info->messageType;
621 pNewDbgFuncNode->pUserData = create_info->pUserData;
622
623 debug_data->active_severities |= create_info->messageSeverity;
624 debug_data->active_types |= create_info->messageType;
625 if (default_callback) {
626 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
627 } else {
628 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
629 }
630
631 VkDebugUtilsMessengerCallbackDataEXT callback_data = {};
632 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
633 callback_data.pNext = NULL;
634 callback_data.flags = 0;
635 callback_data.pMessageIdName = "Layer Internal Message";
636 callback_data.messageIdNumber = 0;
637 callback_data.pMessage = "Added messenger";
638 callback_data.queueLabelCount = 0;
639 callback_data.pQueueLabels = NULL;
640 callback_data.cmdBufLabelCount = 0;
641 callback_data.pCmdBufLabels = NULL;
642 callback_data.objectCount = 0;
643 callback_data.pObjects = NULL;
644 debug_messenger_log_msg(debug_data, VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
645 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, &callback_data, messenger);
646 return VK_SUCCESS;
647 }
648
layer_destroy_report_callback(debug_report_data * debug_data,VkDebugReportCallbackEXT callback,const VkAllocationCallbacks * allocator)649 static inline void layer_destroy_report_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback,
650 const VkAllocationCallbacks *allocator) {
651 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
652 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->debug_callback_list, callback);
653 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->default_debug_callback_list, callback);
654 }
655
layer_create_report_callback(debug_report_data * debug_data,bool default_callback,const VkDebugReportCallbackCreateInfoEXT * create_info,const VkAllocationCallbacks * allocator,VkDebugReportCallbackEXT * callback)656 static inline VkResult layer_create_report_callback(debug_report_data *debug_data, bool default_callback,
657 const VkDebugReportCallbackCreateInfoEXT *create_info,
658 const VkAllocationCallbacks *allocator, VkDebugReportCallbackEXT *callback) {
659 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
660 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
661 if (!pNewDbgFuncNode) {
662 return VK_ERROR_OUT_OF_HOST_MEMORY;
663 }
664 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
665 pNewDbgFuncNode->is_messenger = false;
666
667 // Handle of 0 is logging_callback so use allocated Node address as unique handle
668 if (!(*callback)) *callback = (VkDebugReportCallbackEXT)pNewDbgFuncNode;
669 pNewDbgFuncNode->report.msgCallback = *callback;
670 pNewDbgFuncNode->report.pfnMsgCallback = create_info->pfnCallback;
671 pNewDbgFuncNode->report.msgFlags = create_info->flags;
672 pNewDbgFuncNode->pUserData = create_info->pUserData;
673
674 VkFlags local_severity = 0;
675 VkFlags local_type = 0;
676 DebugReportFlagsToAnnotFlags(create_info->flags, true, &local_severity, &local_type);
677 debug_data->active_severities |= local_severity;
678 debug_data->active_types |= local_type;
679 if (default_callback) {
680 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
681 } else {
682 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
683 }
684
685 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, (uint64_t)*callback, 0,
686 "DebugReport", "Added callback", kVUIDUndefined);
687 return VK_SUCCESS;
688 }
689
debug_utils_get_instance_proc_addr(debug_report_data * debug_data,const char * func_name)690 static inline PFN_vkVoidFunction debug_utils_get_instance_proc_addr(debug_report_data *debug_data, const char *func_name) {
691 if (!debug_data) {
692 return NULL;
693 }
694 if (debug_data->g_DEBUG_REPORT) {
695 if (!strcmp(func_name, "vkCreateDebugReportCallbackEXT")) {
696 return (PFN_vkVoidFunction)vkCreateDebugReportCallbackEXT;
697 }
698 if (!strcmp(func_name, "vkDestroyDebugReportCallbackEXT")) {
699 return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT;
700 }
701 if (!strcmp(func_name, "vkDebugReportMessageEXT")) {
702 return (PFN_vkVoidFunction)vkDebugReportMessageEXT;
703 }
704 }
705 if (debug_data->g_DEBUG_UTILS) {
706 if (!strcmp(func_name, "vkCreateDebugUtilsMessengerEXT")) {
707 return (PFN_vkVoidFunction)vkCreateDebugUtilsMessengerEXT;
708 }
709 if (!strcmp(func_name, "vkDestroyDebugUtilsMessengerEXT")) {
710 return (PFN_vkVoidFunction)vkDestroyDebugUtilsMessengerEXT;
711 }
712 if (!strcmp(func_name, "vkSubmitDebugUtilsMessageEXT")) {
713 return (PFN_vkVoidFunction)vkSubmitDebugUtilsMessageEXT;
714 }
715 }
716 return NULL;
717 }
718
719 // This utility (called at vkCreateInstance() time), looks at a pNext chain.
720 // It counts any VkDebugReportCallbackCreateInfoEXT structs that it finds. It
721 // then allocates an array that can hold that many structs, as well as that
722 // many VkDebugReportCallbackEXT handles. It then copies each
723 // VkDebugReportCallbackCreateInfoEXT, and initializes each handle.
layer_copy_tmp_report_callbacks(const void * pChain,uint32_t * num_callbacks,VkDebugReportCallbackCreateInfoEXT ** infos,VkDebugReportCallbackEXT ** callbacks)724 static inline VkResult layer_copy_tmp_report_callbacks(const void *pChain, uint32_t *num_callbacks,
725 VkDebugReportCallbackCreateInfoEXT **infos,
726 VkDebugReportCallbackEXT **callbacks) {
727 uint32_t n = *num_callbacks = 0;
728
729 const void *pNext = pChain;
730 while (pNext) {
731 // 1st, count the number VkDebugReportCallbackCreateInfoEXT:
732 if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
733 n++;
734 }
735 pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext;
736 }
737 if (n == 0) {
738 return VK_SUCCESS;
739 }
740
741 // 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT:
742 VkDebugReportCallbackCreateInfoEXT *pInfos = *infos =
743 ((VkDebugReportCallbackCreateInfoEXT *)malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT)));
744 if (!pInfos) {
745 return VK_ERROR_OUT_OF_HOST_MEMORY;
746 }
747 // 3rd, allocate memory for a unique handle for each callback:
748 VkDebugReportCallbackEXT *pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)malloc(n * sizeof(VkDebugReportCallbackEXT)));
749 if (!pCallbacks) {
750 free(pInfos);
751 return VK_ERROR_OUT_OF_HOST_MEMORY;
752 }
753 // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by
754 // vkDestroyInstance, and assign a unique handle to each callback (just
755 // use the address of the copied VkDebugReportCallbackCreateInfoEXT):
756 pNext = pChain;
757 while (pNext) {
758 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
759 memcpy(pInfos, pNext, sizeof(VkDebugReportCallbackCreateInfoEXT));
760 *pCallbacks++ = (VkDebugReportCallbackEXT)pInfos++;
761 }
762 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
763 }
764
765 *num_callbacks = n;
766 return VK_SUCCESS;
767 }
768
769 // This utility frees the arrays allocated by layer_copy_tmp_report_callbacks()
layer_free_tmp_report_callbacks(VkDebugReportCallbackCreateInfoEXT * infos,VkDebugReportCallbackEXT * callbacks)770 static inline void layer_free_tmp_report_callbacks(VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) {
771 free(infos);
772 free(callbacks);
773 }
774
775 // This utility enables all of the VkDebugReportCallbackCreateInfoEXT structs
776 // that were copied by layer_copy_tmp_report_callbacks()
layer_enable_tmp_report_callbacks(debug_report_data * debug_data,uint32_t num_callbacks,VkDebugReportCallbackCreateInfoEXT * infos,VkDebugReportCallbackEXT * callbacks)777 static inline VkResult layer_enable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
778 VkDebugReportCallbackCreateInfoEXT *infos,
779 VkDebugReportCallbackEXT *callbacks) {
780 VkResult rtn = VK_SUCCESS;
781 for (uint32_t i = 0; i < num_callbacks; i++) {
782 rtn = layer_create_report_callback(debug_data, false, &infos[i], NULL, &callbacks[i]);
783 if (rtn != VK_SUCCESS) {
784 for (uint32_t j = 0; j < i; j++) {
785 layer_destroy_report_callback(debug_data, callbacks[j], NULL);
786 }
787 return rtn;
788 }
789 }
790 return rtn;
791 }
792
793 // This utility disables all of the VkDebugReportCallbackCreateInfoEXT structs
794 // that were copied by layer_copy_tmp_report_callbacks()
layer_disable_tmp_report_callbacks(debug_report_data * debug_data,uint32_t num_callbacks,VkDebugReportCallbackEXT * callbacks)795 static inline void layer_disable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
796 VkDebugReportCallbackEXT *callbacks) {
797 for (uint32_t i = 0; i < num_callbacks; i++) {
798 layer_destroy_report_callback(debug_data, callbacks[i], NULL);
799 }
800 }
801
802 // This utility (called at vkCreateInstance() time), looks at a pNext chain.
803 // It counts any VkDebugUtilsMessengerCreateInfoEXT structs that it finds. It
804 // then allocates an array that can hold that many structs, as well as that
805 // many VkDebugUtilsMessengerEXT handles. It then copies each
806 // VkDebugUtilsMessengerCreateInfoEXT, and initializes each handle.
layer_copy_tmp_debug_messengers(const void * pChain,uint32_t * num_messengers,VkDebugUtilsMessengerCreateInfoEXT ** infos,VkDebugUtilsMessengerEXT ** messengers)807 static inline VkResult layer_copy_tmp_debug_messengers(const void *pChain, uint32_t *num_messengers,
808 VkDebugUtilsMessengerCreateInfoEXT **infos,
809 VkDebugUtilsMessengerEXT **messengers) {
810 uint32_t n = *num_messengers = 0;
811
812 const void *pNext = pChain;
813 while (pNext) {
814 // 1st, count the number VkDebugUtilsMessengerCreateInfoEXT:
815 if (((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
816 n++;
817 }
818 pNext = (void *)((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->pNext;
819 }
820 if (n == 0) {
821 return VK_SUCCESS;
822 }
823
824 // 2nd, allocate memory for each VkDebugUtilsMessengerCreateInfoEXT:
825 VkDebugUtilsMessengerCreateInfoEXT *pInfos = *infos =
826 ((VkDebugUtilsMessengerCreateInfoEXT *)malloc(n * sizeof(VkDebugUtilsMessengerCreateInfoEXT)));
827 if (!pInfos) {
828 return VK_ERROR_OUT_OF_HOST_MEMORY;
829 }
830 // 3rd, allocate memory for a unique handle for each messenger:
831 VkDebugUtilsMessengerEXT *pMessengers = *messengers =
832 ((VkDebugUtilsMessengerEXT *)malloc(n * sizeof(VkDebugUtilsMessengerEXT)));
833 if (!pMessengers) {
834 free(pInfos);
835 return VK_ERROR_OUT_OF_HOST_MEMORY;
836 }
837 // 4th, copy each VkDebugUtilsMessengerCreateInfoEXT for use by
838 // vkDestroyInstance, and assign a unique handle to each callback (just
839 // use the address of the copied VkDebugUtilsMessengerCreateInfoEXT):
840 pNext = pChain;
841 while (pNext) {
842 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
843 memcpy(pInfos, pNext, sizeof(VkDebugUtilsMessengerCreateInfoEXT));
844 *pMessengers++ = (VkDebugUtilsMessengerEXT)pInfos++;
845 }
846 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
847 }
848
849 *num_messengers = n;
850 return VK_SUCCESS;
851 }
852
853 // This utility frees the arrays allocated by layer_copy_tmp_debug_messengers()
layer_free_tmp_debug_messengers(VkDebugUtilsMessengerCreateInfoEXT * infos,VkDebugUtilsMessengerEXT * messengers)854 static inline void layer_free_tmp_debug_messengers(VkDebugUtilsMessengerCreateInfoEXT *infos,
855 VkDebugUtilsMessengerEXT *messengers) {
856 free(infos);
857 free(messengers);
858 }
859
860 // This utility enables all of the VkDebugUtilsMessengerCreateInfoEXT structs
861 // that were copied by layer_copy_tmp_debug_messengers()
layer_enable_tmp_debug_messengers(debug_report_data * debug_data,uint32_t num_messengers,VkDebugUtilsMessengerCreateInfoEXT * infos,VkDebugUtilsMessengerEXT * messengers)862 static inline VkResult layer_enable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
863 VkDebugUtilsMessengerCreateInfoEXT *infos,
864 VkDebugUtilsMessengerEXT *messengers) {
865 VkResult rtn = VK_SUCCESS;
866 for (uint32_t i = 0; i < num_messengers; i++) {
867 rtn = layer_create_messenger_callback(debug_data, false, &infos[i], NULL, &messengers[i]);
868 if (rtn != VK_SUCCESS) {
869 for (uint32_t j = 0; j < i; j++) {
870 layer_destroy_messenger_callback(debug_data, messengers[j], NULL);
871 }
872 return rtn;
873 }
874 }
875 return rtn;
876 }
877
878 // This utility disables all of the VkDebugUtilsMessengerCreateInfoEXT structs
879 // that were copied by layer_copy_tmp_debug_messengers()
layer_disable_tmp_debug_messengers(debug_report_data * debug_data,uint32_t num_messengers,VkDebugUtilsMessengerEXT * messengers)880 static inline void layer_disable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
881 VkDebugUtilsMessengerEXT *messengers) {
882 for (uint32_t i = 0; i < num_messengers; i++) {
883 layer_destroy_messenger_callback(debug_data, messengers[i], NULL);
884 }
885 }
886
887 // Checks if the message will get logged.
888 // Allows layer to defer collecting & formating data if the
889 // message will be discarded.
will_log_msg(debug_report_data * debug_data,VkFlags msg_flags)890 static inline bool will_log_msg(debug_report_data *debug_data, VkFlags msg_flags) {
891 VkFlags local_severity = 0;
892 VkFlags local_type = 0;
893 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
894 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
895 // Message is not wanted
896 return false;
897 }
898
899 return true;
900 }
901 #ifndef WIN32
902 static inline int string_sprintf(std::string *output, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
903 #endif
string_sprintf(std::string * output,const char * fmt,...)904 static inline int string_sprintf(std::string *output, const char *fmt, ...) {
905 std::string &formatted = *output;
906 va_list argptr;
907 va_start(argptr, fmt);
908 int reserve = vsnprintf(nullptr, 0, fmt, argptr);
909 va_end(argptr);
910 formatted.reserve(reserve + 1); // Set the storage length long enough to hold the output + null
911 formatted.resize(reserve); // Set the *logical* length to be what vsprintf will write
912 va_start(argptr, fmt);
913 int result = vsnprintf((char *)formatted.data(), formatted.capacity(), fmt, argptr);
914 va_end(argptr);
915 assert(result == reserve);
916 assert((formatted.size() == strlen(formatted.c_str())));
917 return result;
918 }
919
920 #ifdef WIN32
vasprintf(char ** strp,char const * fmt,va_list ap)921 static inline int vasprintf(char **strp, char const *fmt, va_list ap) {
922 *strp = nullptr;
923 int size = _vscprintf(fmt, ap);
924 if (size >= 0) {
925 *strp = (char *)malloc(size + 1);
926 if (!*strp) {
927 return -1;
928 }
929 _vsnprintf(*strp, size + 1, fmt, ap);
930 }
931 return size;
932 }
933 #endif
934
935 // Output log message via DEBUG_REPORT. Takes format and variable arg list so that output string is only computed if a message
936 // needs to be logged
937 #ifndef WIN32
938 static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
939 uint64_t src_object, std::string vuid_text, const char *format, ...)
940 __attribute__((format(printf, 6, 7)));
941 #endif
log_msg(const debug_report_data * debug_data,VkFlags msg_flags,VkDebugReportObjectTypeEXT object_type,uint64_t src_object,std::string vuid_text,const char * format,...)942 static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
943 uint64_t src_object, std::string vuid_text, const char *format, ...) {
944 if (!debug_data) return false;
945 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
946 VkFlags local_severity = 0;
947 VkFlags local_type = 0;
948 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
949 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
950 // Message is not wanted
951 return false;
952 }
953
954 va_list argptr;
955 va_start(argptr, format);
956 char *str;
957 if (-1 == vasprintf(&str, format, argptr)) {
958 // On failure, glibc vasprintf leaves str undefined
959 str = nullptr;
960 }
961 va_end(argptr);
962
963 std::string str_plus_spec_text(str ? str : "Allocation failure");
964
965 // Append the spec error text to the error message, unless it's an UNASSIGNED or UNDEFINED vuid
966 if ((vuid_text.find("UNASSIGNED-") == std::string::npos) && (vuid_text.find(kVUIDUndefined) == std::string::npos)) {
967 // Linear search makes no assumptions about the layout of the string table
968 // This is not fast, but it does not need to be at this point in the error reporting path
969 uint32_t num_vuids = sizeof(vuid_spec_text) / sizeof(vuid_spec_text_pair);
970 const char *spec_text = nullptr;
971 for (uint32_t i = 0; i < num_vuids; i++) {
972 if (0 == strcmp(vuid_text.c_str(), vuid_spec_text[i].vuid)) {
973 spec_text = vuid_spec_text[i].spec_text;
974 break;
975 }
976 }
977
978 if (nullptr == spec_text) {
979 // If this happens, you've hit a VUID string that isn't defined in the spec's json file
980 // Try running 'vk_validation_stats -c' to look for invalid VUID strings in the repo code
981 assert(0);
982 } else {
983 str_plus_spec_text += " The Vulkan spec states: ";
984 str_plus_spec_text += spec_text;
985 }
986 }
987
988 // Append layer prefix with VUID string, pass in recovered legacy numerical VUID
989 bool result = debug_log_msg(debug_data, msg_flags, object_type, src_object, 0, "Validation", str_plus_spec_text.c_str(),
990 vuid_text.c_str());
991
992 free(str);
993 return result;
994 }
995
report_log_callback(VkFlags msg_flags,VkDebugReportObjectTypeEXT obj_type,uint64_t src_object,size_t location,int32_t msg_code,const char * layer_prefix,const char * message,void * user_data)996 static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_log_callback(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
997 uint64_t src_object, size_t location, int32_t msg_code,
998 const char *layer_prefix, const char *message, void *user_data) {
999 std::ostringstream msg_buffer;
1000 char msg_flag_string[30];
1001
1002 PrintMessageFlags(msg_flags, msg_flag_string);
1003
1004 msg_buffer << layer_prefix << "(" << msg_flag_string << "): msg_code: " << msg_code << ": " << message << "\n";
1005 const std::string tmp = msg_buffer.str();
1006 const char *cstr = tmp.c_str();
1007
1008 fprintf((FILE *)user_data, "%s", cstr);
1009 fflush((FILE *)user_data);
1010
1011 #if defined __ANDROID__
1012 LOGCONSOLE("%s", cstr);
1013 #endif
1014
1015 return false;
1016 }
1017
report_win32_debug_output_msg(VkFlags msg_flags,VkDebugReportObjectTypeEXT obj_type,uint64_t src_object,size_t location,int32_t msg_code,const char * layer_prefix,const char * message,void * user_data)1018 static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_win32_debug_output_msg(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
1019 uint64_t src_object, size_t location, int32_t msg_code,
1020 const char *layer_prefix, const char *message,
1021 void *user_data) {
1022 #ifdef WIN32
1023 char msg_flag_string[30];
1024 char buf[2048];
1025
1026 PrintMessageFlags(msg_flags, msg_flag_string);
1027 _snprintf(buf, sizeof(buf) - 1, "%s (%s): msg_code: %d: %s\n", layer_prefix, msg_flag_string, msg_code, message);
1028
1029 OutputDebugString(buf);
1030 #endif
1031
1032 return false;
1033 }
1034
DebugBreakCallback(VkFlags msgFlags,VkDebugReportObjectTypeEXT obj_type,uint64_t src_object,size_t location,int32_t msg_code,const char * layer_prefix,const char * message,void * user_data)1035 static inline VKAPI_ATTR VkBool32 VKAPI_CALL DebugBreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT obj_type,
1036 uint64_t src_object, size_t location, int32_t msg_code,
1037 const char *layer_prefix, const char *message, void *user_data) {
1038 #ifdef WIN32
1039 DebugBreak();
1040 #else
1041 raise(SIGTRAP);
1042 #endif
1043
1044 return false;
1045 }
1046
messenger_log_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,VkDebugUtilsMessageTypeFlagsEXT message_type,const VkDebugUtilsMessengerCallbackDataEXT * callback_data,void * user_data)1047 static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_log_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
1048 VkDebugUtilsMessageTypeFlagsEXT message_type,
1049 const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
1050 void *user_data) {
1051 std::ostringstream msg_buffer;
1052 char msg_severity[30];
1053 char msg_type[30];
1054
1055 PrintMessageSeverity(message_severity, msg_severity);
1056 PrintMessageType(message_type, msg_type);
1057
1058 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
1059 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
1060 msg_buffer << " Objects: " << callback_data->objectCount << "\n";
1061 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
1062 msg_buffer << " [" << obj << "] " << std::hex << std::showbase
1063 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
1064 << callback_data->pObjects[obj].objectType
1065 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
1066 << "\n";
1067 }
1068 const std::string tmp = msg_buffer.str();
1069 const char *cstr = tmp.c_str();
1070 fprintf((FILE *)user_data, "%s", cstr);
1071 fflush((FILE *)user_data);
1072
1073 #if defined __ANDROID__
1074 LOGCONSOLE("%s", cstr);
1075 #endif
1076
1077 return false;
1078 }
1079
messenger_win32_debug_output_msg(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,VkDebugUtilsMessageTypeFlagsEXT message_type,const VkDebugUtilsMessengerCallbackDataEXT * callback_data,void * user_data)1080 static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_win32_debug_output_msg(
1081 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type,
1082 const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data) {
1083 #ifdef WIN32
1084 std::ostringstream msg_buffer;
1085 char msg_severity[30];
1086 char msg_type[30];
1087
1088 PrintMessageSeverity(message_severity, msg_severity);
1089 PrintMessageType(message_type, msg_type);
1090
1091 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
1092 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
1093 msg_buffer << " Objects: " << callback_data->objectCount << "\n";
1094
1095 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
1096 msg_buffer << " [" << obj << "] " << std::hex << std::showbase
1097 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
1098 << callback_data->pObjects[obj].objectType
1099 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
1100 << "\n";
1101 }
1102 const std::string tmp = msg_buffer.str();
1103 const char *cstr = tmp.c_str();
1104 OutputDebugString(cstr);
1105 #endif
1106
1107 return false;
1108 }
1109
1110 // This utility converts from the VkDebugUtilsLabelEXT structure into the logging version of the structure.
1111 // In the logging version, we only record what we absolutely need to convey back to the callbacks.
InsertLabelIntoLog(const VkDebugUtilsLabelEXT * utils_label,std::vector<LoggingLabelData> & log_vector)1112 static inline void InsertLabelIntoLog(const VkDebugUtilsLabelEXT *utils_label, std::vector<LoggingLabelData> &log_vector) {
1113 LoggingLabelData log_label_data = {};
1114 log_label_data.name = utils_label->pLabelName;
1115 log_label_data.color[0] = utils_label->color[0];
1116 log_label_data.color[1] = utils_label->color[1];
1117 log_label_data.color[2] = utils_label->color[2];
1118 log_label_data.color[3] = utils_label->color[3];
1119 log_vector.push_back(log_label_data);
1120 }
1121
BeginQueueDebugUtilsLabel(debug_report_data * report_data,VkQueue queue,const VkDebugUtilsLabelEXT * label_info)1122 static inline void BeginQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
1123 const VkDebugUtilsLabelEXT *label_info) {
1124 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
1125 if (nullptr != label_info && nullptr != label_info->pLabelName) {
1126 auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
1127 if (label_iter == report_data->debugUtilsQueueLabels.end()) {
1128 std::vector<LoggingLabelData> new_queue_labels;
1129 InsertLabelIntoLog(label_info, new_queue_labels);
1130 report_data->debugUtilsQueueLabels.insert({queue, new_queue_labels});
1131 } else {
1132 // If the last thing was a label insert, we need to pop it off of the label vector before any
1133 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1134 // temporary location that exists until the next operation occurs. In this case, a new
1135 // "vkQueueBeginDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1136 if (report_data->queueLabelHasInsert) {
1137 report_data->queueLabelHasInsert = false;
1138 label_iter->second.pop_back();
1139 }
1140 InsertLabelIntoLog(label_info, label_iter->second);
1141 }
1142 }
1143 }
1144
EndQueueDebugUtilsLabel(debug_report_data * report_data,VkQueue queue)1145 static inline void EndQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue) {
1146 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
1147 auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
1148 if (label_iter != report_data->debugUtilsQueueLabels.end()) {
1149 // If the last thing was a label insert, we need to pop it off of the label vector before any
1150 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1151 // temporary location that exists until the next operation occurs. In this case, a
1152 // "vkQueueEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
1153 if (report_data->queueLabelHasInsert) {
1154 report_data->queueLabelHasInsert = false;
1155 label_iter->second.pop_back();
1156 }
1157 // Now pop the normal item
1158 label_iter->second.pop_back();
1159 }
1160 }
1161
InsertQueueDebugUtilsLabel(debug_report_data * report_data,VkQueue queue,const VkDebugUtilsLabelEXT * label_info)1162 static inline void InsertQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
1163 const VkDebugUtilsLabelEXT *label_info) {
1164 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
1165 if (nullptr != label_info && nullptr != label_info->pLabelName) {
1166 auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
1167 if (label_iter == report_data->debugUtilsQueueLabels.end()) {
1168 std::vector<LoggingLabelData> new_queue_labels;
1169 InsertLabelIntoLog(label_info, new_queue_labels);
1170 report_data->debugUtilsQueueLabels.insert({queue, new_queue_labels});
1171 } else {
1172 // If the last thing was a label insert, we need to pop it off of the label vector before any
1173 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1174 // temporary location that exists until the next operation occurs. In this case, a new
1175 // "vkQueueInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1176 if (report_data->queueLabelHasInsert) {
1177 label_iter->second.pop_back();
1178 }
1179 // Insert this new label and mark it as one that has been "inserted" so we can remove it on
1180 // the next queue label operation.
1181 InsertLabelIntoLog(label_info, label_iter->second);
1182 report_data->queueLabelHasInsert = true;
1183 }
1184 }
1185 }
1186
BeginCmdDebugUtilsLabel(debug_report_data * report_data,VkCommandBuffer command_buffer,const VkDebugUtilsLabelEXT * label_info)1187 static inline void BeginCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1188 const VkDebugUtilsLabelEXT *label_info) {
1189 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
1190 if (nullptr != label_info && nullptr != label_info->pLabelName) {
1191 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
1192 if (label_iter == report_data->debugUtilsCmdBufLabels.end()) {
1193 std::vector<LoggingLabelData> new_cmdbuf_labels;
1194 InsertLabelIntoLog(label_info, new_cmdbuf_labels);
1195 report_data->debugUtilsCmdBufLabels.insert({command_buffer, new_cmdbuf_labels});
1196 } else {
1197 // If the last thing was a label insert, we need to pop it off of the label vector before any
1198 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1199 // temporary location that exists until the next operation occurs. In this case, a
1200 // "vkCmdBeginDebugUtilsLabelEXT" has occurred erasing the inserted label.
1201 if (report_data->cmdBufLabelHasInsert) {
1202 report_data->cmdBufLabelHasInsert = false;
1203 label_iter->second.pop_back();
1204 }
1205 InsertLabelIntoLog(label_info, label_iter->second);
1206 }
1207 }
1208 }
1209
EndCmdDebugUtilsLabel(debug_report_data * report_data,VkCommandBuffer command_buffer)1210 static inline void EndCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
1211 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
1212 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
1213 if (label_iter != report_data->debugUtilsCmdBufLabels.end()) {
1214 // If the last thing was a label insert, we need to pop it off of the label vector before any
1215 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1216 // temporary location that exists until the next operation occurs. In this case, a
1217 // "vkCmdEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
1218 if (report_data->cmdBufLabelHasInsert) {
1219 report_data->cmdBufLabelHasInsert = false;
1220 label_iter->second.pop_back();
1221 }
1222 // Guard against unbalanced markers.
1223 if (label_iter->second.size() > 0) {
1224 // Now pop the normal item
1225 label_iter->second.pop_back();
1226 }
1227 }
1228 }
1229
InsertCmdDebugUtilsLabel(debug_report_data * report_data,VkCommandBuffer command_buffer,const VkDebugUtilsLabelEXT * label_info)1230 static inline void InsertCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1231 const VkDebugUtilsLabelEXT *label_info) {
1232 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
1233 if (nullptr != label_info && nullptr != label_info->pLabelName) {
1234 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
1235 if (label_iter == report_data->debugUtilsCmdBufLabels.end()) {
1236 std::vector<LoggingLabelData> new_cmdbuf_labels;
1237 InsertLabelIntoLog(label_info, new_cmdbuf_labels);
1238 report_data->debugUtilsCmdBufLabels.insert({command_buffer, new_cmdbuf_labels});
1239 } else {
1240 // If the last thing was a label insert, we need to pop it off of the label vector before any
1241 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1242 // temporary location that exists until the next operation occurs. In this case, a new
1243 // "vkCmdInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1244 if (report_data->cmdBufLabelHasInsert) {
1245 label_iter->second.pop_back();
1246 }
1247 // Insert this new label and mark it as one that has been "inserted" so we can remove it on
1248 // the next command buffer label operation.
1249 InsertLabelIntoLog(label_info, label_iter->second);
1250 report_data->cmdBufLabelHasInsert = true;
1251 }
1252 }
1253 }
1254
1255 #endif // LAYER_LOGGING_H
1256