1 /* Copyright (c) 2015-2020 The Khronos Group Inc.
2  * Copyright (c) 2015-2020 Valve Corporation
3  * Copyright (c) 2015-2020 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 #include <cstring>
43 
44 #include "vk_typemap_helper.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 "vk_enum_string_helper.h"
51 #include "cast_utils.h"
52 #include "vk_validation_error_messages.h"
53 #include "vk_layer_dispatch_table.h"
54 #include "vk_safe_struct.h"
55 #include "xxhash.h"
56 
57 // Suppress unused warning on Linux
58 #if defined(__GNUC__)
59 #define DECORATE_UNUSED __attribute__((unused))
60 #else
61 #define DECORATE_UNUSED
62 #endif
63 
64 #if defined __ANDROID__
65 #include <android/log.h>
66 #define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "VALIDATION", __VA_ARGS__))
67 #else
68 #define LOGCONSOLE(...)      \
69     {                        \
70         printf(__VA_ARGS__); \
71         printf("\n");        \
72     }
73 #endif
74 
75 static const char DECORATE_UNUSED *kVUIDUndefined = "VUID_Undefined";
76 
77 #undef DECORATE_UNUSED
78 
79 typedef enum DebugCallbackStatusBits {
80     DEBUG_CALLBACK_UTILS = 0x00000001,     // This struct describes a VK_EXT_debug_utils callback
81     DEBUG_CALLBACK_DEFAULT = 0x00000002,   // An internally created callback, used if no user-defined callbacks are registered
82     DEBUG_CALLBACK_INSTANCE = 0x00000004,  // An internally created temporary instance callback
83 } DebugCallbackStatusBits;
84 typedef VkFlags DebugCallbackStatusFlags;
85 
86 struct LogObjectList {
87     std::vector<VulkanTypedHandle> object_list;
88 
89     template <typename HANDLE_T>
addLogObjectList90     void add(HANDLE_T object) {
91         VulkanTypedHandle v_t_handle(object, ConvertCoreObjectToVulkanObject(VkHandleInfo<HANDLE_T>::kVkObjectType));
92         object_list.push_back(v_t_handle);
93     }
94 
addLogObjectList95     void add(VulkanTypedHandle typed_handle) { object_list.push_back(typed_handle); }
96 
97     template <typename HANDLE_T>
LogObjectListLogObjectList98     LogObjectList(HANDLE_T object) {
99         add(object);
100     }
101 
LogObjectListLogObjectList102     LogObjectList(){};
103 };
104 
105 typedef struct VkLayerDbgFunctionState {
106     DebugCallbackStatusFlags callback_status;
107 
108     // Debug report related information
109     VkDebugReportCallbackEXT debug_report_callback_object;
110     PFN_vkDebugReportCallbackEXT debug_report_callback_function_ptr;
111     VkFlags debug_report_msg_flags;
112 
113     // Debug utils related information
114     VkDebugUtilsMessengerEXT debug_utils_callback_object;
115     VkDebugUtilsMessageSeverityFlagsEXT debug_utils_msg_flags;
116     VkDebugUtilsMessageTypeFlagsEXT debug_utils_msg_type;
117     PFN_vkDebugUtilsMessengerCallbackEXT debug_utils_callback_function_ptr;
118 
119     void *pUserData;
120 
IsUtilsVkLayerDbgFunctionState121     bool IsUtils() { return ((callback_status & DEBUG_CALLBACK_UTILS) != 0); }
IsDefaultVkLayerDbgFunctionState122     bool IsDefault() { return ((callback_status & DEBUG_CALLBACK_DEFAULT) != 0); }
IsInstanceVkLayerDbgFunctionState123     bool IsInstance() { return ((callback_status & DEBUG_CALLBACK_INSTANCE) != 0); }
124 } VkLayerDbgFunctionState;
125 
126 // TODO: Could be autogenerated for the specific handles for extra type safety...
127 template <typename HANDLE_T>
HandleToUint64(HANDLE_T h)128 static inline uint64_t HandleToUint64(HANDLE_T h) {
129     return CastToUint64<HANDLE_T>(h);
130 }
131 
HandleToUint64(uint64_t h)132 static inline uint64_t HandleToUint64(uint64_t h) { return h; }
133 
134 // Data we store per label for logging
135 struct LoggingLabel {
136     std::string name;
137     std::array<float, 4> color;
138 
ResetLoggingLabel139     void Reset() { *this = LoggingLabel(); }
EmptyLoggingLabel140     bool Empty() const { return name.empty(); }
141 
ExportLoggingLabel142     VkDebugUtilsLabelEXT Export() const {
143         auto out = lvl_init_struct<VkDebugUtilsLabelEXT>();
144         out.pLabelName = name.c_str();
145         std::copy(color.cbegin(), color.cend(), out.color);
146         return out;
147     };
148 
LoggingLabelLoggingLabel149     LoggingLabel() : name(), color({{0.f, 0.f, 0.f, 0.f}}) {}
LoggingLabelLoggingLabel150     LoggingLabel(const VkDebugUtilsLabelEXT *label_info) {
151         if (label_info && label_info->pLabelName) {
152             name = label_info->pLabelName;
153             std::copy_n(std::begin(label_info->color), 4, color.begin());
154         } else {
155             Reset();
156         }
157     }
158 
159     LoggingLabel(const LoggingLabel &) = default;
160     LoggingLabel &operator=(const LoggingLabel &) = default;
161     LoggingLabel &operator=(LoggingLabel &&) = default;
162     LoggingLabel(LoggingLabel &&) = default;
163 
164     template <typename Name, typename Vec>
LoggingLabelLoggingLabel165     LoggingLabel(Name &&name_, Vec &&vec_) : name(std::forward<Name>(name_)), color(std::forward<Vec>(vec_)) {}
166 };
167 
168 struct LoggingLabelState {
169     std::vector<LoggingLabel> labels;
170     LoggingLabel insert_label;
171 
172     // Export the labels, but in reverse order since we want the most recent at the top.
ExportLoggingLabelState173     std::vector<VkDebugUtilsLabelEXT> Export() const {
174         size_t count = labels.size() + (insert_label.Empty() ? 0 : 1);
175         std::vector<VkDebugUtilsLabelEXT> out(count);
176 
177         if (!count) return out;
178 
179         size_t index = count - 1;
180         if (!insert_label.Empty()) {
181             out[index--] = insert_label.Export();
182         }
183         for (const auto &label : labels) {
184             out[index--] = label.Export();
185         }
186         return out;
187     }
188 };
189 
190 typedef struct _debug_report_data {
191     std::vector<VkLayerDbgFunctionState> debug_callback_list;
192     VkDebugUtilsMessageSeverityFlagsEXT active_severities{0};
193     VkDebugUtilsMessageTypeFlagsEXT active_types{0};
194     bool queueLabelHasInsert{false};
195     bool cmdBufLabelHasInsert{false};
196     std::unordered_map<uint64_t, std::string> debugObjectNameMap;
197     std::unordered_map<uint64_t, std::string> debugUtilsObjectNameMap;
198     std::unordered_map<VkQueue, std::unique_ptr<LoggingLabelState>> debugUtilsQueueLabels;
199     std::unordered_map<VkCommandBuffer, std::unique_ptr<LoggingLabelState>> debugUtilsCmdBufLabels;
200     std::vector<uint32_t> filter_message_ids{};
201     // This mutex is defined as mutable since the normal usage for a debug report object is as 'const'. The mutable keyword allows
202     // the layers to continue this pattern, but also allows them to use/change this specific member for synchronization purposes.
203     mutable std::mutex debug_output_mutex;
204     int32_t duplicate_message_limit = 0;
205     mutable std::unordered_map<uint32_t, int32_t> duplicate_message_count_map{};
206     const void *instance_pnext_chain{};
207 
DebugReportSetUtilsObjectName_debug_report_data208     void DebugReportSetUtilsObjectName(const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
209         std::unique_lock<std::mutex> lock(debug_output_mutex);
210         if (pNameInfo->pObjectName) {
211             debugUtilsObjectNameMap[pNameInfo->objectHandle] = pNameInfo->pObjectName;
212         } else {
213             debugUtilsObjectNameMap.erase(pNameInfo->objectHandle);
214         }
215     }
216 
DebugReportSetMarkerObjectName_debug_report_data217     void DebugReportSetMarkerObjectName(const VkDebugMarkerObjectNameInfoEXT *pNameInfo) {
218         std::unique_lock<std::mutex> lock(debug_output_mutex);
219         if (pNameInfo->pObjectName) {
220             debugObjectNameMap[pNameInfo->object] = pNameInfo->pObjectName;
221         } else {
222             debugObjectNameMap.erase(pNameInfo->object);
223         }
224     }
225 
DebugReportGetUtilsObjectName_debug_report_data226     std::string DebugReportGetUtilsObjectName(const uint64_t object) const {
227         std::string label = "";
228         const auto utils_name_iter = debugUtilsObjectNameMap.find(object);
229         if (utils_name_iter != debugUtilsObjectNameMap.end()) {
230             label = utils_name_iter->second;
231         }
232         return label;
233     }
234 
DebugReportGetMarkerObjectName_debug_report_data235     std::string DebugReportGetMarkerObjectName(const uint64_t object) const {
236         std::string label = "";
237         const auto marker_name_iter = debugObjectNameMap.find(object);
238         if (marker_name_iter != debugObjectNameMap.end()) {
239             label = marker_name_iter->second;
240         }
241         return label;
242     }
243 
FormatHandle_debug_report_data244     std::string FormatHandle(const char *handle_type_name, uint64_t handle) const {
245         std::string handle_name = DebugReportGetUtilsObjectName(handle);
246         if (handle_name.empty()) {
247             handle_name = DebugReportGetMarkerObjectName(handle);
248         }
249 
250         std::ostringstream str;
251         str << handle_type_name << " 0x" << std::hex << handle << "[" << handle_name.c_str() << "]";
252         return str.str();
253     }
254 
FormatHandle_debug_report_data255     std::string FormatHandle(const VulkanTypedHandle &handle) const {
256         return FormatHandle(object_string[handle.type], handle.handle);
257     }
258 
259     template <typename HANDLE_T>
FormatHandle_debug_report_data260     std::string FormatHandle(HANDLE_T handle) const {
261         return FormatHandle(VkHandleInfo<HANDLE_T>::Typename(), HandleToUint64(handle));
262     }
263 
264 } debug_report_data;
265 
266 template debug_report_data *GetLayerDataPtr<debug_report_data>(void *data_key,
267                                                                std::unordered_map<void *, debug_report_data *> &data_map);
268 
DebugReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags,bool default_flag_is_spec,VkDebugUtilsMessageSeverityFlagsEXT * da_severity,VkDebugUtilsMessageTypeFlagsEXT * da_type)269 static inline void DebugReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec,
270                                                 VkDebugUtilsMessageSeverityFlagsEXT *da_severity,
271                                                 VkDebugUtilsMessageTypeFlagsEXT *da_type) {
272     *da_severity = 0;
273     *da_type = 0;
274     // If it's explicitly listed as a performance warning, treat it as a performance message. Otherwise, treat it as a validation
275     // issue.
276     if ((dr_flags & kPerformanceWarningBit) != 0) {
277         *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
278         *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
279     }
280     if ((dr_flags & kDebugBit) != 0) {
281         *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
282         *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
283     }
284     if ((dr_flags & kInformationBit) != 0) {
285         *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
286         *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
287     }
288     if ((dr_flags & kWarningBit) != 0) {
289         *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
290         *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
291     }
292     if ((dr_flags & kErrorBit) != 0) {
293         *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
294         *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
295     }
296 }
297 
298 // Forward Declarations
299 static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, const LogObjectList &objects,
300                                  const char *layer_prefix, const char *message, const char *text_vuid);
301 
SetDebugUtilsSeverityFlags(std::vector<VkLayerDbgFunctionState> & callbacks,debug_report_data * debug_data)302 static void SetDebugUtilsSeverityFlags(std::vector<VkLayerDbgFunctionState> &callbacks, debug_report_data *debug_data) {
303     // For all callback in list, return their complete set of severities and modes
304     for (auto item : callbacks) {
305         if (item.IsUtils()) {
306             debug_data->active_severities |= item.debug_utils_msg_flags;
307             debug_data->active_types |= item.debug_utils_msg_type;
308         } else {
309             VkFlags severities = 0;
310             VkFlags types = 0;
311             DebugReportFlagsToAnnotFlags(item.debug_report_msg_flags, true, &severities, &types);
312             debug_data->active_severities |= severities;
313             debug_data->active_types |= types;
314         }
315     }
316 }
317 
RemoveDebugUtilsCallback(debug_report_data * debug_data,std::vector<VkLayerDbgFunctionState> & callbacks,uint64_t callback)318 static inline void RemoveDebugUtilsCallback(debug_report_data *debug_data, std::vector<VkLayerDbgFunctionState> &callbacks,
319                                             uint64_t callback) {
320     auto item = callbacks.begin();
321     for (item = callbacks.begin(); item != callbacks.end(); item++) {
322         if (item->IsUtils()) {
323             if (item->debug_utils_callback_object == CastToHandle<VkDebugUtilsMessengerEXT>(callback)) break;
324         } else {
325             if (item->debug_report_callback_object == CastToHandle<VkDebugReportCallbackEXT>(callback)) break;
326         }
327     }
328     if (item != callbacks.end()) {
329         callbacks.erase(item);
330     }
331     SetDebugUtilsSeverityFlags(callbacks, debug_data);
332 }
333 
334 // Deletes all debug callback function structs
RemoveAllMessageCallbacks(debug_report_data * debug_data,std::vector<VkLayerDbgFunctionState> & callbacks)335 static inline void RemoveAllMessageCallbacks(debug_report_data *debug_data, std::vector<VkLayerDbgFunctionState> &callbacks) {
336     callbacks.clear();
337 }
338 
339 // Returns TRUE if the number of times this message has been logged is over the set limit
UpdateLogMsgCounts(const debug_report_data * debug_data,int32_t vuid_hash)340 static inline bool UpdateLogMsgCounts(const debug_report_data *debug_data, int32_t vuid_hash) {
341     auto vuid_count_it = debug_data->duplicate_message_count_map.find(vuid_hash);
342     if (vuid_count_it == debug_data->duplicate_message_count_map.end()) {
343         debug_data->duplicate_message_count_map.insert({vuid_hash, 1});
344         return false;
345     } else {
346         if (vuid_count_it->second >= debug_data->duplicate_message_limit) {
347             return true;
348         } else {
349             vuid_count_it->second++;
350             return false;
351         }
352     }
353 }
354 
debug_log_msg(const debug_report_data * debug_data,VkFlags msg_flags,const LogObjectList & objects,const char * layer_prefix,const char * message,const char * text_vuid)355 static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, const LogObjectList &objects,
356                                  const char *layer_prefix, const char *message, const char *text_vuid) {
357     bool bail = false;
358     std::vector<VkDebugUtilsLabelEXT> queue_labels;
359     std::vector<VkDebugUtilsLabelEXT> cmd_buf_labels;
360 
361     // Convert the info to the VK_EXT_debug_utils format
362     VkDebugUtilsMessageTypeFlagsEXT types;
363     VkDebugUtilsMessageSeverityFlagsEXT severity;
364     DebugReportFlagsToAnnotFlags(msg_flags, true, &severity, &types);
365 
366     std::vector<VkDebugUtilsObjectNameInfoEXT> object_name_info;
367     object_name_info.resize(objects.object_list.size());
368     for (uint32_t i = 0; i < objects.object_list.size(); i++) {
369         object_name_info[i].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
370         object_name_info[i].pNext = NULL;
371         object_name_info[i].objectType = ConvertVulkanObjectToCoreObject(objects.object_list[i].type);
372         object_name_info[i].objectHandle = objects.object_list[i].handle;
373         object_name_info[i].pObjectName = NULL;
374 
375         std::string object_label = {};
376         // Look for any debug utils or marker names to use for this object
377         object_label = debug_data->DebugReportGetUtilsObjectName(objects.object_list[i].handle);
378         if (object_label.empty()) {
379             object_label = debug_data->DebugReportGetMarkerObjectName(objects.object_list[i].handle);
380         }
381         if (!object_label.empty()) {
382             char *local_obj_name = new char[object_label.length() + 1];
383             std::strcpy(local_obj_name, object_label.c_str());
384             object_name_info[i].pObjectName = local_obj_name;
385         }
386 
387         // If this is a queue, add any queue labels to the callback data.
388         if (VK_OBJECT_TYPE_QUEUE == object_name_info[i].objectType) {
389             auto label_iter = debug_data->debugUtilsQueueLabels.find(reinterpret_cast<VkQueue>(object_name_info[i].objectHandle));
390             if (label_iter != debug_data->debugUtilsQueueLabels.end()) {
391                 auto found_queue_labels = label_iter->second->Export();
392                 queue_labels.insert(queue_labels.end(), found_queue_labels.begin(), found_queue_labels.end());
393             }
394             // If this is a command buffer, add any command buffer labels to the callback data.
395         } else if (VK_OBJECT_TYPE_COMMAND_BUFFER == object_name_info[i].objectType) {
396             auto label_iter =
397                 debug_data->debugUtilsCmdBufLabels.find(reinterpret_cast<VkCommandBuffer>(object_name_info[i].objectHandle));
398             if (label_iter != debug_data->debugUtilsCmdBufLabels.end()) {
399                 auto found_cmd_buf_labels = label_iter->second->Export();
400                 cmd_buf_labels.insert(cmd_buf_labels.end(), found_cmd_buf_labels.begin(), found_cmd_buf_labels.end());
401             }
402         }
403     }
404 
405     int32_t location = 0;
406     if (text_vuid != nullptr) {
407         // Hash for vuid text
408         location = XXH32(text_vuid, strlen(text_vuid), 8);
409         if ((debug_data->duplicate_message_limit > 0) && UpdateLogMsgCounts(debug_data, location)) {
410             // Count for this particular message is over the limit, ignore it
411             return false;
412         }
413     }
414 
415     VkDebugUtilsMessengerCallbackDataEXT callback_data;
416     callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
417     callback_data.pNext = NULL;
418     callback_data.flags = 0;
419     callback_data.pMessageIdName = text_vuid;
420     callback_data.messageIdNumber = static_cast<int32_t>(location);
421     callback_data.pMessage = NULL;
422     callback_data.queueLabelCount = static_cast<uint32_t>(queue_labels.size());
423     callback_data.pQueueLabels = queue_labels.empty() ? nullptr : queue_labels.data();
424     callback_data.cmdBufLabelCount = static_cast<uint32_t>(cmd_buf_labels.size());
425     callback_data.pCmdBufLabels = cmd_buf_labels.empty() ? nullptr : cmd_buf_labels.data();
426     callback_data.objectCount = static_cast<uint32_t>(object_name_info.size());
427     callback_data.pObjects = object_name_info.data();
428 
429     std::ostringstream oss;
430     if (msg_flags & kErrorBit) {
431         oss << "Validation Error: ";
432     } else if (msg_flags & kWarningBit) {
433         oss << "Validation Warning: ";
434     } else if (msg_flags & kPerformanceWarningBit) {
435         oss << "Validation Performance Warning: ";
436     } else if (msg_flags & kInformationBit) {
437         oss << "Validation Information: ";
438     } else if (msg_flags & kDebugBit) {
439         oss << "DEBUG: ";
440     }
441     if (text_vuid != nullptr) {
442         oss << "[ " << text_vuid << " ] ";
443     }
444     uint32_t index = 0;
445     for (auto src_object : object_name_info) {
446         if (0 != src_object.objectHandle) {
447             oss << "Object " << index++ << ": handle = 0x" << std::hex << src_object.objectHandle;
448             if (src_object.pObjectName) {
449                 oss << ", name = " << src_object.pObjectName << ", type = ";
450             } else {
451                 oss << ", type = ";
452             }
453             oss << string_VkObjectType(src_object.objectType) << "; ";
454         } else {
455             oss << "Object " << index++ << ": VK_NULL_HANDLE, type = " << string_VkObjectType(src_object.objectType) << "; ";
456         }
457     }
458     oss << "| MessageID = 0x" << std::hex << location << " | " << message;
459     std::string composite = oss.str();
460 
461     const auto callback_list = &debug_data->debug_callback_list;
462     // We only output to default callbacks if there are no non-default callbacks
463     bool use_default_callbacks = true;
464     for (auto current_callback : *callback_list) {
465         use_default_callbacks &= current_callback.IsDefault();
466     }
467 
468     for (auto current_callback : *callback_list) {
469         // Skip callback if it's a default callback and there are non-default callbacks present
470         if (current_callback.IsDefault() && !use_default_callbacks) continue;
471 
472         // VK_EXT_debug_utils callback
473         if (current_callback.IsUtils() && (current_callback.debug_utils_msg_flags & severity) &&
474             (current_callback.debug_utils_msg_type & types)) {
475             callback_data.pMessage = composite.c_str();
476             if (current_callback.debug_utils_callback_function_ptr(static_cast<VkDebugUtilsMessageSeverityFlagBitsEXT>(severity),
477                                                                    types, &callback_data, current_callback.pUserData)) {
478                 bail = true;
479             }
480         } else if (!current_callback.IsUtils() && (current_callback.debug_report_msg_flags & msg_flags)) {
481             // VK_EXT_debug_report callback (deprecated)
482             if (current_callback.debug_report_callback_function_ptr(
483                     msg_flags, convertCoreObjectToDebugReportObject(object_name_info[0].objectType),
484                     object_name_info[0].objectHandle, location, 0, layer_prefix, composite.c_str(), current_callback.pUserData)) {
485                 bail = true;
486             }
487         }
488     }
489     return bail;
490 }
491 
DebugAnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,VkDebugUtilsMessageTypeFlagsEXT da_type)492 static inline VkDebugReportFlagsEXT DebugAnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,
493                                                                  VkDebugUtilsMessageTypeFlagsEXT da_type) {
494     if (da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) return VK_DEBUG_REPORT_ERROR_BIT_EXT;
495     if (da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
496         if (da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)
497             return VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
498         else
499             return VK_DEBUG_REPORT_WARNING_BIT_EXT;
500     }
501     if (da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) return VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
502     if (da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) return VK_DEBUG_REPORT_DEBUG_BIT_EXT;
503 
504     return 0;
505 }
506 
DebugAnnotFlagsToMsgTypeFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,VkDebugUtilsMessageTypeFlagsEXT da_type)507 static inline LogMessageTypeFlags DebugAnnotFlagsToMsgTypeFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,
508                                                                 VkDebugUtilsMessageTypeFlagsEXT da_type) {
509     LogMessageTypeFlags msg_type_flags = 0;
510     if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) {
511         msg_type_flags |= kErrorBit;
512     } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) {
513         if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) {
514             msg_type_flags |= kPerformanceWarningBit;
515         } else {
516             msg_type_flags |= kWarningBit;
517         }
518     } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) {
519         msg_type_flags |= kInformationBit;
520     } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) {
521         msg_type_flags |= kDebugBit;
522     }
523     return msg_type_flags;
524 }
525 
layer_debug_utils_destroy_instance(debug_report_data * debug_data)526 static inline void layer_debug_utils_destroy_instance(debug_report_data *debug_data) {
527     if (debug_data) {
528         std::unique_lock<std::mutex> lock(debug_data->debug_output_mutex);
529         RemoveAllMessageCallbacks(debug_data, debug_data->debug_callback_list);
530         lock.unlock();
531         delete (debug_data);
532     }
533 }
534 
535 template <typename T>
layer_destroy_callback(debug_report_data * debug_data,T callback,const VkAllocationCallbacks * allocator)536 static inline void layer_destroy_callback(debug_report_data *debug_data, T callback, const VkAllocationCallbacks *allocator) {
537     std::unique_lock<std::mutex> lock(debug_data->debug_output_mutex);
538     RemoveDebugUtilsCallback(debug_data, debug_data->debug_callback_list, CastToUint64(callback));
539 }
540 
541 template <typename TCreateInfo, typename TCallback>
layer_create_callback(DebugCallbackStatusFlags callback_status,debug_report_data * debug_data,const TCreateInfo * create_info,const VkAllocationCallbacks * allocator,TCallback * callback)542 static inline void layer_create_callback(DebugCallbackStatusFlags callback_status, debug_report_data *debug_data,
543                                          const TCreateInfo *create_info, const VkAllocationCallbacks *allocator,
544                                          TCallback *callback) {
545     std::unique_lock<std::mutex> lock(debug_data->debug_output_mutex);
546 
547     debug_data->debug_callback_list.emplace_back(VkLayerDbgFunctionState());
548     auto &callback_state = debug_data->debug_callback_list.back();
549     callback_state.callback_status = callback_status;
550     callback_state.pUserData = create_info->pUserData;
551 
552     if (callback_state.IsUtils()) {
553         auto utils_create_info = reinterpret_cast<const VkDebugUtilsMessengerCreateInfoEXT *>(create_info);
554         auto utils_callback = reinterpret_cast<VkDebugUtilsMessengerEXT *>(callback);
555         if (!(*utils_callback)) {
556             // callback constructed default callbacks have no handle -- so use struct address as unique handle
557             *utils_callback = reinterpret_cast<VkDebugUtilsMessengerEXT>(&callback_state);
558         }
559         callback_state.debug_utils_callback_object = *utils_callback;
560         callback_state.debug_utils_callback_function_ptr = utils_create_info->pfnUserCallback;
561         callback_state.debug_utils_msg_flags = utils_create_info->messageSeverity;
562         callback_state.debug_utils_msg_type = utils_create_info->messageType;
563     } else {  // Debug report callback
564         auto report_create_info = reinterpret_cast<const VkDebugReportCallbackCreateInfoEXT *>(create_info);
565         auto report_callback = reinterpret_cast<VkDebugReportCallbackEXT *>(callback);
566         if (!(*report_callback)) {
567             // Internally constructed default callbacks have no handle -- so use struct address as unique handle
568             *report_callback = reinterpret_cast<VkDebugReportCallbackEXT>(&callback_state);
569         }
570         callback_state.debug_report_callback_object = *report_callback;
571         callback_state.debug_report_callback_function_ptr = report_create_info->pfnCallback;
572         callback_state.debug_report_msg_flags = report_create_info->flags;
573     }
574 
575     SetDebugUtilsSeverityFlags(debug_data->debug_callback_list, debug_data);
576 }
577 
layer_create_messenger_callback(debug_report_data * debug_data,bool default_callback,const VkDebugUtilsMessengerCreateInfoEXT * create_info,const VkAllocationCallbacks * allocator,VkDebugUtilsMessengerEXT * messenger)578 static inline VkResult layer_create_messenger_callback(debug_report_data *debug_data, bool default_callback,
579                                                        const VkDebugUtilsMessengerCreateInfoEXT *create_info,
580                                                        const VkAllocationCallbacks *allocator,
581                                                        VkDebugUtilsMessengerEXT *messenger) {
582     layer_create_callback((DEBUG_CALLBACK_UTILS | (default_callback ? DEBUG_CALLBACK_DEFAULT : 0)), debug_data, create_info,
583                           allocator, messenger);
584     return VK_SUCCESS;
585 }
586 
layer_create_report_callback(debug_report_data * debug_data,bool default_callback,const VkDebugReportCallbackCreateInfoEXT * create_info,const VkAllocationCallbacks * allocator,VkDebugReportCallbackEXT * callback)587 static inline VkResult layer_create_report_callback(debug_report_data *debug_data, bool default_callback,
588                                                     const VkDebugReportCallbackCreateInfoEXT *create_info,
589                                                     const VkAllocationCallbacks *allocator, VkDebugReportCallbackEXT *callback) {
590     layer_create_callback((default_callback ? DEBUG_CALLBACK_DEFAULT : 0), debug_data, create_info, allocator, callback);
591     return VK_SUCCESS;
592 }
593 
ActivateInstanceDebugCallbacks(debug_report_data * debug_data)594 static inline void ActivateInstanceDebugCallbacks(debug_report_data *debug_data) {
595     auto current = debug_data->instance_pnext_chain;
596     for (;;) {
597         auto create_info = lvl_find_in_chain<VkDebugUtilsMessengerCreateInfoEXT>(current);
598         if (!create_info) break;
599         current = create_info->pNext;
600         VkDebugUtilsMessengerEXT utils_callback{};
601         layer_create_callback((DEBUG_CALLBACK_UTILS | DEBUG_CALLBACK_INSTANCE), debug_data, create_info, nullptr, &utils_callback);
602     }
603     for (;;) {
604         auto create_info = lvl_find_in_chain<VkDebugReportCallbackCreateInfoEXT>(current);
605         if (!create_info) break;
606         current = create_info->pNext;
607         VkDebugReportCallbackEXT report_callback{};
608         layer_create_callback(DEBUG_CALLBACK_INSTANCE, debug_data, create_info, nullptr, &report_callback);
609     }
610 }
611 
DeactivateInstanceDebugCallbacks(debug_report_data * debug_data)612 static inline void DeactivateInstanceDebugCallbacks(debug_report_data *debug_data) {
613     if (!lvl_find_in_chain<VkDebugUtilsMessengerCreateInfoEXT>(debug_data->instance_pnext_chain) &&
614         !lvl_find_in_chain<VkDebugReportCallbackCreateInfoEXT>(debug_data->instance_pnext_chain))
615         return;
616     std::vector<VkDebugUtilsMessengerEXT> instance_utils_callback_handles{};
617     std::vector<VkDebugReportCallbackEXT> instance_report_callback_handles{};
618     for (auto item : debug_data->debug_callback_list) {
619         if (item.IsInstance()) {
620             if (item.IsUtils()) {
621                 instance_utils_callback_handles.push_back(item.debug_utils_callback_object);
622             } else {
623                 instance_report_callback_handles.push_back(item.debug_report_callback_object);
624             }
625         }
626     }
627     for (auto item : instance_utils_callback_handles) {
628         layer_destroy_callback(debug_data, item, nullptr);
629     }
630     for (auto item : instance_report_callback_handles) {
631         layer_destroy_callback(debug_data, item, nullptr);
632     }
633 }
634 
635 #ifdef WIN32
vasprintf(char ** strp,char const * fmt,va_list ap)636 static inline int vasprintf(char **strp, char const *fmt, va_list ap) {
637     *strp = nullptr;
638     int size = _vscprintf(fmt, ap);
639     if (size >= 0) {
640         *strp = (char *)malloc(size + 1);
641         if (!*strp) {
642             return -1;
643         }
644         _vsnprintf(*strp, size + 1, fmt, ap);
645     }
646     return size;
647 }
648 #endif
649 
LogMsgLocked(const debug_report_data * debug_data,VkFlags msg_flags,const LogObjectList & objects,const std::string & vuid_text,char * err_msg)650 static inline bool LogMsgLocked(const debug_report_data *debug_data, VkFlags msg_flags, const LogObjectList &objects,
651                                 const std::string &vuid_text, char *err_msg) {
652     std::string str_plus_spec_text(err_msg ? err_msg : "Allocation failure");
653 
654     // If message is in filter list, bail out very early
655     size_t message_id = XXH32(vuid_text.c_str(), strlen(vuid_text.c_str()), 8);
656     if (std::find(debug_data->filter_message_ids.begin(), debug_data->filter_message_ids.end(),
657                   static_cast<uint32_t>(message_id)) != debug_data->filter_message_ids.end())
658         return false;
659 
660     // Append the spec error text to the error message, unless it's an UNASSIGNED or UNDEFINED vuid
661     if ((vuid_text.find("UNASSIGNED-") == std::string::npos) && (vuid_text.find(kVUIDUndefined) == std::string::npos) &&
662         (vuid_text.rfind("SYNC-", 0) == std::string::npos)) {
663         // Linear search makes no assumptions about the layout of the string table. This is not fast, but it does not need to be at
664         // this point in the error reporting path
665         uint32_t num_vuids = sizeof(vuid_spec_text) / sizeof(vuid_spec_text_pair);
666         const char *spec_text = nullptr;
667         std::string spec_type;
668         for (uint32_t i = 0; i < num_vuids; i++) {
669             if (0 == strcmp(vuid_text.c_str(), vuid_spec_text[i].vuid)) {
670                 spec_text = vuid_spec_text[i].spec_text;
671                 spec_type = vuid_spec_text[i].url_id;
672                 break;
673             }
674         }
675 
676         // Construct and append the specification text and link to the appropriate version of the spec
677         if (nullptr != spec_text) {
678             std::string spec_link = "https://www.khronos.org/registry/vulkan/specs/_MAGIC_KHRONOS_SPEC_TYPE_/html/vkspec.html";
679 #ifdef ANNOTATED_SPEC_LINK
680             spec_link = ANNOTATED_SPEC_LINK;
681 #endif
682             static std::string kAtToken = "_MAGIC_ANNOTATED_SPEC_TYPE_";
683             static std::string kKtToken = "_MAGIC_KHRONOS_SPEC_TYPE_";
684             static std::string kVeToken = "_MAGIC_VERSION_ID_";
685             auto Replace = [](std::string &dest_string, const std::string &to_replace, const std::string &replace_with) {
686                 if (dest_string.find(to_replace) != std::string::npos) {
687                     dest_string.replace(dest_string.find(to_replace), to_replace.size(), replace_with);
688                 }
689             };
690 
691             str_plus_spec_text.append(" The Vulkan spec states: ");
692             str_plus_spec_text.append(spec_text);
693             if (0 == spec_type.compare("default")) {
694                 str_plus_spec_text.append(" (https://github.com/KhronosGroup/Vulkan-Docs/search?q=)");
695             } else {
696                 str_plus_spec_text.append(" (");
697                 str_plus_spec_text.append(spec_link);
698                 std::string major_version = std::to_string(VK_VERSION_MAJOR(VK_HEADER_VERSION_COMPLETE));
699                 std::string minor_version = std::to_string(VK_VERSION_MINOR(VK_HEADER_VERSION_COMPLETE));
700                 std::string patch_version = std::to_string(VK_VERSION_PATCH(VK_HEADER_VERSION_COMPLETE));
701                 std::string header_version = major_version + "." + minor_version + "." + patch_version;
702                 std::string annotated_spec_type = major_version + "." + minor_version + "-extensions";
703                 Replace(str_plus_spec_text, kKtToken, spec_type);
704                 Replace(str_plus_spec_text, kAtToken, annotated_spec_type);
705                 Replace(str_plus_spec_text, kVeToken, header_version);
706                 str_plus_spec_text.append("#");  // CMake hates hashes
707             }
708             str_plus_spec_text.append(vuid_text);
709             str_plus_spec_text.append(")");
710         }
711     }
712 
713     bool result = debug_log_msg(debug_data, msg_flags, objects, "Validation", str_plus_spec_text.c_str(), vuid_text.c_str());
714     free(err_msg);
715     return result;
716 }
717 
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)718 static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_log_callback(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
719                                                                  uint64_t src_object, size_t location, int32_t msg_code,
720                                                                  const char *layer_prefix, const char *message, void *user_data) {
721     std::ostringstream msg_buffer;
722     char msg_flag_string[30];
723 
724     PrintMessageFlags(msg_flags, msg_flag_string);
725 
726     msg_buffer << layer_prefix << "(" << msg_flag_string << "): msg_code: " << msg_code << ": " << message << "\n";
727     const std::string tmp = msg_buffer.str();
728     const char *cstr = tmp.c_str();
729 
730     fprintf((FILE *)user_data, "%s", cstr);
731     fflush((FILE *)user_data);
732 
733 #if defined __ANDROID__
734     LOGCONSOLE("%s", cstr);
735 #endif
736 
737     return false;
738 }
739 
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)740 static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_win32_debug_output_msg(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
741                                                                            uint64_t src_object, size_t location, int32_t msg_code,
742                                                                            const char *layer_prefix, const char *message,
743                                                                            void *user_data) {
744 #ifdef WIN32
745     char msg_flag_string[30];
746     char buf[2048];
747 
748     PrintMessageFlags(msg_flags, msg_flag_string);
749     _snprintf(buf, sizeof(buf) - 1, "%s (%s): msg_code: %d: %s\n", layer_prefix, msg_flag_string, msg_code, message);
750 
751     OutputDebugString(buf);
752 #endif
753 
754     return false;
755 }
756 
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)757 static inline VKAPI_ATTR VkBool32 VKAPI_CALL DebugBreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT obj_type,
758                                                                 uint64_t src_object, size_t location, int32_t msg_code,
759                                                                 const char *layer_prefix, const char *message, void *user_data) {
760 #ifdef WIN32
761     DebugBreak();
762 #else
763     raise(SIGTRAP);
764 #endif
765 
766     return false;
767 }
768 
MessengerBreakCallback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,VkDebugUtilsMessageTypeFlagsEXT message_type,const VkDebugUtilsMessengerCallbackDataEXT * callback_data,void * user_data)769 static inline VKAPI_ATTR VkBool32 VKAPI_CALL MessengerBreakCallback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
770                                                                     VkDebugUtilsMessageTypeFlagsEXT message_type,
771                                                                     const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
772                                                                     void *user_data) {
773 #ifdef WIN32
774     DebugBreak();
775 #else
776     raise(SIGTRAP);
777 #endif
778 
779     return false;
780 }
781 
messenger_log_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,VkDebugUtilsMessageTypeFlagsEXT message_type,const VkDebugUtilsMessengerCallbackDataEXT * callback_data,void * user_data)782 static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_log_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
783                                                                     VkDebugUtilsMessageTypeFlagsEXT message_type,
784                                                                     const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
785                                                                     void *user_data) {
786     std::ostringstream msg_buffer;
787     char msg_severity[30];
788     char msg_type[30];
789 
790     PrintMessageSeverity(message_severity, msg_severity);
791     PrintMessageType(message_type, msg_type);
792 
793     msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
794                << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
795     msg_buffer << "    Objects: " << callback_data->objectCount << "\n";
796     for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
797         msg_buffer << "        [" << obj << "] " << std::hex << std::showbase
798                    << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
799                    << callback_data->pObjects[obj].objectType
800                    << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
801                    << "\n";
802     }
803     const std::string tmp = msg_buffer.str();
804     const char *cstr = tmp.c_str();
805     fprintf((FILE *)user_data, "%s", cstr);
806     fflush((FILE *)user_data);
807 
808 #if defined __ANDROID__
809     LOGCONSOLE("%s", cstr);
810 #endif
811 
812     return false;
813 }
814 
messenger_win32_debug_output_msg(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,VkDebugUtilsMessageTypeFlagsEXT message_type,const VkDebugUtilsMessengerCallbackDataEXT * callback_data,void * user_data)815 static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_win32_debug_output_msg(
816     VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type,
817     const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data) {
818 #ifdef WIN32
819     std::ostringstream msg_buffer;
820     char msg_severity[30];
821     char msg_type[30];
822 
823     PrintMessageSeverity(message_severity, msg_severity);
824     PrintMessageType(message_type, msg_type);
825 
826     msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
827                << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
828     msg_buffer << "    Objects: " << callback_data->objectCount << "\n";
829 
830     for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
831         msg_buffer << "       [" << obj << "]  " << std::hex << std::showbase
832                    << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
833                    << callback_data->pObjects[obj].objectType
834                    << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
835                    << "\n";
836     }
837     const std::string tmp = msg_buffer.str();
838     const char *cstr = tmp.c_str();
839     OutputDebugString(cstr);
840 #endif
841 
842     return false;
843 }
844 
845 template <typename Map>
GetLoggingLabelState(Map * map,typename Map::key_type key,bool insert)846 static LoggingLabelState *GetLoggingLabelState(Map *map, typename Map::key_type key, bool insert) {
847     auto iter = map->find(key);
848     LoggingLabelState *label_state = nullptr;
849     if (iter == map->end()) {
850         if (insert) {
851             // Add a label state if not present
852             auto inserted = map->insert(std::make_pair(key, std::unique_ptr<LoggingLabelState>(new LoggingLabelState())));
853             assert(inserted.second);
854             iter = inserted.first;
855             label_state = iter->second.get();
856         }
857     } else {
858         label_state = iter->second.get();
859     }
860     return label_state;
861 }
862 
BeginQueueDebugUtilsLabel(debug_report_data * report_data,VkQueue queue,const VkDebugUtilsLabelEXT * label_info)863 static inline void BeginQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
864                                              const VkDebugUtilsLabelEXT *label_info) {
865     std::unique_lock<std::mutex> lock(report_data->debug_output_mutex);
866     if (nullptr != label_info && nullptr != label_info->pLabelName) {
867         auto *label_state = GetLoggingLabelState(&report_data->debugUtilsQueueLabels, queue, /* insert */ true);
868         assert(label_state);
869         label_state->labels.push_back(LoggingLabel(label_info));
870 
871         // TODO: Determine if this is the correct semantics for insert label vs. begin/end, perserving existing semantics for now
872         label_state->insert_label.Reset();
873     }
874 }
875 
EndQueueDebugUtilsLabel(debug_report_data * report_data,VkQueue queue)876 static inline void EndQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue) {
877     std::unique_lock<std::mutex> lock(report_data->debug_output_mutex);
878     auto *label_state = GetLoggingLabelState(&report_data->debugUtilsQueueLabels, queue, /* insert */ false);
879     if (label_state) {
880         // Pop the normal item
881         if (!label_state->labels.empty()) {
882             label_state->labels.pop_back();
883         }
884 
885         // TODO: Determine if this is the correct semantics for insert label vs. begin/end, perserving existing semantics for now
886         label_state->insert_label.Reset();
887     }
888 }
889 
InsertQueueDebugUtilsLabel(debug_report_data * report_data,VkQueue queue,const VkDebugUtilsLabelEXT * label_info)890 static inline void InsertQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
891                                               const VkDebugUtilsLabelEXT *label_info) {
892     std::unique_lock<std::mutex> lock(report_data->debug_output_mutex);
893     auto *label_state = GetLoggingLabelState(&report_data->debugUtilsQueueLabels, queue, /* insert */ true);
894 
895     // TODO: Determine if this is the correct semantics for insert label vs. begin/end, perserving existing semantics for now
896     label_state->insert_label = LoggingLabel(label_info);
897 }
898 
BeginCmdDebugUtilsLabel(debug_report_data * report_data,VkCommandBuffer command_buffer,const VkDebugUtilsLabelEXT * label_info)899 static inline void BeginCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
900                                            const VkDebugUtilsLabelEXT *label_info) {
901     std::unique_lock<std::mutex> lock(report_data->debug_output_mutex);
902     if (nullptr != label_info && nullptr != label_info->pLabelName) {
903         auto *label_state = GetLoggingLabelState(&report_data->debugUtilsCmdBufLabels, command_buffer, /* insert */ true);
904         assert(label_state);
905         label_state->labels.push_back(LoggingLabel(label_info));
906 
907         // TODO: Determine if this is the correct semantics for insert label vs. begin/end, perserving existing semantics for now
908         label_state->insert_label.Reset();
909     }
910 }
911 
EndCmdDebugUtilsLabel(debug_report_data * report_data,VkCommandBuffer command_buffer)912 static inline void EndCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
913     std::unique_lock<std::mutex> lock(report_data->debug_output_mutex);
914     auto *label_state = GetLoggingLabelState(&report_data->debugUtilsCmdBufLabels, command_buffer, /* insert */ false);
915     if (label_state) {
916         // Pop the normal item
917         if (!label_state->labels.empty()) {
918             label_state->labels.pop_back();
919         }
920 
921         // TODO: Determine if this is the correct semantics for insert label vs. begin/end, perserving existing semantics for now
922         label_state->insert_label.Reset();
923     }
924 }
925 
InsertCmdDebugUtilsLabel(debug_report_data * report_data,VkCommandBuffer command_buffer,const VkDebugUtilsLabelEXT * label_info)926 static inline void InsertCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
927                                             const VkDebugUtilsLabelEXT *label_info) {
928     std::unique_lock<std::mutex> lock(report_data->debug_output_mutex);
929     auto *label_state = GetLoggingLabelState(&report_data->debugUtilsCmdBufLabels, command_buffer, /* insert */ true);
930     assert(label_state);
931 
932     // TODO: Determine if this is the correct semantics for insert label vs. begin/end, perserving existing semantics for now
933     label_state->insert_label = LoggingLabel(label_info);
934 }
935 
936 // 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)937 static inline void ResetCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
938     std::unique_lock<std::mutex> lock(report_data->debug_output_mutex);
939     auto *label_state = GetLoggingLabelState(&report_data->debugUtilsCmdBufLabels, command_buffer, /* insert */ false);
940     if (label_state) {
941         label_state->labels.clear();
942         label_state->insert_label.Reset();
943     }
944 }
945 
EraseCmdDebugUtilsLabel(debug_report_data * report_data,VkCommandBuffer command_buffer)946 static inline void EraseCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
947     report_data->debugUtilsCmdBufLabels.erase(command_buffer);
948 }
949 
950 #endif  // LAYER_LOGGING_H
951