• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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