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