blob: 3d80af6e8d299505b1c2fdcce9e6ecb16cb6d6e5 [file] [log] [blame]
Mark Lobodzinskifeb61fe2019-01-10 08:56:57 -07001/* Copyright (c) 2015-2019 The Khronos Group Inc.
2 * Copyright (c) 2015-2019 Valve Corporation
3 * Copyright (c) 2015-2019 LunarG, Inc.
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -06004 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -06005 * 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
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -06008 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -06009 * http://www.apache.org/licenses/LICENSE-2.0
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -060010 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060011 * 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.
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -060016 *
Courtney Goeltzenleuchter05559522015-10-30 11:14:30 -060017 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
18 * Author: Tobin Ehlis <tobin@lunarg.com>
Mark Young6ba8abe2017-11-09 10:37:04 -070019 * Author: Mark Young <marky@lunarg.com>
Dave Houlton4d9b2f82018-10-24 18:21:06 -060020 * Author: Dave Houlton <daveh@lunarg.com>
Courtney Goeltzenleuchter05559522015-10-30 11:14:30 -060021 *
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -060022 */
23
24#ifndef LAYER_LOGGING_H
25#define LAYER_LOGGING_H
26
John Zulaufc64f97c2019-04-10 10:34:52 -060027#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>
Ricardo Garcia008cebb2019-05-06 11:10:08 +020041#include <utility>
John Zulaufc64f97c2019-04-10 10:34:52 -060042
43#include "vk_typemap_helper.h"
Mark Lobodzinskib87f9022016-05-24 16:04:56 -060044#include "vk_loader_layer.h"
Tobin Ehlis2d9deec2016-04-21 14:19:26 -060045#include "vk_layer_config.h"
Tobin Ehlisa0cb02e2015-07-03 10:15:26 -060046#include "vk_layer_data.h"
Tobin Ehlis2d9deec2016-04-21 14:19:26 -060047#include "vk_loader_platform.h"
48#include "vulkan/vk_layer.h"
Mark Young6ba8abe2017-11-09 10:37:04 -070049#include "vk_object_types.h"
John Zulauf2c2ccd42019-04-05 13:13:13 -060050#include "cast_utils.h"
Mark Lobodzinski487a0d12018-03-30 10:09:03 -060051#include "vk_validation_error_messages.h"
Lenny Komow4c0da772018-07-03 10:17:21 -060052#include "vk_layer_dispatch_table.h"
Mark Young6ba8abe2017-11-09 10:37:04 -070053
Dave Houlton57ae22f2018-05-18 16:20:52 -060054// Suppress unused warning on Linux
55#if defined(__GNUC__)
Dave Houltoncfcecbf2018-05-31 16:20:57 -060056#define DECORATE_UNUSED __attribute__((unused))
57#else
58#define DECORATE_UNUSED
Dave Houlton57ae22f2018-05-18 16:20:52 -060059#endif
60
Mark Lobodzinski706e15a2018-12-12 15:35:29 -070061#if defined __ANDROID__
62#include <android/log.h>
63#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "VALIDATION", __VA_ARGS__))
64#else
65#define LOGCONSOLE(...) \
66 { \
67 printf(__VA_ARGS__); \
68 printf("\n"); \
69 }
70#endif
71
Dave Houltoncfcecbf2018-05-31 16:20:57 -060072static const char DECORATE_UNUSED *kVUIDUndefined = "VUID_Undefined";
Dave Houlton8e9f6542018-05-18 12:18:22 -060073
Dave Houltoncfcecbf2018-05-31 16:20:57 -060074#undef DECORATE_UNUSED
Dave Houlton57ae22f2018-05-18 16:20:52 -060075
Mark Young6ba8abe2017-11-09 10:37:04 -070076// TODO: Could be autogenerated for the specific handles for extra type safety...
77template <typename HANDLE_T>
John Zulauf2c2ccd42019-04-05 13:13:13 -060078static inline uint64_t HandleToUint64(HANDLE_T h) {
79 return CastToUint64<HANDLE_T>(h);
Mark Young6ba8abe2017-11-09 10:37:04 -070080}
81
82static inline uint64_t HandleToUint64(uint64_t h) { return h; }
83
84// Data we store per label for logging
John Zulaufc64f97c2019-04-10 10:34:52 -060085struct LoggingLabel {
Mark Young6ba8abe2017-11-09 10:37:04 -070086 std::string name;
John Zulaufc64f97c2019-04-10 10:34:52 -060087 std::array<float, 4> color;
88
89 void Reset() { *this = LoggingLabel(); }
90 bool Empty() const { return name.empty(); }
91
92 VkDebugUtilsLabelEXT Export() const {
93 auto out = lvl_init_struct<VkDebugUtilsLabelEXT>();
94 out.pLabelName = name.c_str();
95 std::copy(color.cbegin(), color.cend(), out.color);
96 return out;
97 };
98
99 LoggingLabel() : name(), color({0.f, 0.f, 0.f, 0.f}) {}
John Zulaufc64f97c2019-04-10 10:34:52 -0600100 LoggingLabel(const VkDebugUtilsLabelEXT *label_info) {
101 if (label_info && label_info->pLabelName) {
102 name = label_info->pLabelName;
103 std::copy_n(std::begin(label_info->color), 4, color.begin());
104 } else {
105 Reset();
106 }
107 }
Ricardo Garcia008cebb2019-05-06 11:10:08 +0200108
109 LoggingLabel(const LoggingLabel &) = default;
110 LoggingLabel &operator=(const LoggingLabel &) = default;
111 LoggingLabel &operator=(LoggingLabel &&) = default;
112 LoggingLabel(LoggingLabel &&) = default;
113
114 template <typename Name, typename Vec>
115 LoggingLabel(Name &&name_, Vec &&vec_) : name(std::forward<Name>(name_)), color(std::forward<Vec>(vec_)) {}
John Zulaufc64f97c2019-04-10 10:34:52 -0600116};
117
118struct LoggingLabelState {
119 std::vector<LoggingLabel> labels;
120 LoggingLabel insert_label;
121
122 // Export the labels, but in reverse order since we want the most recent at the top.
123 std::vector<VkDebugUtilsLabelEXT> Export() const {
124 size_t count = labels.size() + (insert_label.Empty() ? 0 : 1);
125 std::vector<VkDebugUtilsLabelEXT> out(count);
126
127 if (!count) return out;
128
129 size_t index = count - 1;
130 if (!insert_label.Empty()) {
131 out[index--] = insert_label.Export();
132 }
133 for (const auto &label : labels) {
134 out[index--] = label.Export();
135 }
136 return out;
137 }
138};
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600139
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600140typedef struct _debug_report_data {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700141 VkLayerDbgFunctionNode *debug_callback_list{nullptr};
142 VkLayerDbgFunctionNode *default_debug_callback_list{nullptr};
143 VkDebugUtilsMessageSeverityFlagsEXT active_severities{0};
144 VkDebugUtilsMessageTypeFlagsEXT active_types{0};
145 bool g_DEBUG_REPORT{false};
146 bool g_DEBUG_UTILS{false};
147 bool queueLabelHasInsert{false};
148 bool cmdBufLabelHasInsert{false};
149 std::unordered_map<uint64_t, std::string> debugObjectNameMap;
150 std::unordered_map<uint64_t, std::string> debugUtilsObjectNameMap;
John Zulaufc64f97c2019-04-10 10:34:52 -0600151 std::unordered_map<VkQueue, std::unique_ptr<LoggingLabelState>> debugUtilsQueueLabels;
152 std::unordered_map<VkCommandBuffer, std::unique_ptr<LoggingLabelState>> debugUtilsCmdBufLabels;
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700153 // This mutex is defined as mutable since the normal usage for a debug report object is as 'const'. The mutable keyword allows
154 // the layers to continue this pattern, but also allows them to use/change this specific member for synchronization purposes.
155 mutable std::mutex debug_report_mutex;
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700156
157 void DebugReportSetUtilsObjectName(const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700158 std::unique_lock<std::mutex> lock(debug_report_mutex);
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700159 if (pNameInfo->pObjectName) {
Mark Lobodzinski20075722019-02-25 09:34:49 -0700160 debugUtilsObjectNameMap[pNameInfo->objectHandle] = pNameInfo->pObjectName;
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700161 } else {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700162 debugUtilsObjectNameMap.erase(pNameInfo->objectHandle);
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700163 }
164 }
165
166 void DebugReportSetMarkerObjectName(const VkDebugMarkerObjectNameInfoEXT *pNameInfo) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700167 std::unique_lock<std::mutex> lock(debug_report_mutex);
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700168 if (pNameInfo->pObjectName) {
Mark Lobodzinski20075722019-02-25 09:34:49 -0700169 debugObjectNameMap[pNameInfo->object] = pNameInfo->pObjectName;
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700170 } else {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700171 debugObjectNameMap.erase(pNameInfo->object);
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700172 }
173 }
174
175 std::string DebugReportGetUtilsObjectName(const uint64_t object) const {
176 std::string label = "";
Mark Lobodzinski61a6d622019-02-14 14:11:24 -0700177 const auto utils_name_iter = debugUtilsObjectNameMap.find(object);
Mark Lobodzinski12813302019-02-07 15:03:06 -0700178 if (utils_name_iter != debugUtilsObjectNameMap.end()) {
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700179 label = utils_name_iter->second;
180 }
181 return label;
182 }
183
184 std::string DebugReportGetMarkerObjectName(const uint64_t object) const {
185 std::string label = "";
Mark Lobodzinski61a6d622019-02-14 14:11:24 -0700186 const auto marker_name_iter = debugObjectNameMap.find(object);
Mark Lobodzinski12813302019-02-07 15:03:06 -0700187 if (marker_name_iter != debugObjectNameMap.end()) {
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700188 label = marker_name_iter->second;
189 }
190 return label;
191 }
192
John Zulauf2c2ccd42019-04-05 13:13:13 -0600193 std::string FormatHandle(const char * /* handle_name */, uint64_t h) const {
194 // Ignore handle_name string until the tests are changed to not fail when typename is emitted
Locked4722ab2019-02-25 12:25:35 -0700195 char uint64_string[64];
196 sprintf(uint64_string, "0x%" PRIxLEAST64, h);
197 std::string ret = uint64_string;
Locke26335512019-02-18 13:49:02 -0700198
199 std::string name = DebugReportGetUtilsObjectName(h);
200 if (name.empty()) {
201 name = DebugReportGetMarkerObjectName(h);
202 }
203 if (!name.empty()) {
204 ret.append("[");
205 ret.append(name);
206 ret.append("]");
207 }
208 return ret;
209 }
210
John Zulauf2c2ccd42019-04-05 13:13:13 -0600211 // Backwards compatible path for entry points that pass uint64_t's
212 std::string FormatHandle(uint64_t h) const { return FormatHandle("", h); }
213
John Zulauf4fea6622019-04-01 11:38:18 -0600214 std::string FormatHandle(const VulkanTypedHandle &handle) const {
215 return FormatHandle(object_string[handle.type], handle.handle);
216 }
217
John Zulauf2c2ccd42019-04-05 13:13:13 -0600218 template <typename HANDLE_T>
219 std::string FormatHandle(HANDLE_T h) const {
220 return FormatHandle(VkHandleInfo<HANDLE_T>::Typename(), HandleToUint64(h));
221 }
222
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600223} debug_report_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600224
Tobin Ehlis8d6acde2017-02-08 07:40:40 -0700225template debug_report_data *GetLayerDataPtr<debug_report_data>(void *data_key,
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700226 std::unordered_map<void *, debug_report_data *> &data_map);
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600227
Mark Young6ba8abe2017-11-09 10:37:04 -0700228static inline void DebugReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec,
229 VkDebugUtilsMessageSeverityFlagsEXT *da_severity,
230 VkDebugUtilsMessageTypeFlagsEXT *da_type) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700231 *da_severity = 0;
Mark Youngfbaae712018-10-04 14:33:50 -0600232 *da_type = 0;
Mark Youngc2347792018-05-30 08:41:25 -0600233 // If it's explicitly listed as a performance warning, treat it as a performance message.
234 // Otherwise, treat it as a validation issue.
235 if ((dr_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600236 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
237 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
Mark Youngc2347792018-05-30 08:41:25 -0600238 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700239 if ((dr_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600240 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700241 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700242 }
243 if ((dr_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600244 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700245 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700246 }
Mark Youngfbaae712018-10-04 14:33:50 -0600247 if ((dr_flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) != 0) {
248 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700249 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
250 }
251 if ((dr_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600252 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700253 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
254 }
255}
256
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600257// Forward Declarations
Mark Young6ba8abe2017-11-09 10:37:04 -0700258static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Dave Houlton407df732018-08-06 17:58:24 -0600259 uint64_t src_object, size_t location, const char *layer_prefix, const char *message,
260 const char *text_vuid);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600261
262// Add a debug message callback node structure to the specified callback linked list
Mark Young6ba8abe2017-11-09 10:37:04 -0700263static inline void AddDebugCallbackNode(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
264 VkLayerDbgFunctionNode *new_node) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600265 new_node->pNext = *list_head;
266 *list_head = new_node;
267}
268
Mark Young6ba8abe2017-11-09 10:37:04 -0700269// Remove specified debug messenger node structure from the specified linked list
270static inline void RemoveDebugUtilsMessenger(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
271 VkDebugUtilsMessengerEXT messenger) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600272 VkLayerDbgFunctionNode *cur_callback = *list_head;
Mark Youngfbaae712018-10-04 14:33:50 -0600273 VkLayerDbgFunctionNode *prev_callback = nullptr;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600274 bool matched = false;
Mark Young6ba8abe2017-11-09 10:37:04 -0700275 VkFlags local_severities = 0;
276 VkFlags local_types = 0;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600277
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600278 while (cur_callback) {
Mark Youngfbaae712018-10-04 14:33:50 -0600279 if (cur_callback->is_messenger) {
280 // If it's actually a messenger, then set it up for deletion.
281 if (cur_callback->messenger.messenger == messenger) {
282 matched = true;
283 if (*list_head == cur_callback) {
284 *list_head = cur_callback->pNext;
285 } else {
286 assert(nullptr != prev_callback);
287 prev_callback->pNext = cur_callback->pNext;
288 }
289 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
290 reinterpret_cast<uint64_t &>(cur_callback->messenger.messenger), 0, "DebugUtilsMessenger",
291 "Destroyed messenger\n", kVUIDUndefined);
292 } else {
293 // If it's not the one we're looking for, just keep the types/severities
294 local_severities |= cur_callback->messenger.messageSeverity;
295 local_types |= cur_callback->messenger.messageType;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600296 }
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600297 } else {
Mark Youngfbaae712018-10-04 14:33:50 -0600298 // If it's not a messenger, just keep the types/severities
299 VkFlags this_severities = 0;
300 VkFlags this_types = 0;
301 DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types);
302 local_severities |= this_severities;
303 local_types |= this_types;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600304 }
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600305 if (matched) {
Mark Youngfbaae712018-10-04 14:33:50 -0600306 free(cur_callback);
307 matched = false;
308 // Intentionally keep the last prev_callback, but select the proper cur_callback
309 if (nullptr != prev_callback) {
310 cur_callback = prev_callback->pNext;
311 } else {
312 cur_callback = *list_head;
313 }
314 } else {
315 prev_callback = cur_callback;
316 cur_callback = cur_callback->pNext;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600317 }
318 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700319 debug_data->active_severities = local_severities;
320 debug_data->active_types = local_types;
321}
322
323// Remove specified debug message callback node structure from the specified callback linked list
324static inline void RemoveDebugUtilsMessageCallback(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
325 VkDebugReportCallbackEXT callback) {
326 VkLayerDbgFunctionNode *cur_callback = *list_head;
Mark Youngfbaae712018-10-04 14:33:50 -0600327 VkLayerDbgFunctionNode *prev_callback = nullptr;
Mark Young6ba8abe2017-11-09 10:37:04 -0700328 bool matched = false;
329 VkFlags local_severities = 0;
330 VkFlags local_types = 0;
331
332 while (cur_callback) {
Mark Youngfbaae712018-10-04 14:33:50 -0600333 if (!cur_callback->is_messenger) {
334 // If it's actually a callback, then set it up for deletion.
335 if (cur_callback->report.msgCallback == callback) {
336 matched = true;
337 if (*list_head == cur_callback) {
338 *list_head = cur_callback->pNext;
339 } else {
340 assert(nullptr != prev_callback);
341 prev_callback->pNext = cur_callback->pNext;
342 }
343 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
344 reinterpret_cast<uint64_t &>(cur_callback->report.msgCallback), 0, "DebugReport",
345 "Destroyed callback\n", kVUIDUndefined);
346 } else {
347 // If it's not the one we're looking for, just keep the types/severities
348 VkFlags this_severities = 0;
349 VkFlags this_types = 0;
350 DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types);
351 local_severities |= this_severities;
352 local_types |= this_types;
Mark Young6ba8abe2017-11-09 10:37:04 -0700353 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700354 } else {
Mark Youngfbaae712018-10-04 14:33:50 -0600355 // If it's not a callback, just keep the types/severities
356 local_severities |= cur_callback->messenger.messageSeverity;
357 local_types |= cur_callback->messenger.messageType;
Mark Young6ba8abe2017-11-09 10:37:04 -0700358 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700359 if (matched) {
Mark Youngfbaae712018-10-04 14:33:50 -0600360 free(cur_callback);
361 matched = false;
362 // Intentionally keep the last prev_callback, but select the proper cur_callback
363 if (nullptr != prev_callback) {
364 cur_callback = prev_callback->pNext;
365 } else {
366 cur_callback = *list_head;
367 }
368 } else {
369 prev_callback = cur_callback;
370 cur_callback = cur_callback->pNext;
Mark Young6ba8abe2017-11-09 10:37:04 -0700371 }
372 }
373 debug_data->active_severities = local_severities;
374 debug_data->active_types = local_types;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600375}
376
377// Removes all debug callback function nodes from the specified callback linked lists and frees their resources
378static inline void RemoveAllMessageCallbacks(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head) {
379 VkLayerDbgFunctionNode *current_callback = *list_head;
380 VkLayerDbgFunctionNode *prev_callback = current_callback;
381
382 while (current_callback) {
383 prev_callback = current_callback->pNext;
Mark Young6ba8abe2017-11-09 10:37:04 -0700384 if (!current_callback->is_messenger) {
385 debug_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
Dave Houlton407df732018-08-06 17:58:24 -0600386 (uint64_t)current_callback->report.msgCallback, 0, "DebugReport",
387 "Debug Report callbacks not removed before DestroyInstance", kVUIDUndefined);
Mark Young6ba8abe2017-11-09 10:37:04 -0700388 } else {
389 debug_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
Dave Houlton407df732018-08-06 17:58:24 -0600390 (uint64_t)current_callback->messenger.messenger, 0, "Messenger",
391 "Debug messengers not removed before DestroyInstance", kVUIDUndefined);
Mark Young6ba8abe2017-11-09 10:37:04 -0700392 }
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600393 free(current_callback);
394 current_callback = prev_callback;
395 }
396 *list_head = NULL;
397}
398
Mark Young6ba8abe2017-11-09 10:37:04 -0700399static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Dave Houlton407df732018-08-06 17:58:24 -0600400 uint64_t src_object, size_t location, const char *layer_prefix, const char *message,
401 const char *text_vuid) {
Dustin Graves8f1eab92016-04-05 09:41:17 -0600402 bool bail = false;
Mark Young6ba8abe2017-11-09 10:37:04 -0700403 VkLayerDbgFunctionNode *layer_dbg_node = NULL;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600404
Mark Lobodzinski55a197f2016-06-21 15:54:57 -0600405 if (debug_data->debug_callback_list != NULL) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700406 layer_dbg_node = debug_data->debug_callback_list;
Mark Lobodzinski55a197f2016-06-21 15:54:57 -0600407 } else {
Mark Young6ba8abe2017-11-09 10:37:04 -0700408 layer_dbg_node = debug_data->default_debug_callback_list;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600409 }
410
Mark Young6ba8abe2017-11-09 10:37:04 -0700411 VkDebugUtilsMessageSeverityFlagsEXT severity;
412 VkDebugUtilsMessageTypeFlagsEXT types;
413 VkDebugUtilsMessengerCallbackDataEXT callback_data;
414 VkDebugUtilsObjectNameInfoEXT object_name_info;
415
416 // Convert the info to the VK_EXT_debug_utils form in case we need it.
417 DebugReportFlagsToAnnotFlags(msg_flags, true, &severity, &types);
418 object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
419 object_name_info.pNext = NULL;
420 object_name_info.objectType = convertDebugReportObjectToCoreObject(object_type);
421 object_name_info.objectHandle = (uint64_t)(uintptr_t)src_object;
422 object_name_info.pObjectName = NULL;
Mark Lobodzinski5d98ba12019-03-25 13:35:01 -0600423 std::string object_label = {};
Mark Young6ba8abe2017-11-09 10:37:04 -0700424
425 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
426 callback_data.pNext = NULL;
427 callback_data.flags = 0;
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700428 callback_data.pMessageIdName = text_vuid;
Dave Houlton407df732018-08-06 17:58:24 -0600429 callback_data.messageIdNumber = 0; // deprecated, validation layers use only the pMessageIdName
Mark Young6ba8abe2017-11-09 10:37:04 -0700430 callback_data.pMessage = message;
431 callback_data.queueLabelCount = 0;
432 callback_data.pQueueLabels = NULL;
433 callback_data.cmdBufLabelCount = 0;
434 callback_data.pCmdBufLabels = NULL;
435 callback_data.objectCount = 1;
436 callback_data.pObjects = &object_name_info;
437
John Zulaufc64f97c2019-04-10 10:34:52 -0600438 std::vector<VkDebugUtilsLabelEXT> queue_labels;
439 std::vector<VkDebugUtilsLabelEXT> cmd_buf_labels;
Mark Young6ba8abe2017-11-09 10:37:04 -0700440 std::string new_debug_report_message = "";
441 std::ostringstream oss;
Mark Young6ba8abe2017-11-09 10:37:04 -0700442
443 if (0 != src_object) {
Mark Young8504ba62018-03-21 13:35:34 -0600444 oss << "Object: 0x" << std::hex << src_object;
Mark Young6ba8abe2017-11-09 10:37:04 -0700445 // If this is a queue, add any queue labels to the callback data.
446 if (VK_OBJECT_TYPE_QUEUE == object_name_info.objectType) {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700447 auto label_iter = debug_data->debugUtilsQueueLabels.find(reinterpret_cast<VkQueue>(src_object));
448 if (label_iter != debug_data->debugUtilsQueueLabels.end()) {
John Zulaufc64f97c2019-04-10 10:34:52 -0600449 queue_labels = label_iter->second->Export();
450 callback_data.queueLabelCount = static_cast<uint32_t>(queue_labels.size());
451 callback_data.pQueueLabels = queue_labels.empty() ? nullptr : queue_labels.data();
Mark Young6ba8abe2017-11-09 10:37:04 -0700452 }
453 // If this is a command buffer, add any command buffer labels to the callback data.
454 } else if (VK_OBJECT_TYPE_COMMAND_BUFFER == object_name_info.objectType) {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700455 auto label_iter = debug_data->debugUtilsCmdBufLabels.find(reinterpret_cast<VkCommandBuffer>(src_object));
456 if (label_iter != debug_data->debugUtilsCmdBufLabels.end()) {
John Zulaufc64f97c2019-04-10 10:34:52 -0600457 cmd_buf_labels = label_iter->second->Export();
458 callback_data.cmdBufLabelCount = static_cast<uint32_t>(cmd_buf_labels.size());
459 callback_data.pCmdBufLabels = cmd_buf_labels.empty() ? nullptr : cmd_buf_labels.data();
Mark Young6ba8abe2017-11-09 10:37:04 -0700460 }
461 }
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700462
Mark Young6ba8abe2017-11-09 10:37:04 -0700463 // Look for any debug utils or marker names to use for this object
Mark Lobodzinski5d98ba12019-03-25 13:35:01 -0600464 object_label = debug_data->DebugReportGetUtilsObjectName(src_object);
465 if (object_label.empty()) {
466 object_label = debug_data->DebugReportGetMarkerObjectName(src_object);
Mark Young6ba8abe2017-11-09 10:37:04 -0700467 }
Mark Lobodzinski5d98ba12019-03-25 13:35:01 -0600468 if (!object_label.empty()) {
469 object_name_info.pObjectName = object_label.c_str();
470 oss << " (Name = " << object_label << " : Type = ";
Mark Young8504ba62018-03-21 13:35:34 -0600471 } else {
472 oss << " (Type = ";
Mark Young6ba8abe2017-11-09 10:37:04 -0700473 }
Mark Young8504ba62018-03-21 13:35:34 -0600474 oss << std::to_string(object_type) << ")";
475 } else {
476 oss << "Object: VK_NULL_HANDLE (Type = " << std::to_string(object_type) << ")";
Mark Young6ba8abe2017-11-09 10:37:04 -0700477 }
478 new_debug_report_message += oss.str();
479 new_debug_report_message += " | ";
480 new_debug_report_message += message;
481
482 while (layer_dbg_node) {
Mark Young8504ba62018-03-21 13:35:34 -0600483 // If the app uses the VK_EXT_debug_report extension, call all of those registered callbacks.
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700484 if (!layer_dbg_node->is_messenger && (layer_dbg_node->report.msgFlags & msg_flags)) {
485 if (text_vuid != nullptr) {
486 // If a text vuid is supplied for the old debug report extension, prepend it to the message string
487 new_debug_report_message.insert(0, " ] ");
488 new_debug_report_message.insert(0, text_vuid);
489 new_debug_report_message.insert(0, " [ ");
490 }
491
Dave Houlton407df732018-08-06 17:58:24 -0600492 if (layer_dbg_node->report.pfnMsgCallback(msg_flags, object_type, src_object, location, 0, layer_prefix,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700493 new_debug_report_message.c_str(), layer_dbg_node->pUserData)) {
494 bail = true;
495 }
Mark Young8504ba62018-03-21 13:35:34 -0600496 // If the app uses the VK_EXT_debug_utils extension, call all of those registered callbacks.
Mark Young6ba8abe2017-11-09 10:37:04 -0700497 } else if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & severity) &&
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700498 (layer_dbg_node->messenger.messageType & types)) {
499 if (layer_dbg_node->messenger.pfnUserCallback(static_cast<VkDebugUtilsMessageSeverityFlagBitsEXT>(severity), types,
500 &callback_data, layer_dbg_node->pUserData)) {
501 bail = true;
502 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700503 }
504 layer_dbg_node = layer_dbg_node->pNext;
505 }
506
Mark Young6ba8abe2017-11-09 10:37:04 -0700507 return bail;
508}
509
510static inline void DebugAnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,
511 VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags) {
512 *dr_flags = 0;
513
514 if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) {
515 *dr_flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
516 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) {
517 if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) {
518 *dr_flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
519 } else {
520 *dr_flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
521 }
522 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) {
523 *dr_flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
524 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) {
525 *dr_flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
526 }
527}
528
529static inline bool debug_messenger_log_msg(const debug_report_data *debug_data,
530 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
531 VkDebugUtilsMessageTypeFlagsEXT message_type,
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700532 VkDebugUtilsMessengerCallbackDataEXT *callback_data,
533 const VkDebugUtilsMessengerEXT *messenger) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700534 bool bail = false;
535 VkLayerDbgFunctionNode *layer_dbg_node = NULL;
536
537 if (debug_data->debug_callback_list != NULL) {
538 layer_dbg_node = debug_data->debug_callback_list;
539 } else {
540 layer_dbg_node = debug_data->default_debug_callback_list;
541 }
542
543 VkDebugReportFlagsEXT object_flags = 0;
544
545 DebugAnnotFlagsToReportFlags(message_severity, message_type, &object_flags);
546
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700547 VkDebugUtilsObjectNameInfoEXT object_name_info;
548 object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
549 object_name_info.pNext = NULL;
550 object_name_info.objectType = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT;
551 object_name_info.objectHandle = HandleToUint64(*messenger);
552 object_name_info.pObjectName = NULL;
553 callback_data->pObjects = &object_name_info;
554 callback_data->objectCount = 1;
555
Mark Young6ba8abe2017-11-09 10:37:04 -0700556 while (layer_dbg_node) {
557 if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & message_severity) &&
558 (layer_dbg_node->messenger.messageType & message_type)) {
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700559 std::string messenger_label = debug_data->DebugReportGetUtilsObjectName(object_name_info.objectHandle);
560 if (!messenger_label.empty()) {
561 object_name_info.pObjectName = messenger_label.c_str();
Mark Young6ba8abe2017-11-09 10:37:04 -0700562 }
563 if (layer_dbg_node->messenger.pfnUserCallback(message_severity, message_type, callback_data,
564 layer_dbg_node->pUserData)) {
565 bail = true;
566 }
567 } else if (!layer_dbg_node->is_messenger && layer_dbg_node->report.msgFlags & object_flags) {
John Zulauf536649b2018-05-01 13:28:27 -0600568 VkDebugReportObjectTypeEXT object_type = convertCoreObjectToDebugReportObject(callback_data->pObjects[0].objectType);
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700569 std::string marker_label = debug_data->DebugReportGetMarkerObjectName(object_name_info.objectHandle);
570 if (marker_label.empty()) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700571 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
572 callback_data->messageIdNumber, callback_data->pMessageIdName,
573 callback_data->pMessage, layer_dbg_node->pUserData)) {
Tony Barbour3431dac2017-06-19 16:50:37 -0600574 bail = true;
575 }
576 } else {
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700577 std::string newMsg = "SrcObject name = " + marker_label;
Tony Barbour3431dac2017-06-19 16:50:37 -0600578 newMsg.append(" ");
Mark Young6ba8abe2017-11-09 10:37:04 -0700579 newMsg.append(callback_data->pMessage);
580 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
581 callback_data->messageIdNumber, callback_data->pMessageIdName,
582 newMsg.c_str(), layer_dbg_node->pUserData)) {
Tony Barbour3431dac2017-06-19 16:50:37 -0600583 bail = true;
584 }
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -0600585 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600586 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700587 layer_dbg_node = layer_dbg_node->pNext;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600588 }
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -0600589
590 return bail;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600591}
592
Mark Young6ba8abe2017-11-09 10:37:04 -0700593static inline debug_report_data *debug_utils_create_instance(
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700594 VkLayerInstanceDispatchTable *table, VkInstance inst, uint32_t extension_count,
Mark Young6ba8abe2017-11-09 10:37:04 -0700595 const char *const *enabled_extensions) // layer or extension name to be enabled
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600596{
Mark Lobodzinski12813302019-02-07 15:03:06 -0700597 debug_report_data *debug_data = new debug_report_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600598 for (uint32_t i = 0; i < extension_count; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700599 if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600600 debug_data->g_DEBUG_REPORT = true;
Mark Young6ba8abe2017-11-09 10:37:04 -0700601 } else if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
602 debug_data->g_DEBUG_UTILS = true;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600603 }
604 }
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600605 return debug_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600606}
607
Mark Young6ba8abe2017-11-09 10:37:04 -0700608static inline void layer_debug_utils_destroy_instance(debug_report_data *debug_data) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600609 if (debug_data) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700610 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600611 RemoveAllMessageCallbacks(debug_data, &debug_data->default_debug_callback_list);
612 RemoveAllMessageCallbacks(debug_data, &debug_data->debug_callback_list);
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700613 lock.unlock();
Mark Lobodzinski12813302019-02-07 15:03:06 -0700614 delete (debug_data);
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600615 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600616}
617
Mark Young6ba8abe2017-11-09 10:37:04 -0700618static inline debug_report_data *layer_debug_utils_create_device(debug_report_data *instance_debug_data, VkDevice device) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600619 // DEBUG_REPORT shares data between Instance and Device,
620 // so just return instance's data pointer
Courtney Goeltzenleuchterb9f0bf32015-06-14 09:50:18 -0600621 return instance_debug_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600622}
623
Mark Young6ba8abe2017-11-09 10:37:04 -0700624static inline void layer_debug_utils_destroy_device(VkDevice device) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600625 // Nothing to do since we're using instance data record
626}
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600627
Mark Young6ba8abe2017-11-09 10:37:04 -0700628static inline void layer_destroy_messenger_callback(debug_report_data *debug_data, VkDebugUtilsMessengerEXT messenger,
629 const VkAllocationCallbacks *allocator) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700630 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -0700631 RemoveDebugUtilsMessenger(debug_data, &debug_data->debug_callback_list, messenger);
632 RemoveDebugUtilsMessenger(debug_data, &debug_data->default_debug_callback_list, messenger);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600633}
634
Mark Young6ba8abe2017-11-09 10:37:04 -0700635static inline VkResult layer_create_messenger_callback(debug_report_data *debug_data, bool default_callback,
636 const VkDebugUtilsMessengerCreateInfoEXT *create_info,
637 const VkAllocationCallbacks *allocator,
638 VkDebugUtilsMessengerEXT *messenger) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700639 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700640 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700641 if (!pNewDbgFuncNode) return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young6ba8abe2017-11-09 10:37:04 -0700642 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
643 pNewDbgFuncNode->is_messenger = true;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600644
Tobin Ehliseb7715d2015-09-21 09:36:47 -0600645 // Handle of 0 is logging_callback so use allocated Node address as unique handle
Mark Young6ba8abe2017-11-09 10:37:04 -0700646 if (!(*messenger)) *messenger = (VkDebugUtilsMessengerEXT)pNewDbgFuncNode;
647 pNewDbgFuncNode->messenger.messenger = *messenger;
648 pNewDbgFuncNode->messenger.pfnUserCallback = create_info->pfnUserCallback;
649 pNewDbgFuncNode->messenger.messageSeverity = create_info->messageSeverity;
650 pNewDbgFuncNode->messenger.messageType = create_info->messageType;
651 pNewDbgFuncNode->pUserData = create_info->pUserData;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600652
Mark Young6ba8abe2017-11-09 10:37:04 -0700653 debug_data->active_severities |= create_info->messageSeverity;
654 debug_data->active_types |= create_info->messageType;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600655 if (default_callback) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700656 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600657 } else {
Mark Young6ba8abe2017-11-09 10:37:04 -0700658 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600659 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600660
Mark Young6ba8abe2017-11-09 10:37:04 -0700661 VkDebugUtilsMessengerCallbackDataEXT callback_data = {};
Mark Young6ba8abe2017-11-09 10:37:04 -0700662 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
663 callback_data.pNext = NULL;
664 callback_data.flags = 0;
665 callback_data.pMessageIdName = "Layer Internal Message";
666 callback_data.messageIdNumber = 0;
667 callback_data.pMessage = "Added messenger";
668 callback_data.queueLabelCount = 0;
669 callback_data.pQueueLabels = NULL;
670 callback_data.cmdBufLabelCount = 0;
671 callback_data.pCmdBufLabels = NULL;
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700672 callback_data.objectCount = 0;
673 callback_data.pObjects = NULL;
Mark Young6ba8abe2017-11-09 10:37:04 -0700674 debug_messenger_log_msg(debug_data, VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700675 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, &callback_data, messenger);
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600676 return VK_SUCCESS;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600677}
678
Mark Young6ba8abe2017-11-09 10:37:04 -0700679static inline void layer_destroy_report_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback,
680 const VkAllocationCallbacks *allocator) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700681 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -0700682 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->debug_callback_list, callback);
683 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->default_debug_callback_list, callback);
684}
685
686static inline VkResult layer_create_report_callback(debug_report_data *debug_data, bool default_callback,
687 const VkDebugReportCallbackCreateInfoEXT *create_info,
688 const VkAllocationCallbacks *allocator, VkDebugReportCallbackEXT *callback) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700689 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -0700690 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
691 if (!pNewDbgFuncNode) {
692 return VK_ERROR_OUT_OF_HOST_MEMORY;
693 }
694 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
695 pNewDbgFuncNode->is_messenger = false;
696
697 // Handle of 0 is logging_callback so use allocated Node address as unique handle
698 if (!(*callback)) *callback = (VkDebugReportCallbackEXT)pNewDbgFuncNode;
699 pNewDbgFuncNode->report.msgCallback = *callback;
700 pNewDbgFuncNode->report.pfnMsgCallback = create_info->pfnCallback;
701 pNewDbgFuncNode->report.msgFlags = create_info->flags;
702 pNewDbgFuncNode->pUserData = create_info->pUserData;
703
704 VkFlags local_severity = 0;
705 VkFlags local_type = 0;
706 DebugReportFlagsToAnnotFlags(create_info->flags, true, &local_severity, &local_type);
707 debug_data->active_severities |= local_severity;
708 debug_data->active_types |= local_type;
709 if (default_callback) {
710 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
711 } else {
712 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600713 }
714
Mark Young6ba8abe2017-11-09 10:37:04 -0700715 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, (uint64_t)*callback, 0,
Dave Houlton407df732018-08-06 17:58:24 -0600716 "DebugReport", "Added callback", kVUIDUndefined);
Mark Young6ba8abe2017-11-09 10:37:04 -0700717 return VK_SUCCESS;
718}
719
720static inline PFN_vkVoidFunction debug_utils_get_instance_proc_addr(debug_report_data *debug_data, const char *func_name) {
721 if (!debug_data) {
722 return NULL;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600723 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700724 if (debug_data->g_DEBUG_REPORT) {
725 if (!strcmp(func_name, "vkCreateDebugReportCallbackEXT")) {
726 return (PFN_vkVoidFunction)vkCreateDebugReportCallbackEXT;
727 }
728 if (!strcmp(func_name, "vkDestroyDebugReportCallbackEXT")) {
729 return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT;
730 }
731 if (!strcmp(func_name, "vkDebugReportMessageEXT")) {
732 return (PFN_vkVoidFunction)vkDebugReportMessageEXT;
733 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600734 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700735 if (debug_data->g_DEBUG_UTILS) {
736 if (!strcmp(func_name, "vkCreateDebugUtilsMessengerEXT")) {
737 return (PFN_vkVoidFunction)vkCreateDebugUtilsMessengerEXT;
738 }
739 if (!strcmp(func_name, "vkDestroyDebugUtilsMessengerEXT")) {
740 return (PFN_vkVoidFunction)vkDestroyDebugUtilsMessengerEXT;
741 }
742 if (!strcmp(func_name, "vkSubmitDebugUtilsMessageEXT")) {
743 return (PFN_vkVoidFunction)vkSubmitDebugUtilsMessageEXT;
744 }
Courtney Goeltzenleuchter822e8d72015-11-30 15:28:25 -0700745 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600746 return NULL;
747}
748
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600749// This utility (called at vkCreateInstance() time), looks at a pNext chain.
750// It counts any VkDebugReportCallbackCreateInfoEXT structs that it finds. It
751// then allocates an array that can hold that many structs, as well as that
752// many VkDebugReportCallbackEXT handles. It then copies each
753// VkDebugReportCallbackCreateInfoEXT, and initializes each handle.
Mark Young6ba8abe2017-11-09 10:37:04 -0700754static inline VkResult layer_copy_tmp_report_callbacks(const void *pChain, uint32_t *num_callbacks,
755 VkDebugReportCallbackCreateInfoEXT **infos,
756 VkDebugReportCallbackEXT **callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600757 uint32_t n = *num_callbacks = 0;
758
759 const void *pNext = pChain;
760 while (pNext) {
761 // 1st, count the number VkDebugReportCallbackCreateInfoEXT:
762 if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
763 n++;
764 }
765 pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext;
766 }
767 if (n == 0) {
768 return VK_SUCCESS;
769 }
770
771 // 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT:
772 VkDebugReportCallbackCreateInfoEXT *pInfos = *infos =
773 ((VkDebugReportCallbackCreateInfoEXT *)malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT)));
774 if (!pInfos) {
775 return VK_ERROR_OUT_OF_HOST_MEMORY;
776 }
777 // 3rd, allocate memory for a unique handle for each callback:
778 VkDebugReportCallbackEXT *pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)malloc(n * sizeof(VkDebugReportCallbackEXT)));
779 if (!pCallbacks) {
780 free(pInfos);
781 return VK_ERROR_OUT_OF_HOST_MEMORY;
782 }
783 // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by
784 // vkDestroyInstance, and assign a unique handle to each callback (just
785 // use the address of the copied VkDebugReportCallbackCreateInfoEXT):
786 pNext = pChain;
787 while (pNext) {
788 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
789 memcpy(pInfos, pNext, sizeof(VkDebugReportCallbackCreateInfoEXT));
790 *pCallbacks++ = (VkDebugReportCallbackEXT)pInfos++;
791 }
792 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
793 }
794
795 *num_callbacks = n;
796 return VK_SUCCESS;
797}
798
Mark Young6ba8abe2017-11-09 10:37:04 -0700799// This utility frees the arrays allocated by layer_copy_tmp_report_callbacks()
800static inline void layer_free_tmp_report_callbacks(VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600801 free(infos);
802 free(callbacks);
803}
804
805// This utility enables all of the VkDebugReportCallbackCreateInfoEXT structs
Mark Young6ba8abe2017-11-09 10:37:04 -0700806// that were copied by layer_copy_tmp_report_callbacks()
807static inline VkResult layer_enable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
808 VkDebugReportCallbackCreateInfoEXT *infos,
809 VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600810 VkResult rtn = VK_SUCCESS;
811 for (uint32_t i = 0; i < num_callbacks; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700812 rtn = layer_create_report_callback(debug_data, false, &infos[i], NULL, &callbacks[i]);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600813 if (rtn != VK_SUCCESS) {
814 for (uint32_t j = 0; j < i; j++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700815 layer_destroy_report_callback(debug_data, callbacks[j], NULL);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600816 }
817 return rtn;
818 }
819 }
820 return rtn;
821}
822
823// This utility disables all of the VkDebugReportCallbackCreateInfoEXT structs
Mark Young6ba8abe2017-11-09 10:37:04 -0700824// that were copied by layer_copy_tmp_report_callbacks()
825static inline void layer_disable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
826 VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600827 for (uint32_t i = 0; i < num_callbacks; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700828 layer_destroy_report_callback(debug_data, callbacks[i], NULL);
829 }
830}
831
832// This utility (called at vkCreateInstance() time), looks at a pNext chain.
833// It counts any VkDebugUtilsMessengerCreateInfoEXT structs that it finds. It
834// then allocates an array that can hold that many structs, as well as that
835// many VkDebugUtilsMessengerEXT handles. It then copies each
836// VkDebugUtilsMessengerCreateInfoEXT, and initializes each handle.
Mark Young8504ba62018-03-21 13:35:34 -0600837static inline VkResult layer_copy_tmp_debug_messengers(const void *pChain, uint32_t *num_messengers,
838 VkDebugUtilsMessengerCreateInfoEXT **infos,
839 VkDebugUtilsMessengerEXT **messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700840 uint32_t n = *num_messengers = 0;
841
842 const void *pNext = pChain;
843 while (pNext) {
844 // 1st, count the number VkDebugUtilsMessengerCreateInfoEXT:
845 if (((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
846 n++;
847 }
848 pNext = (void *)((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->pNext;
849 }
850 if (n == 0) {
851 return VK_SUCCESS;
852 }
853
854 // 2nd, allocate memory for each VkDebugUtilsMessengerCreateInfoEXT:
855 VkDebugUtilsMessengerCreateInfoEXT *pInfos = *infos =
856 ((VkDebugUtilsMessengerCreateInfoEXT *)malloc(n * sizeof(VkDebugUtilsMessengerCreateInfoEXT)));
857 if (!pInfos) {
858 return VK_ERROR_OUT_OF_HOST_MEMORY;
859 }
860 // 3rd, allocate memory for a unique handle for each messenger:
861 VkDebugUtilsMessengerEXT *pMessengers = *messengers =
862 ((VkDebugUtilsMessengerEXT *)malloc(n * sizeof(VkDebugUtilsMessengerEXT)));
863 if (!pMessengers) {
864 free(pInfos);
865 return VK_ERROR_OUT_OF_HOST_MEMORY;
866 }
867 // 4th, copy each VkDebugUtilsMessengerCreateInfoEXT for use by
868 // vkDestroyInstance, and assign a unique handle to each callback (just
869 // use the address of the copied VkDebugUtilsMessengerCreateInfoEXT):
870 pNext = pChain;
871 while (pNext) {
872 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
873 memcpy(pInfos, pNext, sizeof(VkDebugUtilsMessengerCreateInfoEXT));
874 *pMessengers++ = (VkDebugUtilsMessengerEXT)pInfos++;
875 }
876 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
877 }
878
879 *num_messengers = n;
880 return VK_SUCCESS;
881}
882
883// This utility frees the arrays allocated by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600884static inline void layer_free_tmp_debug_messengers(VkDebugUtilsMessengerCreateInfoEXT *infos,
885 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700886 free(infos);
887 free(messengers);
888}
889
890// This utility enables all of the VkDebugUtilsMessengerCreateInfoEXT structs
891// that were copied by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600892static inline VkResult layer_enable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
893 VkDebugUtilsMessengerCreateInfoEXT *infos,
894 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700895 VkResult rtn = VK_SUCCESS;
896 for (uint32_t i = 0; i < num_messengers; i++) {
897 rtn = layer_create_messenger_callback(debug_data, false, &infos[i], NULL, &messengers[i]);
898 if (rtn != VK_SUCCESS) {
899 for (uint32_t j = 0; j < i; j++) {
900 layer_destroy_messenger_callback(debug_data, messengers[j], NULL);
901 }
902 return rtn;
903 }
904 }
905 return rtn;
906}
907
908// This utility disables all of the VkDebugUtilsMessengerCreateInfoEXT structs
909// that were copied by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600910static inline void layer_disable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
911 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700912 for (uint32_t i = 0; i < num_messengers; i++) {
913 layer_destroy_messenger_callback(debug_data, messengers[i], NULL);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600914 }
915}
916
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600917// Checks if the message will get logged.
918// Allows layer to defer collecting & formating data if the
919// message will be discarded.
Mark Young6ba8abe2017-11-09 10:37:04 -0700920static inline bool will_log_msg(debug_report_data *debug_data, VkFlags msg_flags) {
921 VkFlags local_severity = 0;
922 VkFlags local_type = 0;
923 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
924 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600925 // Message is not wanted
Courtney Goeltzenleuchter6a564a12015-09-18 16:30:24 -0600926 return false;
927 }
928
929 return true;
930}
John Zulauf6664e272018-01-17 11:00:22 -0700931#ifndef WIN32
Mark Lobodzinski1bcbdf92018-02-07 10:00:22 -0700932static inline int string_sprintf(std::string *output, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
John Zulauf6664e272018-01-17 11:00:22 -0700933#endif
Mark Lobodzinski1bcbdf92018-02-07 10:00:22 -0700934static inline int string_sprintf(std::string *output, const char *fmt, ...) {
John Zulauf6664e272018-01-17 11:00:22 -0700935 std::string &formatted = *output;
936 va_list argptr;
937 va_start(argptr, fmt);
938 int reserve = vsnprintf(nullptr, 0, fmt, argptr);
939 va_end(argptr);
John Zulaufdeaa0132018-12-12 16:22:30 -0700940 formatted.reserve(reserve + 1); // Set the storage length long enough to hold the output + null
941 formatted.resize(reserve); // Set the *logical* length to be what vsprintf will write
John Zulauf6664e272018-01-17 11:00:22 -0700942 va_start(argptr, fmt);
943 int result = vsnprintf((char *)formatted.data(), formatted.capacity(), fmt, argptr);
944 va_end(argptr);
945 assert(result == reserve);
John Zulaufdeaa0132018-12-12 16:22:30 -0700946 assert((formatted.size() == strlen(formatted.c_str())));
John Zulauf6664e272018-01-17 11:00:22 -0700947 return result;
948}
Courtney Goeltzenleuchter6a564a12015-09-18 16:30:24 -0600949
Chris Forbes8a25bce2016-03-24 12:06:35 +1300950#ifdef WIN32
951static inline int vasprintf(char **strp, char const *fmt, va_list ap) {
952 *strp = nullptr;
953 int size = _vscprintf(fmt, ap);
954 if (size >= 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700955 *strp = (char *)malloc(size + 1);
Chris Forbes8a25bce2016-03-24 12:06:35 +1300956 if (!*strp) {
957 return -1;
958 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700959 _vsnprintf(*strp, size + 1, fmt, ap);
Chris Forbes8a25bce2016-03-24 12:06:35 +1300960 }
961 return size;
962}
963#endif
964
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700965// Output log message via DEBUG_REPORT. Takes format and variable arg list so that output string is only computed if a message
966// needs to be logged
Michael Lentine010f4692015-11-03 16:19:46 -0800967#ifndef WIN32
Mark Young6ba8abe2017-11-09 10:37:04 -0700968static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700969 uint64_t src_object, std::string vuid_text, const char *format, ...)
970 __attribute__((format(printf, 6, 7)));
Michael Lentine010f4692015-11-03 16:19:46 -0800971#endif
Mark Young6ba8abe2017-11-09 10:37:04 -0700972static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700973 uint64_t src_object, std::string vuid_text, const char *format, ...) {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700974 if (!debug_data) return false;
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700975 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700976 VkFlags local_severity = 0;
977 VkFlags local_type = 0;
978 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
979 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
980 // Message is not wanted
981 return false;
982 }
983
984 va_list argptr;
985 va_start(argptr, format);
986 char *str;
987 if (-1 == vasprintf(&str, format, argptr)) {
988 // On failure, glibc vasprintf leaves str undefined
989 str = nullptr;
990 }
991 va_end(argptr);
992
Dave Houlton407df732018-08-06 17:58:24 -0600993 std::string str_plus_spec_text(str ? str : "Allocation failure");
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700994
Dave Houlton407df732018-08-06 17:58:24 -0600995 // Append the spec error text to the error message, unless it's an UNASSIGNED or UNDEFINED vuid
996 if ((vuid_text.find("UNASSIGNED-") == std::string::npos) && (vuid_text.find(kVUIDUndefined) == std::string::npos)) {
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600997 // Linear search makes no assumptions about the layout of the string table
998 // This is not fast, but it does not need to be at this point in the error reporting path
999 uint32_t num_vuids = sizeof(vuid_spec_text) / sizeof(vuid_spec_text_pair);
1000 const char *spec_text = nullptr;
1001 for (uint32_t i = 0; i < num_vuids; i++) {
1002 if (0 == strcmp(vuid_text.c_str(), vuid_spec_text[i].vuid)) {
1003 spec_text = vuid_spec_text[i].spec_text;
1004 break;
1005 }
1006 }
1007
1008 if (nullptr == spec_text) {
Dave Houlton407df732018-08-06 17:58:24 -06001009 // If this happens, you've hit a VUID string that isn't defined in the spec's json file
1010 // Try running 'vk_validation_stats -c' to look for invalid VUID strings in the repo code
1011 assert(0);
1012 } else {
1013 str_plus_spec_text += " The Vulkan spec states: ";
Dave Houlton4d9b2f82018-10-24 18:21:06 -06001014 str_plus_spec_text += spec_text;
Dave Houlton407df732018-08-06 17:58:24 -06001015 }
Mark Lobodzinski316c18c2018-02-21 09:48:42 -07001016 }
1017
Dave Houlton8e9f6542018-05-18 12:18:22 -06001018 // Append layer prefix with VUID string, pass in recovered legacy numerical VUID
Dave Houlton407df732018-08-06 17:58:24 -06001019 bool result = debug_log_msg(debug_data, msg_flags, object_type, src_object, 0, "Validation", str_plus_spec_text.c_str(),
1020 vuid_text.c_str());
Mark Lobodzinski316c18c2018-02-21 09:48:42 -07001021
1022 free(str);
1023 return result;
1024}
1025
Mark Young6ba8abe2017-11-09 10:37:04 -07001026static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_log_callback(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
1027 uint64_t src_object, size_t location, int32_t msg_code,
1028 const char *layer_prefix, const char *message, void *user_data) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001029 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -07001030 char msg_flag_string[30];
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -06001031
Mark Young6ba8abe2017-11-09 10:37:04 -07001032 PrintMessageFlags(msg_flags, msg_flag_string);
Courtney Goeltzenleuchter2f25bb42015-06-14 11:29:24 -06001033
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001034 msg_buffer << layer_prefix << "(" << msg_flag_string << "): msg_code: " << msg_code << ": " << message << "\n";
1035 const std::string tmp = msg_buffer.str();
1036 const char *cstr = tmp.c_str();
1037
1038 fprintf((FILE *)user_data, "%s", cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -07001039 fflush((FILE *)user_data);
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -06001040
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001041#if defined __ANDROID__
1042 LOGCONSOLE("%s", cstr);
1043#endif
1044
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -06001045 return false;
Courtney Goeltzenleuchter2f25bb42015-06-14 11:29:24 -06001046}
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001047
Mark Young6ba8abe2017-11-09 10:37:04 -07001048static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_win32_debug_output_msg(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
1049 uint64_t src_object, size_t location, int32_t msg_code,
1050 const char *layer_prefix, const char *message,
1051 void *user_data) {
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001052#ifdef WIN32
Mark Young6ba8abe2017-11-09 10:37:04 -07001053 char msg_flag_string[30];
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001054 char buf[2048];
1055
Mark Young6ba8abe2017-11-09 10:37:04 -07001056 PrintMessageFlags(msg_flags, msg_flag_string);
Mark Lobodzinskib1fd9d12018-03-30 14:26:00 -06001057 _snprintf(buf, sizeof(buf) - 1, "%s (%s): msg_code: %d: %s\n", layer_prefix, msg_flag_string, msg_code, message);
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001058
1059 OutputDebugString(buf);
1060#endif
1061
1062 return false;
1063}
1064
Mark Young6ba8abe2017-11-09 10:37:04 -07001065static inline VKAPI_ATTR VkBool32 VKAPI_CALL DebugBreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT obj_type,
1066 uint64_t src_object, size_t location, int32_t msg_code,
1067 const char *layer_prefix, const char *message, void *user_data) {
Mark Lobodzinskic9d81652017-08-10 11:01:17 -06001068#ifdef WIN32
1069 DebugBreak();
1070#else
1071 raise(SIGTRAP);
1072#endif
1073
1074 return false;
1075}
1076
Mark Young6ba8abe2017-11-09 10:37:04 -07001077static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_log_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
1078 VkDebugUtilsMessageTypeFlagsEXT message_type,
1079 const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
1080 void *user_data) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001081 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -07001082 char msg_severity[30];
1083 char msg_type[30];
1084
1085 PrintMessageSeverity(message_severity, msg_severity);
1086 PrintMessageType(message_type, msg_type);
1087
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001088 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
1089 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
1090 msg_buffer << " Objects: " << callback_data->objectCount << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001091 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001092 msg_buffer << " [" << obj << "] " << std::hex << std::showbase
1093 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
1094 << callback_data->pObjects[obj].objectType
1095 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
1096 << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001097 }
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001098 const std::string tmp = msg_buffer.str();
1099 const char *cstr = tmp.c_str();
1100 fprintf((FILE *)user_data, "%s", cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -07001101 fflush((FILE *)user_data);
1102
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001103#if defined __ANDROID__
1104 LOGCONSOLE("%s", cstr);
1105#endif
1106
Mark Young6ba8abe2017-11-09 10:37:04 -07001107 return false;
Petr Krause9388f62017-05-13 20:53:12 +02001108}
1109
Mark Young6ba8abe2017-11-09 10:37:04 -07001110static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_win32_debug_output_msg(
1111 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type,
1112 const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data) {
1113#ifdef WIN32
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001114 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -07001115 char msg_severity[30];
1116 char msg_type[30];
Mark Lobodzinski863d5de2017-05-22 10:10:07 -06001117
Mark Young6ba8abe2017-11-09 10:37:04 -07001118 PrintMessageSeverity(message_severity, msg_severity);
1119 PrintMessageType(message_type, msg_type);
1120
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001121 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
1122 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
1123 msg_buffer << " Objects: " << callback_data->objectCount << "\n";
1124
Mark Young8504ba62018-03-21 13:35:34 -06001125 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001126 msg_buffer << " [" << obj << "] " << std::hex << std::showbase
1127 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
1128 << callback_data->pObjects[obj].objectType
1129 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
1130 << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001131 }
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001132 const std::string tmp = msg_buffer.str();
1133 const char *cstr = tmp.c_str();
1134 OutputDebugString(cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -07001135#endif
1136
1137 return false;
1138}
1139
John Zulaufc64f97c2019-04-10 10:34:52 -06001140template <typename Map>
1141static LoggingLabelState *GetLoggingLabelState(Map *map, typename Map::key_type key, bool insert) {
1142 auto iter = map->find(key);
1143 LoggingLabelState *label_state = nullptr;
1144 if (iter == map->end()) {
1145 if (insert) {
1146 // Add a label state if not present
1147 label_state = new LoggingLabelState();
1148 auto inserted = map->insert(std::make_pair(key, std::unique_ptr<LoggingLabelState>(new LoggingLabelState())));
1149 assert(inserted.second);
1150 iter = inserted.first;
1151 label_state = iter->second.get();
1152 }
1153 } else {
1154 label_state = iter->second.get();
1155 }
1156 return label_state;
Mark Young6ba8abe2017-11-09 10:37:04 -07001157}
1158
Mark Young8504ba62018-03-21 13:35:34 -06001159static inline void BeginQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
1160 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001161 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001162 if (nullptr != label_info && nullptr != label_info->pLabelName) {
John Zulaufc64f97c2019-04-10 10:34:52 -06001163 auto *label_state = GetLoggingLabelState(&report_data->debugUtilsQueueLabels, queue, /* insert */ true);
1164 assert(label_state);
1165 label_state->labels.push_back(LoggingLabel(label_info));
1166
1167 // TODO: Determine if this is the correct semantics for insert label vs. begin/end, perserving existing semantics for now
1168 label_state->insert_label.Reset();
Mark Young6ba8abe2017-11-09 10:37:04 -07001169 }
1170}
1171
Mark Young8504ba62018-03-21 13:35:34 -06001172static inline void EndQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001173 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
John Zulaufc64f97c2019-04-10 10:34:52 -06001174 auto *label_state = GetLoggingLabelState(&report_data->debugUtilsQueueLabels, queue, /* insert */ false);
1175 if (label_state) {
1176 // Pop the normal item
1177 if (!label_state->labels.empty()) {
1178 label_state->labels.pop_back();
Mark Young6ba8abe2017-11-09 10:37:04 -07001179 }
John Zulaufc64f97c2019-04-10 10:34:52 -06001180
1181 // TODO: Determine if this is the correct semantics for insert label vs. begin/end, perserving existing semantics for now
1182 label_state->insert_label.Reset();
Mark Young6ba8abe2017-11-09 10:37:04 -07001183 }
1184}
1185
Mark Young8504ba62018-03-21 13:35:34 -06001186static inline void InsertQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
1187 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001188 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
John Zulaufc64f97c2019-04-10 10:34:52 -06001189 auto *label_state = GetLoggingLabelState(&report_data->debugUtilsQueueLabels, queue, /* insert */ true);
1190
1191 // TODO: Determine if this is the correct semantics for insert label vs. begin/end, perserving existing semantics for now
1192 label_state->insert_label = LoggingLabel(label_info);
Mark Young6ba8abe2017-11-09 10:37:04 -07001193}
1194
Mark Young8504ba62018-03-21 13:35:34 -06001195static inline void BeginCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1196 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001197 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001198 if (nullptr != label_info && nullptr != label_info->pLabelName) {
John Zulaufc64f97c2019-04-10 10:34:52 -06001199 auto *label_state = GetLoggingLabelState(&report_data->debugUtilsCmdBufLabels, command_buffer, /* insert */ true);
1200 assert(label_state);
1201 label_state->labels.push_back(LoggingLabel(label_info));
1202
1203 // TODO: Determine if this is the correct semantics for insert label vs. begin/end, perserving existing semantics for now
1204 label_state->insert_label.Reset();
Mark Young6ba8abe2017-11-09 10:37:04 -07001205 }
1206}
1207
Mark Young8504ba62018-03-21 13:35:34 -06001208static inline void EndCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001209 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
John Zulaufc64f97c2019-04-10 10:34:52 -06001210 auto *label_state = GetLoggingLabelState(&report_data->debugUtilsCmdBufLabels, command_buffer, /* insert */ false);
1211 if (label_state) {
1212 // Pop the normal item
1213 if (!label_state->labels.empty()) {
1214 label_state->labels.pop_back();
Mark Young6ba8abe2017-11-09 10:37:04 -07001215 }
John Zulaufc64f97c2019-04-10 10:34:52 -06001216
1217 // TODO: Determine if this is the correct semantics for insert label vs. begin/end, perserving existing semantics for now
1218 label_state->insert_label.Reset();
Mark Young6ba8abe2017-11-09 10:37:04 -07001219 }
1220}
1221
Mark Young8504ba62018-03-21 13:35:34 -06001222static inline void InsertCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1223 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001224 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
John Zulaufc64f97c2019-04-10 10:34:52 -06001225 auto *label_state = GetLoggingLabelState(&report_data->debugUtilsCmdBufLabels, command_buffer, /* insert */ true);
1226 assert(label_state);
1227
1228 // TODO: Determine if this is the correct semantics for insert label vs. begin/end, perserving existing semantics for now
1229 label_state->insert_label = LoggingLabel(label_info);
1230}
1231
1232// Current tracking beyond a single command buffer scope is incorrect, and even when it is we need to be able to clean up
1233static inline void ResetCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
1234 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
1235 auto *label_state = GetLoggingLabelState(&report_data->debugUtilsCmdBufLabels, command_buffer, /* insert */ false);
1236 if (label_state) {
1237 label_state->labels.clear();
1238 label_state->insert_label.Reset();
Mark Young6ba8abe2017-11-09 10:37:04 -07001239 }
1240}
Mark Lobodzinski863d5de2017-05-22 10:10:07 -06001241
John Zulaufc64f97c2019-04-10 10:34:52 -06001242static inline void EraseCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
1243 report_data->debugUtilsCmdBufLabels.erase(command_buffer);
1244}
1245
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001246#endif // LAYER_LOGGING_H