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