blob: 68b6ee16781c2c49415a09d3079a52b7d5d92061 [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
Mark Lobodzinskib87f9022016-05-24 16:04:56 -060027#include "vk_loader_layer.h"
Tobin Ehlis2d9deec2016-04-21 14:19:26 -060028#include "vk_layer_config.h"
Tobin Ehlisa0cb02e2015-07-03 10:15:26 -060029#include "vk_layer_data.h"
Tobin Ehlis2d9deec2016-04-21 14:19:26 -060030#include "vk_loader_platform.h"
31#include "vulkan/vk_layer.h"
Mark Young6ba8abe2017-11-09 10:37:04 -070032#include "vk_object_types.h"
Mark Lobodzinski487a0d12018-03-30 10:09:03 -060033#include "vk_validation_error_messages.h"
Lenny Komow4c0da772018-07-03 10:17:21 -060034#include "vk_layer_dispatch_table.h"
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -070035#include <mutex>
Mark Lobodzinskic9d81652017-08-10 11:01:17 -060036#include <signal.h>
Karl Schultzd7f37542016-05-10 11:36:08 -060037#include <cinttypes>
Tobin Ehlis2d9deec2016-04-21 14:19:26 -060038#include <stdarg.h>
39#include <stdbool.h>
40#include <stdio.h>
41#include <unordered_map>
Mark Lobodzinski97c4d512016-05-19 15:27:18 -060042#include <vector>
Mark Young6ba8abe2017-11-09 10:37:04 -070043#include <sstream>
44#include <string>
45
Dave Houlton57ae22f2018-05-18 16:20:52 -060046// Suppress unused warning on Linux
47#if defined(__GNUC__)
Dave Houltoncfcecbf2018-05-31 16:20:57 -060048#define DECORATE_UNUSED __attribute__((unused))
49#else
50#define DECORATE_UNUSED
Dave Houlton57ae22f2018-05-18 16:20:52 -060051#endif
52
Mark Lobodzinski706e15a2018-12-12 15:35:29 -070053#if defined __ANDROID__
54#include <android/log.h>
55#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "VALIDATION", __VA_ARGS__))
56#else
57#define LOGCONSOLE(...) \
58 { \
59 printf(__VA_ARGS__); \
60 printf("\n"); \
61 }
62#endif
63
Dave Houltoncfcecbf2018-05-31 16:20:57 -060064static const char DECORATE_UNUSED *kVUIDUndefined = "VUID_Undefined";
Dave Houlton8e9f6542018-05-18 12:18:22 -060065
Dave Houltoncfcecbf2018-05-31 16:20:57 -060066#undef DECORATE_UNUSED
Dave Houlton57ae22f2018-05-18 16:20:52 -060067
Mark Young6ba8abe2017-11-09 10:37:04 -070068// TODO: Could be autogenerated for the specific handles for extra type safety...
69template <typename HANDLE_T>
70static inline uint64_t HandleToUint64(HANDLE_T *h) {
71 return reinterpret_cast<uint64_t>(h);
72}
73
74static inline uint64_t HandleToUint64(uint64_t h) { return h; }
75
76// Data we store per label for logging
77typedef struct _LoggingLabelData {
78 std::string name;
79 float color[4];
80} LoggingLabelData;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -060081
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -060082typedef struct _debug_report_data {
Mark Lobodzinski12813302019-02-07 15:03:06 -070083 VkLayerDbgFunctionNode *debug_callback_list{nullptr};
84 VkLayerDbgFunctionNode *default_debug_callback_list{nullptr};
85 VkDebugUtilsMessageSeverityFlagsEXT active_severities{0};
86 VkDebugUtilsMessageTypeFlagsEXT active_types{0};
87 bool g_DEBUG_REPORT{false};
88 bool g_DEBUG_UTILS{false};
89 bool queueLabelHasInsert{false};
90 bool cmdBufLabelHasInsert{false};
91 std::unordered_map<uint64_t, std::string> debugObjectNameMap;
92 std::unordered_map<uint64_t, std::string> debugUtilsObjectNameMap;
93 std::unordered_map<VkQueue, std::vector<LoggingLabelData>> debugUtilsQueueLabels;
94 std::unordered_map<VkCommandBuffer, std::vector<LoggingLabelData>> debugUtilsCmdBufLabels;
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -070095 // This mutex is defined as mutable since the normal usage for a debug report object is as 'const'. The mutable keyword allows
96 // the layers to continue this pattern, but also allows them to use/change this specific member for synchronization purposes.
97 mutable std::mutex debug_report_mutex;
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -070098
99 void DebugReportSetUtilsObjectName(const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700100 std::unique_lock<std::mutex> lock(debug_report_mutex);
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700101 if (pNameInfo->pObjectName) {
Mark Lobodzinski20075722019-02-25 09:34:49 -0700102 debugUtilsObjectNameMap[pNameInfo->objectHandle] = pNameInfo->pObjectName;
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700103 } else {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700104 debugUtilsObjectNameMap.erase(pNameInfo->objectHandle);
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700105 }
106 }
107
108 void DebugReportSetMarkerObjectName(const VkDebugMarkerObjectNameInfoEXT *pNameInfo) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700109 std::unique_lock<std::mutex> lock(debug_report_mutex);
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700110 if (pNameInfo->pObjectName) {
Mark Lobodzinski20075722019-02-25 09:34:49 -0700111 debugObjectNameMap[pNameInfo->object] = pNameInfo->pObjectName;
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700112 } else {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700113 debugObjectNameMap.erase(pNameInfo->object);
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700114 }
115 }
116
117 std::string DebugReportGetUtilsObjectName(const uint64_t object) const {
118 std::string label = "";
Mark Lobodzinski61a6d622019-02-14 14:11:24 -0700119 const auto utils_name_iter = debugUtilsObjectNameMap.find(object);
Mark Lobodzinski12813302019-02-07 15:03:06 -0700120 if (utils_name_iter != debugUtilsObjectNameMap.end()) {
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700121 label = utils_name_iter->second;
122 }
123 return label;
124 }
125
126 std::string DebugReportGetMarkerObjectName(const uint64_t object) const {
127 std::string label = "";
Mark Lobodzinski61a6d622019-02-14 14:11:24 -0700128 const auto marker_name_iter = debugObjectNameMap.find(object);
Mark Lobodzinski12813302019-02-07 15:03:06 -0700129 if (marker_name_iter != debugObjectNameMap.end()) {
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -0700130 label = marker_name_iter->second;
131 }
132 return label;
133 }
134
Locke26335512019-02-18 13:49:02 -0700135 template <typename HANDLE_T>
136 std::string FormatHandle(HANDLE_T *h) const {
137 return FormatHandle(HandleToUint64(h));
138 }
139
140 std::string FormatHandle(uint64_t h) const {
Locked4722ab2019-02-25 12:25:35 -0700141 char uint64_string[64];
142 sprintf(uint64_string, "0x%" PRIxLEAST64, h);
143 std::string ret = uint64_string;
Locke26335512019-02-18 13:49:02 -0700144
145 std::string name = DebugReportGetUtilsObjectName(h);
146 if (name.empty()) {
147 name = DebugReportGetMarkerObjectName(h);
148 }
149 if (!name.empty()) {
150 ret.append("[");
151 ret.append(name);
152 ret.append("]");
153 }
154 return ret;
155 }
156
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600157} debug_report_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600158
Tobin Ehlis8d6acde2017-02-08 07:40:40 -0700159template debug_report_data *GetLayerDataPtr<debug_report_data>(void *data_key,
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700160 std::unordered_map<void *, debug_report_data *> &data_map);
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600161
Mark Young6ba8abe2017-11-09 10:37:04 -0700162static inline void DebugReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec,
163 VkDebugUtilsMessageSeverityFlagsEXT *da_severity,
164 VkDebugUtilsMessageTypeFlagsEXT *da_type) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700165 *da_severity = 0;
Mark Youngfbaae712018-10-04 14:33:50 -0600166 *da_type = 0;
Mark Youngc2347792018-05-30 08:41:25 -0600167 // If it's explicitly listed as a performance warning, treat it as a performance message.
168 // Otherwise, treat it as a validation issue.
169 if ((dr_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600170 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
171 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
Mark Youngc2347792018-05-30 08:41:25 -0600172 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700173 if ((dr_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600174 *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 -0700175 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700176 }
177 if ((dr_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600178 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700179 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700180 }
Mark Youngfbaae712018-10-04 14:33:50 -0600181 if ((dr_flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) != 0) {
182 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700183 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
184 }
185 if ((dr_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600186 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700187 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
188 }
189}
190
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600191// Forward Declarations
Mark Young6ba8abe2017-11-09 10:37:04 -0700192static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Dave Houlton407df732018-08-06 17:58:24 -0600193 uint64_t src_object, size_t location, const char *layer_prefix, const char *message,
194 const char *text_vuid);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600195
196// Add a debug message callback node structure to the specified callback linked list
Mark Young6ba8abe2017-11-09 10:37:04 -0700197static inline void AddDebugCallbackNode(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
198 VkLayerDbgFunctionNode *new_node) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600199 new_node->pNext = *list_head;
200 *list_head = new_node;
201}
202
Mark Young6ba8abe2017-11-09 10:37:04 -0700203// Remove specified debug messenger node structure from the specified linked list
204static inline void RemoveDebugUtilsMessenger(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
205 VkDebugUtilsMessengerEXT messenger) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600206 VkLayerDbgFunctionNode *cur_callback = *list_head;
Mark Youngfbaae712018-10-04 14:33:50 -0600207 VkLayerDbgFunctionNode *prev_callback = nullptr;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600208 bool matched = false;
Mark Young6ba8abe2017-11-09 10:37:04 -0700209 VkFlags local_severities = 0;
210 VkFlags local_types = 0;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600211
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600212 while (cur_callback) {
Mark Youngfbaae712018-10-04 14:33:50 -0600213 if (cur_callback->is_messenger) {
214 // If it's actually a messenger, then set it up for deletion.
215 if (cur_callback->messenger.messenger == messenger) {
216 matched = true;
217 if (*list_head == cur_callback) {
218 *list_head = cur_callback->pNext;
219 } else {
220 assert(nullptr != prev_callback);
221 prev_callback->pNext = cur_callback->pNext;
222 }
223 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
224 reinterpret_cast<uint64_t &>(cur_callback->messenger.messenger), 0, "DebugUtilsMessenger",
225 "Destroyed messenger\n", kVUIDUndefined);
226 } else {
227 // If it's not the one we're looking for, just keep the types/severities
228 local_severities |= cur_callback->messenger.messageSeverity;
229 local_types |= cur_callback->messenger.messageType;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600230 }
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600231 } else {
Mark Youngfbaae712018-10-04 14:33:50 -0600232 // If it's not a messenger, just keep the types/severities
233 VkFlags this_severities = 0;
234 VkFlags this_types = 0;
235 DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types);
236 local_severities |= this_severities;
237 local_types |= this_types;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600238 }
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600239 if (matched) {
Mark Youngfbaae712018-10-04 14:33:50 -0600240 free(cur_callback);
241 matched = false;
242 // Intentionally keep the last prev_callback, but select the proper cur_callback
243 if (nullptr != prev_callback) {
244 cur_callback = prev_callback->pNext;
245 } else {
246 cur_callback = *list_head;
247 }
248 } else {
249 prev_callback = cur_callback;
250 cur_callback = cur_callback->pNext;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600251 }
252 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700253 debug_data->active_severities = local_severities;
254 debug_data->active_types = local_types;
255}
256
257// Remove specified debug message callback node structure from the specified callback linked list
258static inline void RemoveDebugUtilsMessageCallback(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
259 VkDebugReportCallbackEXT callback) {
260 VkLayerDbgFunctionNode *cur_callback = *list_head;
Mark Youngfbaae712018-10-04 14:33:50 -0600261 VkLayerDbgFunctionNode *prev_callback = nullptr;
Mark Young6ba8abe2017-11-09 10:37:04 -0700262 bool matched = false;
263 VkFlags local_severities = 0;
264 VkFlags local_types = 0;
265
266 while (cur_callback) {
Mark Youngfbaae712018-10-04 14:33:50 -0600267 if (!cur_callback->is_messenger) {
268 // If it's actually a callback, then set it up for deletion.
269 if (cur_callback->report.msgCallback == callback) {
270 matched = true;
271 if (*list_head == cur_callback) {
272 *list_head = cur_callback->pNext;
273 } else {
274 assert(nullptr != prev_callback);
275 prev_callback->pNext = cur_callback->pNext;
276 }
277 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
278 reinterpret_cast<uint64_t &>(cur_callback->report.msgCallback), 0, "DebugReport",
279 "Destroyed callback\n", kVUIDUndefined);
280 } else {
281 // If it's not the one we're looking for, just keep the types/severities
282 VkFlags this_severities = 0;
283 VkFlags this_types = 0;
284 DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types);
285 local_severities |= this_severities;
286 local_types |= this_types;
Mark Young6ba8abe2017-11-09 10:37:04 -0700287 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700288 } else {
Mark Youngfbaae712018-10-04 14:33:50 -0600289 // If it's not a callback, just keep the types/severities
290 local_severities |= cur_callback->messenger.messageSeverity;
291 local_types |= cur_callback->messenger.messageType;
Mark Young6ba8abe2017-11-09 10:37:04 -0700292 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700293 if (matched) {
Mark Youngfbaae712018-10-04 14:33:50 -0600294 free(cur_callback);
295 matched = false;
296 // Intentionally keep the last prev_callback, but select the proper cur_callback
297 if (nullptr != prev_callback) {
298 cur_callback = prev_callback->pNext;
299 } else {
300 cur_callback = *list_head;
301 }
302 } else {
303 prev_callback = cur_callback;
304 cur_callback = cur_callback->pNext;
Mark Young6ba8abe2017-11-09 10:37:04 -0700305 }
306 }
307 debug_data->active_severities = local_severities;
308 debug_data->active_types = local_types;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600309}
310
311// Removes all debug callback function nodes from the specified callback linked lists and frees their resources
312static inline void RemoveAllMessageCallbacks(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head) {
313 VkLayerDbgFunctionNode *current_callback = *list_head;
314 VkLayerDbgFunctionNode *prev_callback = current_callback;
315
316 while (current_callback) {
317 prev_callback = current_callback->pNext;
Mark Young6ba8abe2017-11-09 10:37:04 -0700318 if (!current_callback->is_messenger) {
319 debug_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
Dave Houlton407df732018-08-06 17:58:24 -0600320 (uint64_t)current_callback->report.msgCallback, 0, "DebugReport",
321 "Debug Report callbacks not removed before DestroyInstance", kVUIDUndefined);
Mark Young6ba8abe2017-11-09 10:37:04 -0700322 } else {
323 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 -0600324 (uint64_t)current_callback->messenger.messenger, 0, "Messenger",
325 "Debug messengers not removed before DestroyInstance", kVUIDUndefined);
Mark Young6ba8abe2017-11-09 10:37:04 -0700326 }
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600327 free(current_callback);
328 current_callback = prev_callback;
329 }
330 *list_head = NULL;
331}
332
Mark Young6ba8abe2017-11-09 10:37:04 -0700333static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Dave Houlton407df732018-08-06 17:58:24 -0600334 uint64_t src_object, size_t location, const char *layer_prefix, const char *message,
335 const char *text_vuid) {
Dustin Graves8f1eab92016-04-05 09:41:17 -0600336 bool bail = false;
Mark Young6ba8abe2017-11-09 10:37:04 -0700337 VkLayerDbgFunctionNode *layer_dbg_node = NULL;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600338
Mark Lobodzinski55a197f2016-06-21 15:54:57 -0600339 if (debug_data->debug_callback_list != NULL) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700340 layer_dbg_node = debug_data->debug_callback_list;
Mark Lobodzinski55a197f2016-06-21 15:54:57 -0600341 } else {
Mark Young6ba8abe2017-11-09 10:37:04 -0700342 layer_dbg_node = debug_data->default_debug_callback_list;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600343 }
344
Mark Young6ba8abe2017-11-09 10:37:04 -0700345 VkDebugUtilsMessageSeverityFlagsEXT severity;
346 VkDebugUtilsMessageTypeFlagsEXT types;
347 VkDebugUtilsMessengerCallbackDataEXT callback_data;
348 VkDebugUtilsObjectNameInfoEXT object_name_info;
349
350 // Convert the info to the VK_EXT_debug_utils form in case we need it.
351 DebugReportFlagsToAnnotFlags(msg_flags, true, &severity, &types);
352 object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
353 object_name_info.pNext = NULL;
354 object_name_info.objectType = convertDebugReportObjectToCoreObject(object_type);
355 object_name_info.objectHandle = (uint64_t)(uintptr_t)src_object;
356 object_name_info.pObjectName = NULL;
357
358 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
359 callback_data.pNext = NULL;
360 callback_data.flags = 0;
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700361 callback_data.pMessageIdName = text_vuid;
Dave Houlton407df732018-08-06 17:58:24 -0600362 callback_data.messageIdNumber = 0; // deprecated, validation layers use only the pMessageIdName
Mark Young6ba8abe2017-11-09 10:37:04 -0700363 callback_data.pMessage = message;
364 callback_data.queueLabelCount = 0;
365 callback_data.pQueueLabels = NULL;
366 callback_data.cmdBufLabelCount = 0;
367 callback_data.pCmdBufLabels = NULL;
368 callback_data.objectCount = 1;
369 callback_data.pObjects = &object_name_info;
370
371 VkDebugUtilsLabelEXT *queue_labels = nullptr;
372 VkDebugUtilsLabelEXT *cmd_buf_labels = nullptr;
373 std::string new_debug_report_message = "";
374 std::ostringstream oss;
Mark Young6ba8abe2017-11-09 10:37:04 -0700375
376 if (0 != src_object) {
Mark Young8504ba62018-03-21 13:35:34 -0600377 oss << "Object: 0x" << std::hex << src_object;
Mark Young6ba8abe2017-11-09 10:37:04 -0700378 // If this is a queue, add any queue labels to the callback data.
379 if (VK_OBJECT_TYPE_QUEUE == object_name_info.objectType) {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700380 auto label_iter = debug_data->debugUtilsQueueLabels.find(reinterpret_cast<VkQueue>(src_object));
381 if (label_iter != debug_data->debugUtilsQueueLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700382 queue_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
383 if (nullptr != queue_labels) {
384 // Record the labels, but record them in reverse order since we want the
385 // most recent at the top.
386 uint32_t label_size = static_cast<uint32_t>(label_iter->second.size());
387 uint32_t last_index = label_size - 1;
388 for (uint32_t label = 0; label < label_size; ++label) {
389 queue_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
390 queue_labels[last_index - label].pNext = nullptr;
391 queue_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
392 queue_labels[last_index - label].color[0] = label_iter->second[label].color[0];
393 queue_labels[last_index - label].color[1] = label_iter->second[label].color[1];
394 queue_labels[last_index - label].color[2] = label_iter->second[label].color[2];
395 queue_labels[last_index - label].color[3] = label_iter->second[label].color[3];
396 }
397 callback_data.queueLabelCount = label_size;
398 callback_data.pQueueLabels = queue_labels;
399 }
400 }
401 // If this is a command buffer, add any command buffer labels to the callback data.
402 } else if (VK_OBJECT_TYPE_COMMAND_BUFFER == object_name_info.objectType) {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700403 auto label_iter = debug_data->debugUtilsCmdBufLabels.find(reinterpret_cast<VkCommandBuffer>(src_object));
404 if (label_iter != debug_data->debugUtilsCmdBufLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700405 cmd_buf_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
406 if (nullptr != cmd_buf_labels) {
407 // Record the labels, but record them in reverse order since we want the
408 // most recent at the top.
409 uint32_t label_size = static_cast<uint32_t>(label_iter->second.size());
410 uint32_t last_index = label_size - 1;
411 for (uint32_t label = 0; label < label_size; ++label) {
412 cmd_buf_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
413 cmd_buf_labels[last_index - label].pNext = nullptr;
414 cmd_buf_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
415 cmd_buf_labels[last_index - label].color[0] = label_iter->second[label].color[0];
416 cmd_buf_labels[last_index - label].color[1] = label_iter->second[label].color[1];
417 cmd_buf_labels[last_index - label].color[2] = label_iter->second[label].color[2];
418 cmd_buf_labels[last_index - label].color[3] = label_iter->second[label].color[3];
419 }
420 callback_data.cmdBufLabelCount = label_size;
421 callback_data.pCmdBufLabels = cmd_buf_labels;
422 }
423 }
424 }
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700425
Mark Young6ba8abe2017-11-09 10:37:04 -0700426 // Look for any debug utils or marker names to use for this object
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700427 std::string label = debug_data->DebugReportGetUtilsObjectName(src_object);
428 if (label.empty()) {
429 label = debug_data->DebugReportGetMarkerObjectName(src_object);
Mark Young6ba8abe2017-11-09 10:37:04 -0700430 }
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700431 if (!label.empty()) {
432 object_name_info.pObjectName = label.c_str();
433 oss << " (Name = " << label << " : Type = ";
Mark Young8504ba62018-03-21 13:35:34 -0600434 } else {
435 oss << " (Type = ";
Mark Young6ba8abe2017-11-09 10:37:04 -0700436 }
Mark Young8504ba62018-03-21 13:35:34 -0600437 oss << std::to_string(object_type) << ")";
438 } else {
439 oss << "Object: VK_NULL_HANDLE (Type = " << std::to_string(object_type) << ")";
Mark Young6ba8abe2017-11-09 10:37:04 -0700440 }
441 new_debug_report_message += oss.str();
442 new_debug_report_message += " | ";
443 new_debug_report_message += message;
444
445 while (layer_dbg_node) {
Mark Young8504ba62018-03-21 13:35:34 -0600446 // If the app uses the VK_EXT_debug_report extension, call all of those registered callbacks.
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700447 if (!layer_dbg_node->is_messenger && (layer_dbg_node->report.msgFlags & msg_flags)) {
448 if (text_vuid != nullptr) {
449 // If a text vuid is supplied for the old debug report extension, prepend it to the message string
450 new_debug_report_message.insert(0, " ] ");
451 new_debug_report_message.insert(0, text_vuid);
452 new_debug_report_message.insert(0, " [ ");
453 }
454
Dave Houlton407df732018-08-06 17:58:24 -0600455 if (layer_dbg_node->report.pfnMsgCallback(msg_flags, object_type, src_object, location, 0, layer_prefix,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700456 new_debug_report_message.c_str(), layer_dbg_node->pUserData)) {
457 bail = true;
458 }
Mark Young8504ba62018-03-21 13:35:34 -0600459 // If the app uses the VK_EXT_debug_utils extension, call all of those registered callbacks.
Mark Young6ba8abe2017-11-09 10:37:04 -0700460 } else if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & severity) &&
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700461 (layer_dbg_node->messenger.messageType & types)) {
462 if (layer_dbg_node->messenger.pfnUserCallback(static_cast<VkDebugUtilsMessageSeverityFlagBitsEXT>(severity), types,
463 &callback_data, layer_dbg_node->pUserData)) {
464 bail = true;
465 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700466 }
467 layer_dbg_node = layer_dbg_node->pNext;
468 }
469
470 if (nullptr != queue_labels) {
471 delete[] queue_labels;
472 }
473 if (nullptr != cmd_buf_labels) {
474 delete[] cmd_buf_labels;
475 }
476
477 return bail;
478}
479
480static inline void DebugAnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,
481 VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags) {
482 *dr_flags = 0;
483
484 if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) {
485 *dr_flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
486 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) {
487 if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) {
488 *dr_flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
489 } else {
490 *dr_flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
491 }
492 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) {
493 *dr_flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
494 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) {
495 *dr_flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
496 }
497}
498
499static inline bool debug_messenger_log_msg(const debug_report_data *debug_data,
500 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
501 VkDebugUtilsMessageTypeFlagsEXT message_type,
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700502 VkDebugUtilsMessengerCallbackDataEXT *callback_data,
503 const VkDebugUtilsMessengerEXT *messenger) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700504 bool bail = false;
505 VkLayerDbgFunctionNode *layer_dbg_node = NULL;
506
507 if (debug_data->debug_callback_list != NULL) {
508 layer_dbg_node = debug_data->debug_callback_list;
509 } else {
510 layer_dbg_node = debug_data->default_debug_callback_list;
511 }
512
513 VkDebugReportFlagsEXT object_flags = 0;
514
515 DebugAnnotFlagsToReportFlags(message_severity, message_type, &object_flags);
516
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700517 VkDebugUtilsObjectNameInfoEXT object_name_info;
518 object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
519 object_name_info.pNext = NULL;
520 object_name_info.objectType = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT;
521 object_name_info.objectHandle = HandleToUint64(*messenger);
522 object_name_info.pObjectName = NULL;
523 callback_data->pObjects = &object_name_info;
524 callback_data->objectCount = 1;
525
Mark Young6ba8abe2017-11-09 10:37:04 -0700526 while (layer_dbg_node) {
527 if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & message_severity) &&
528 (layer_dbg_node->messenger.messageType & message_type)) {
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700529 std::string messenger_label = debug_data->DebugReportGetUtilsObjectName(object_name_info.objectHandle);
530 if (!messenger_label.empty()) {
531 object_name_info.pObjectName = messenger_label.c_str();
Mark Young6ba8abe2017-11-09 10:37:04 -0700532 }
533 if (layer_dbg_node->messenger.pfnUserCallback(message_severity, message_type, callback_data,
534 layer_dbg_node->pUserData)) {
535 bail = true;
536 }
537 } else if (!layer_dbg_node->is_messenger && layer_dbg_node->report.msgFlags & object_flags) {
John Zulauf536649b2018-05-01 13:28:27 -0600538 VkDebugReportObjectTypeEXT object_type = convertCoreObjectToDebugReportObject(callback_data->pObjects[0].objectType);
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700539 std::string marker_label = debug_data->DebugReportGetMarkerObjectName(object_name_info.objectHandle);
540 if (marker_label.empty()) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700541 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
542 callback_data->messageIdNumber, callback_data->pMessageIdName,
543 callback_data->pMessage, layer_dbg_node->pUserData)) {
Tony Barbour3431dac2017-06-19 16:50:37 -0600544 bail = true;
545 }
546 } else {
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700547 std::string newMsg = "SrcObject name = " + marker_label;
Tony Barbour3431dac2017-06-19 16:50:37 -0600548 newMsg.append(" ");
Mark Young6ba8abe2017-11-09 10:37:04 -0700549 newMsg.append(callback_data->pMessage);
550 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
551 callback_data->messageIdNumber, callback_data->pMessageIdName,
552 newMsg.c_str(), layer_dbg_node->pUserData)) {
Tony Barbour3431dac2017-06-19 16:50:37 -0600553 bail = true;
554 }
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -0600555 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600556 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700557 layer_dbg_node = layer_dbg_node->pNext;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600558 }
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -0600559
560 return bail;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600561}
562
Mark Young6ba8abe2017-11-09 10:37:04 -0700563static inline debug_report_data *debug_utils_create_instance(
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700564 VkLayerInstanceDispatchTable *table, VkInstance inst, uint32_t extension_count,
Mark Young6ba8abe2017-11-09 10:37:04 -0700565 const char *const *enabled_extensions) // layer or extension name to be enabled
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600566{
Mark Lobodzinski12813302019-02-07 15:03:06 -0700567 debug_report_data *debug_data = new debug_report_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600568 for (uint32_t i = 0; i < extension_count; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700569 if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600570 debug_data->g_DEBUG_REPORT = true;
Mark Young6ba8abe2017-11-09 10:37:04 -0700571 } else if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
572 debug_data->g_DEBUG_UTILS = true;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600573 }
574 }
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600575 return debug_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600576}
577
Mark Young6ba8abe2017-11-09 10:37:04 -0700578static inline void layer_debug_utils_destroy_instance(debug_report_data *debug_data) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600579 if (debug_data) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700580 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600581 RemoveAllMessageCallbacks(debug_data, &debug_data->default_debug_callback_list);
582 RemoveAllMessageCallbacks(debug_data, &debug_data->debug_callback_list);
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700583 lock.unlock();
Mark Lobodzinski12813302019-02-07 15:03:06 -0700584 delete (debug_data);
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600585 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600586}
587
Mark Young6ba8abe2017-11-09 10:37:04 -0700588static inline debug_report_data *layer_debug_utils_create_device(debug_report_data *instance_debug_data, VkDevice device) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600589 // DEBUG_REPORT shares data between Instance and Device,
590 // so just return instance's data pointer
Courtney Goeltzenleuchterb9f0bf32015-06-14 09:50:18 -0600591 return instance_debug_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600592}
593
Mark Young6ba8abe2017-11-09 10:37:04 -0700594static inline void layer_debug_utils_destroy_device(VkDevice device) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600595 // Nothing to do since we're using instance data record
596}
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600597
Mark Young6ba8abe2017-11-09 10:37:04 -0700598static inline void layer_destroy_messenger_callback(debug_report_data *debug_data, VkDebugUtilsMessengerEXT messenger,
599 const VkAllocationCallbacks *allocator) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700600 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -0700601 RemoveDebugUtilsMessenger(debug_data, &debug_data->debug_callback_list, messenger);
602 RemoveDebugUtilsMessenger(debug_data, &debug_data->default_debug_callback_list, messenger);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600603}
604
Mark Young6ba8abe2017-11-09 10:37:04 -0700605static inline VkResult layer_create_messenger_callback(debug_report_data *debug_data, bool default_callback,
606 const VkDebugUtilsMessengerCreateInfoEXT *create_info,
607 const VkAllocationCallbacks *allocator,
608 VkDebugUtilsMessengerEXT *messenger) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700609 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700610 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700611 if (!pNewDbgFuncNode) return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young6ba8abe2017-11-09 10:37:04 -0700612 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
613 pNewDbgFuncNode->is_messenger = true;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600614
Tobin Ehliseb7715d2015-09-21 09:36:47 -0600615 // Handle of 0 is logging_callback so use allocated Node address as unique handle
Mark Young6ba8abe2017-11-09 10:37:04 -0700616 if (!(*messenger)) *messenger = (VkDebugUtilsMessengerEXT)pNewDbgFuncNode;
617 pNewDbgFuncNode->messenger.messenger = *messenger;
618 pNewDbgFuncNode->messenger.pfnUserCallback = create_info->pfnUserCallback;
619 pNewDbgFuncNode->messenger.messageSeverity = create_info->messageSeverity;
620 pNewDbgFuncNode->messenger.messageType = create_info->messageType;
621 pNewDbgFuncNode->pUserData = create_info->pUserData;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600622
Mark Young6ba8abe2017-11-09 10:37:04 -0700623 debug_data->active_severities |= create_info->messageSeverity;
624 debug_data->active_types |= create_info->messageType;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600625 if (default_callback) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700626 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600627 } else {
Mark Young6ba8abe2017-11-09 10:37:04 -0700628 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600629 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600630
Mark Young6ba8abe2017-11-09 10:37:04 -0700631 VkDebugUtilsMessengerCallbackDataEXT callback_data = {};
Mark Young6ba8abe2017-11-09 10:37:04 -0700632 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
633 callback_data.pNext = NULL;
634 callback_data.flags = 0;
635 callback_data.pMessageIdName = "Layer Internal Message";
636 callback_data.messageIdNumber = 0;
637 callback_data.pMessage = "Added messenger";
638 callback_data.queueLabelCount = 0;
639 callback_data.pQueueLabels = NULL;
640 callback_data.cmdBufLabelCount = 0;
641 callback_data.pCmdBufLabels = NULL;
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700642 callback_data.objectCount = 0;
643 callback_data.pObjects = NULL;
Mark Young6ba8abe2017-11-09 10:37:04 -0700644 debug_messenger_log_msg(debug_data, VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700645 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, &callback_data, messenger);
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600646 return VK_SUCCESS;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600647}
648
Mark Young6ba8abe2017-11-09 10:37:04 -0700649static inline void layer_destroy_report_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback,
650 const VkAllocationCallbacks *allocator) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700651 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -0700652 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->debug_callback_list, callback);
653 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->default_debug_callback_list, callback);
654}
655
656static inline VkResult layer_create_report_callback(debug_report_data *debug_data, bool default_callback,
657 const VkDebugReportCallbackCreateInfoEXT *create_info,
658 const VkAllocationCallbacks *allocator, VkDebugReportCallbackEXT *callback) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700659 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -0700660 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
661 if (!pNewDbgFuncNode) {
662 return VK_ERROR_OUT_OF_HOST_MEMORY;
663 }
664 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
665 pNewDbgFuncNode->is_messenger = false;
666
667 // Handle of 0 is logging_callback so use allocated Node address as unique handle
668 if (!(*callback)) *callback = (VkDebugReportCallbackEXT)pNewDbgFuncNode;
669 pNewDbgFuncNode->report.msgCallback = *callback;
670 pNewDbgFuncNode->report.pfnMsgCallback = create_info->pfnCallback;
671 pNewDbgFuncNode->report.msgFlags = create_info->flags;
672 pNewDbgFuncNode->pUserData = create_info->pUserData;
673
674 VkFlags local_severity = 0;
675 VkFlags local_type = 0;
676 DebugReportFlagsToAnnotFlags(create_info->flags, true, &local_severity, &local_type);
677 debug_data->active_severities |= local_severity;
678 debug_data->active_types |= local_type;
679 if (default_callback) {
680 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
681 } else {
682 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600683 }
684
Mark Young6ba8abe2017-11-09 10:37:04 -0700685 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 -0600686 "DebugReport", "Added callback", kVUIDUndefined);
Mark Young6ba8abe2017-11-09 10:37:04 -0700687 return VK_SUCCESS;
688}
689
690static inline PFN_vkVoidFunction debug_utils_get_instance_proc_addr(debug_report_data *debug_data, const char *func_name) {
691 if (!debug_data) {
692 return NULL;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600693 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700694 if (debug_data->g_DEBUG_REPORT) {
695 if (!strcmp(func_name, "vkCreateDebugReportCallbackEXT")) {
696 return (PFN_vkVoidFunction)vkCreateDebugReportCallbackEXT;
697 }
698 if (!strcmp(func_name, "vkDestroyDebugReportCallbackEXT")) {
699 return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT;
700 }
701 if (!strcmp(func_name, "vkDebugReportMessageEXT")) {
702 return (PFN_vkVoidFunction)vkDebugReportMessageEXT;
703 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600704 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700705 if (debug_data->g_DEBUG_UTILS) {
706 if (!strcmp(func_name, "vkCreateDebugUtilsMessengerEXT")) {
707 return (PFN_vkVoidFunction)vkCreateDebugUtilsMessengerEXT;
708 }
709 if (!strcmp(func_name, "vkDestroyDebugUtilsMessengerEXT")) {
710 return (PFN_vkVoidFunction)vkDestroyDebugUtilsMessengerEXT;
711 }
712 if (!strcmp(func_name, "vkSubmitDebugUtilsMessageEXT")) {
713 return (PFN_vkVoidFunction)vkSubmitDebugUtilsMessageEXT;
714 }
Courtney Goeltzenleuchter822e8d72015-11-30 15:28:25 -0700715 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600716 return NULL;
717}
718
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600719// This utility (called at vkCreateInstance() time), looks at a pNext chain.
720// It counts any VkDebugReportCallbackCreateInfoEXT structs that it finds. It
721// then allocates an array that can hold that many structs, as well as that
722// many VkDebugReportCallbackEXT handles. It then copies each
723// VkDebugReportCallbackCreateInfoEXT, and initializes each handle.
Mark Young6ba8abe2017-11-09 10:37:04 -0700724static inline VkResult layer_copy_tmp_report_callbacks(const void *pChain, uint32_t *num_callbacks,
725 VkDebugReportCallbackCreateInfoEXT **infos,
726 VkDebugReportCallbackEXT **callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600727 uint32_t n = *num_callbacks = 0;
728
729 const void *pNext = pChain;
730 while (pNext) {
731 // 1st, count the number VkDebugReportCallbackCreateInfoEXT:
732 if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
733 n++;
734 }
735 pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext;
736 }
737 if (n == 0) {
738 return VK_SUCCESS;
739 }
740
741 // 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT:
742 VkDebugReportCallbackCreateInfoEXT *pInfos = *infos =
743 ((VkDebugReportCallbackCreateInfoEXT *)malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT)));
744 if (!pInfos) {
745 return VK_ERROR_OUT_OF_HOST_MEMORY;
746 }
747 // 3rd, allocate memory for a unique handle for each callback:
748 VkDebugReportCallbackEXT *pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)malloc(n * sizeof(VkDebugReportCallbackEXT)));
749 if (!pCallbacks) {
750 free(pInfos);
751 return VK_ERROR_OUT_OF_HOST_MEMORY;
752 }
753 // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by
754 // vkDestroyInstance, and assign a unique handle to each callback (just
755 // use the address of the copied VkDebugReportCallbackCreateInfoEXT):
756 pNext = pChain;
757 while (pNext) {
758 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
759 memcpy(pInfos, pNext, sizeof(VkDebugReportCallbackCreateInfoEXT));
760 *pCallbacks++ = (VkDebugReportCallbackEXT)pInfos++;
761 }
762 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
763 }
764
765 *num_callbacks = n;
766 return VK_SUCCESS;
767}
768
Mark Young6ba8abe2017-11-09 10:37:04 -0700769// This utility frees the arrays allocated by layer_copy_tmp_report_callbacks()
770static inline void layer_free_tmp_report_callbacks(VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600771 free(infos);
772 free(callbacks);
773}
774
775// This utility enables all of the VkDebugReportCallbackCreateInfoEXT structs
Mark Young6ba8abe2017-11-09 10:37:04 -0700776// that were copied by layer_copy_tmp_report_callbacks()
777static inline VkResult layer_enable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
778 VkDebugReportCallbackCreateInfoEXT *infos,
779 VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600780 VkResult rtn = VK_SUCCESS;
781 for (uint32_t i = 0; i < num_callbacks; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700782 rtn = layer_create_report_callback(debug_data, false, &infos[i], NULL, &callbacks[i]);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600783 if (rtn != VK_SUCCESS) {
784 for (uint32_t j = 0; j < i; j++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700785 layer_destroy_report_callback(debug_data, callbacks[j], NULL);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600786 }
787 return rtn;
788 }
789 }
790 return rtn;
791}
792
793// This utility disables all of the VkDebugReportCallbackCreateInfoEXT structs
Mark Young6ba8abe2017-11-09 10:37:04 -0700794// that were copied by layer_copy_tmp_report_callbacks()
795static inline void layer_disable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
796 VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600797 for (uint32_t i = 0; i < num_callbacks; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700798 layer_destroy_report_callback(debug_data, callbacks[i], NULL);
799 }
800}
801
802// This utility (called at vkCreateInstance() time), looks at a pNext chain.
803// It counts any VkDebugUtilsMessengerCreateInfoEXT structs that it finds. It
804// then allocates an array that can hold that many structs, as well as that
805// many VkDebugUtilsMessengerEXT handles. It then copies each
806// VkDebugUtilsMessengerCreateInfoEXT, and initializes each handle.
Mark Young8504ba62018-03-21 13:35:34 -0600807static inline VkResult layer_copy_tmp_debug_messengers(const void *pChain, uint32_t *num_messengers,
808 VkDebugUtilsMessengerCreateInfoEXT **infos,
809 VkDebugUtilsMessengerEXT **messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700810 uint32_t n = *num_messengers = 0;
811
812 const void *pNext = pChain;
813 while (pNext) {
814 // 1st, count the number VkDebugUtilsMessengerCreateInfoEXT:
815 if (((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
816 n++;
817 }
818 pNext = (void *)((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->pNext;
819 }
820 if (n == 0) {
821 return VK_SUCCESS;
822 }
823
824 // 2nd, allocate memory for each VkDebugUtilsMessengerCreateInfoEXT:
825 VkDebugUtilsMessengerCreateInfoEXT *pInfos = *infos =
826 ((VkDebugUtilsMessengerCreateInfoEXT *)malloc(n * sizeof(VkDebugUtilsMessengerCreateInfoEXT)));
827 if (!pInfos) {
828 return VK_ERROR_OUT_OF_HOST_MEMORY;
829 }
830 // 3rd, allocate memory for a unique handle for each messenger:
831 VkDebugUtilsMessengerEXT *pMessengers = *messengers =
832 ((VkDebugUtilsMessengerEXT *)malloc(n * sizeof(VkDebugUtilsMessengerEXT)));
833 if (!pMessengers) {
834 free(pInfos);
835 return VK_ERROR_OUT_OF_HOST_MEMORY;
836 }
837 // 4th, copy each VkDebugUtilsMessengerCreateInfoEXT for use by
838 // vkDestroyInstance, and assign a unique handle to each callback (just
839 // use the address of the copied VkDebugUtilsMessengerCreateInfoEXT):
840 pNext = pChain;
841 while (pNext) {
842 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
843 memcpy(pInfos, pNext, sizeof(VkDebugUtilsMessengerCreateInfoEXT));
844 *pMessengers++ = (VkDebugUtilsMessengerEXT)pInfos++;
845 }
846 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
847 }
848
849 *num_messengers = n;
850 return VK_SUCCESS;
851}
852
853// This utility frees the arrays allocated by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600854static inline void layer_free_tmp_debug_messengers(VkDebugUtilsMessengerCreateInfoEXT *infos,
855 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700856 free(infos);
857 free(messengers);
858}
859
860// This utility enables all of the VkDebugUtilsMessengerCreateInfoEXT structs
861// that were copied by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600862static inline VkResult layer_enable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
863 VkDebugUtilsMessengerCreateInfoEXT *infos,
864 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700865 VkResult rtn = VK_SUCCESS;
866 for (uint32_t i = 0; i < num_messengers; i++) {
867 rtn = layer_create_messenger_callback(debug_data, false, &infos[i], NULL, &messengers[i]);
868 if (rtn != VK_SUCCESS) {
869 for (uint32_t j = 0; j < i; j++) {
870 layer_destroy_messenger_callback(debug_data, messengers[j], NULL);
871 }
872 return rtn;
873 }
874 }
875 return rtn;
876}
877
878// This utility disables all of the VkDebugUtilsMessengerCreateInfoEXT structs
879// that were copied by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600880static inline void layer_disable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
881 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700882 for (uint32_t i = 0; i < num_messengers; i++) {
883 layer_destroy_messenger_callback(debug_data, messengers[i], NULL);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600884 }
885}
886
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600887// Checks if the message will get logged.
888// Allows layer to defer collecting & formating data if the
889// message will be discarded.
Mark Young6ba8abe2017-11-09 10:37:04 -0700890static inline bool will_log_msg(debug_report_data *debug_data, VkFlags msg_flags) {
891 VkFlags local_severity = 0;
892 VkFlags local_type = 0;
893 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
894 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600895 // Message is not wanted
Courtney Goeltzenleuchter6a564a12015-09-18 16:30:24 -0600896 return false;
897 }
898
899 return true;
900}
John Zulauf6664e272018-01-17 11:00:22 -0700901#ifndef WIN32
Mark Lobodzinski1bcbdf92018-02-07 10:00:22 -0700902static inline int string_sprintf(std::string *output, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
John Zulauf6664e272018-01-17 11:00:22 -0700903#endif
Mark Lobodzinski1bcbdf92018-02-07 10:00:22 -0700904static inline int string_sprintf(std::string *output, const char *fmt, ...) {
John Zulauf6664e272018-01-17 11:00:22 -0700905 std::string &formatted = *output;
906 va_list argptr;
907 va_start(argptr, fmt);
908 int reserve = vsnprintf(nullptr, 0, fmt, argptr);
909 va_end(argptr);
John Zulaufdeaa0132018-12-12 16:22:30 -0700910 formatted.reserve(reserve + 1); // Set the storage length long enough to hold the output + null
911 formatted.resize(reserve); // Set the *logical* length to be what vsprintf will write
John Zulauf6664e272018-01-17 11:00:22 -0700912 va_start(argptr, fmt);
913 int result = vsnprintf((char *)formatted.data(), formatted.capacity(), fmt, argptr);
914 va_end(argptr);
915 assert(result == reserve);
John Zulaufdeaa0132018-12-12 16:22:30 -0700916 assert((formatted.size() == strlen(formatted.c_str())));
John Zulauf6664e272018-01-17 11:00:22 -0700917 return result;
918}
Courtney Goeltzenleuchter6a564a12015-09-18 16:30:24 -0600919
Chris Forbes8a25bce2016-03-24 12:06:35 +1300920#ifdef WIN32
921static inline int vasprintf(char **strp, char const *fmt, va_list ap) {
922 *strp = nullptr;
923 int size = _vscprintf(fmt, ap);
924 if (size >= 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700925 *strp = (char *)malloc(size + 1);
Chris Forbes8a25bce2016-03-24 12:06:35 +1300926 if (!*strp) {
927 return -1;
928 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700929 _vsnprintf(*strp, size + 1, fmt, ap);
Chris Forbes8a25bce2016-03-24 12:06:35 +1300930 }
931 return size;
932}
933#endif
934
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700935// Output log message via DEBUG_REPORT. Takes format and variable arg list so that output string is only computed if a message
936// needs to be logged
Michael Lentine010f4692015-11-03 16:19:46 -0800937#ifndef WIN32
Mark Young6ba8abe2017-11-09 10:37:04 -0700938static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700939 uint64_t src_object, std::string vuid_text, const char *format, ...)
940 __attribute__((format(printf, 6, 7)));
Michael Lentine010f4692015-11-03 16:19:46 -0800941#endif
Mark Young6ba8abe2017-11-09 10:37:04 -0700942static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700943 uint64_t src_object, std::string vuid_text, const char *format, ...) {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700944 if (!debug_data) return false;
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700945 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700946 VkFlags local_severity = 0;
947 VkFlags local_type = 0;
948 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
949 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
950 // Message is not wanted
951 return false;
952 }
953
954 va_list argptr;
955 va_start(argptr, format);
956 char *str;
957 if (-1 == vasprintf(&str, format, argptr)) {
958 // On failure, glibc vasprintf leaves str undefined
959 str = nullptr;
960 }
961 va_end(argptr);
962
Dave Houlton407df732018-08-06 17:58:24 -0600963 std::string str_plus_spec_text(str ? str : "Allocation failure");
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700964
Dave Houlton407df732018-08-06 17:58:24 -0600965 // Append the spec error text to the error message, unless it's an UNASSIGNED or UNDEFINED vuid
966 if ((vuid_text.find("UNASSIGNED-") == std::string::npos) && (vuid_text.find(kVUIDUndefined) == std::string::npos)) {
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600967 // Linear search makes no assumptions about the layout of the string table
968 // This is not fast, but it does not need to be at this point in the error reporting path
969 uint32_t num_vuids = sizeof(vuid_spec_text) / sizeof(vuid_spec_text_pair);
970 const char *spec_text = nullptr;
971 for (uint32_t i = 0; i < num_vuids; i++) {
972 if (0 == strcmp(vuid_text.c_str(), vuid_spec_text[i].vuid)) {
973 spec_text = vuid_spec_text[i].spec_text;
974 break;
975 }
976 }
977
978 if (nullptr == spec_text) {
Dave Houlton407df732018-08-06 17:58:24 -0600979 // If this happens, you've hit a VUID string that isn't defined in the spec's json file
980 // Try running 'vk_validation_stats -c' to look for invalid VUID strings in the repo code
981 assert(0);
982 } else {
983 str_plus_spec_text += " The Vulkan spec states: ";
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600984 str_plus_spec_text += spec_text;
Dave Houlton407df732018-08-06 17:58:24 -0600985 }
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700986 }
987
Dave Houlton8e9f6542018-05-18 12:18:22 -0600988 // Append layer prefix with VUID string, pass in recovered legacy numerical VUID
Dave Houlton407df732018-08-06 17:58:24 -0600989 bool result = debug_log_msg(debug_data, msg_flags, object_type, src_object, 0, "Validation", str_plus_spec_text.c_str(),
990 vuid_text.c_str());
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700991
992 free(str);
993 return result;
994}
995
Mark Young6ba8abe2017-11-09 10:37:04 -0700996static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_log_callback(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
997 uint64_t src_object, size_t location, int32_t msg_code,
998 const char *layer_prefix, const char *message, void *user_data) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -0700999 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -07001000 char msg_flag_string[30];
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -06001001
Mark Young6ba8abe2017-11-09 10:37:04 -07001002 PrintMessageFlags(msg_flags, msg_flag_string);
Courtney Goeltzenleuchter2f25bb42015-06-14 11:29:24 -06001003
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001004 msg_buffer << layer_prefix << "(" << msg_flag_string << "): msg_code: " << msg_code << ": " << message << "\n";
1005 const std::string tmp = msg_buffer.str();
1006 const char *cstr = tmp.c_str();
1007
1008 fprintf((FILE *)user_data, "%s", cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -07001009 fflush((FILE *)user_data);
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -06001010
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001011#if defined __ANDROID__
1012 LOGCONSOLE("%s", cstr);
1013#endif
1014
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -06001015 return false;
Courtney Goeltzenleuchter2f25bb42015-06-14 11:29:24 -06001016}
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001017
Mark Young6ba8abe2017-11-09 10:37:04 -07001018static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_win32_debug_output_msg(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
1019 uint64_t src_object, size_t location, int32_t msg_code,
1020 const char *layer_prefix, const char *message,
1021 void *user_data) {
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001022#ifdef WIN32
Mark Young6ba8abe2017-11-09 10:37:04 -07001023 char msg_flag_string[30];
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001024 char buf[2048];
1025
Mark Young6ba8abe2017-11-09 10:37:04 -07001026 PrintMessageFlags(msg_flags, msg_flag_string);
Mark Lobodzinskib1fd9d12018-03-30 14:26:00 -06001027 _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 -06001028
1029 OutputDebugString(buf);
1030#endif
1031
1032 return false;
1033}
1034
Mark Young6ba8abe2017-11-09 10:37:04 -07001035static inline VKAPI_ATTR VkBool32 VKAPI_CALL DebugBreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT obj_type,
1036 uint64_t src_object, size_t location, int32_t msg_code,
1037 const char *layer_prefix, const char *message, void *user_data) {
Mark Lobodzinskic9d81652017-08-10 11:01:17 -06001038#ifdef WIN32
1039 DebugBreak();
1040#else
1041 raise(SIGTRAP);
1042#endif
1043
1044 return false;
1045}
1046
Mark Young6ba8abe2017-11-09 10:37:04 -07001047static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_log_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
1048 VkDebugUtilsMessageTypeFlagsEXT message_type,
1049 const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
1050 void *user_data) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001051 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -07001052 char msg_severity[30];
1053 char msg_type[30];
1054
1055 PrintMessageSeverity(message_severity, msg_severity);
1056 PrintMessageType(message_type, msg_type);
1057
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001058 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
1059 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
1060 msg_buffer << " Objects: " << callback_data->objectCount << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001061 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001062 msg_buffer << " [" << obj << "] " << std::hex << std::showbase
1063 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
1064 << callback_data->pObjects[obj].objectType
1065 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
1066 << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001067 }
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001068 const std::string tmp = msg_buffer.str();
1069 const char *cstr = tmp.c_str();
1070 fprintf((FILE *)user_data, "%s", cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -07001071 fflush((FILE *)user_data);
1072
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001073#if defined __ANDROID__
1074 LOGCONSOLE("%s", cstr);
1075#endif
1076
Mark Young6ba8abe2017-11-09 10:37:04 -07001077 return false;
Petr Krause9388f62017-05-13 20:53:12 +02001078}
1079
Mark Young6ba8abe2017-11-09 10:37:04 -07001080static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_win32_debug_output_msg(
1081 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type,
1082 const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data) {
1083#ifdef WIN32
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001084 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -07001085 char msg_severity[30];
1086 char msg_type[30];
Mark Lobodzinski863d5de2017-05-22 10:10:07 -06001087
Mark Young6ba8abe2017-11-09 10:37:04 -07001088 PrintMessageSeverity(message_severity, msg_severity);
1089 PrintMessageType(message_type, msg_type);
1090
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001091 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
1092 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
1093 msg_buffer << " Objects: " << callback_data->objectCount << "\n";
1094
Mark Young8504ba62018-03-21 13:35:34 -06001095 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001096 msg_buffer << " [" << obj << "] " << std::hex << std::showbase
1097 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
1098 << callback_data->pObjects[obj].objectType
1099 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
1100 << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001101 }
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001102 const std::string tmp = msg_buffer.str();
1103 const char *cstr = tmp.c_str();
1104 OutputDebugString(cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -07001105#endif
1106
1107 return false;
1108}
1109
1110// This utility converts from the VkDebugUtilsLabelEXT structure into the logging version of the structure.
1111// In the logging version, we only record what we absolutely need to convey back to the callbacks.
1112static inline void InsertLabelIntoLog(const VkDebugUtilsLabelEXT *utils_label, std::vector<LoggingLabelData> &log_vector) {
1113 LoggingLabelData log_label_data = {};
1114 log_label_data.name = utils_label->pLabelName;
1115 log_label_data.color[0] = utils_label->color[0];
1116 log_label_data.color[1] = utils_label->color[1];
1117 log_label_data.color[2] = utils_label->color[2];
1118 log_label_data.color[3] = utils_label->color[3];
1119 log_vector.push_back(log_label_data);
1120}
1121
Mark Young8504ba62018-03-21 13:35:34 -06001122static inline void BeginQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
1123 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001124 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001125 if (nullptr != label_info && nullptr != label_info->pLabelName) {
Mark Lobodzinski12813302019-02-07 15:03:06 -07001126 auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
1127 if (label_iter == report_data->debugUtilsQueueLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001128 std::vector<LoggingLabelData> new_queue_labels;
1129 InsertLabelIntoLog(label_info, new_queue_labels);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001130 report_data->debugUtilsQueueLabels.insert({queue, new_queue_labels});
Mark Young6ba8abe2017-11-09 10:37:04 -07001131 } else {
1132 // If the last thing was a label insert, we need to pop it off of the label vector before any
1133 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1134 // temporary location that exists until the next operation occurs. In this case, a new
1135 // "vkQueueBeginDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1136 if (report_data->queueLabelHasInsert) {
1137 report_data->queueLabelHasInsert = false;
1138 label_iter->second.pop_back();
1139 }
1140 InsertLabelIntoLog(label_info, label_iter->second);
1141 }
1142 }
1143}
1144
Mark Young8504ba62018-03-21 13:35:34 -06001145static inline void EndQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001146 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001147 auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
1148 if (label_iter != report_data->debugUtilsQueueLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001149 // If the last thing was a label insert, we need to pop it off of the label vector before any
1150 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1151 // temporary location that exists until the next operation occurs. In this case, a
1152 // "vkQueueEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
1153 if (report_data->queueLabelHasInsert) {
1154 report_data->queueLabelHasInsert = false;
1155 label_iter->second.pop_back();
1156 }
1157 // Now pop the normal item
1158 label_iter->second.pop_back();
1159 }
1160}
1161
Mark Young8504ba62018-03-21 13:35:34 -06001162static inline void InsertQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
1163 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001164 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001165 if (nullptr != label_info && nullptr != label_info->pLabelName) {
Mark Lobodzinski12813302019-02-07 15:03:06 -07001166 auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
1167 if (label_iter == report_data->debugUtilsQueueLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001168 std::vector<LoggingLabelData> new_queue_labels;
1169 InsertLabelIntoLog(label_info, new_queue_labels);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001170 report_data->debugUtilsQueueLabels.insert({queue, new_queue_labels});
Mark Young6ba8abe2017-11-09 10:37:04 -07001171 } else {
1172 // If the last thing was a label insert, we need to pop it off of the label vector before any
1173 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1174 // temporary location that exists until the next operation occurs. In this case, a new
1175 // "vkQueueInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1176 if (report_data->queueLabelHasInsert) {
1177 label_iter->second.pop_back();
1178 }
1179 // Insert this new label and mark it as one that has been "inserted" so we can remove it on
1180 // the next queue label operation.
1181 InsertLabelIntoLog(label_info, label_iter->second);
1182 report_data->queueLabelHasInsert = true;
1183 }
1184 }
1185}
1186
Mark Young8504ba62018-03-21 13:35:34 -06001187static inline void BeginCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1188 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001189 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001190 if (nullptr != label_info && nullptr != label_info->pLabelName) {
Mark Lobodzinski12813302019-02-07 15:03:06 -07001191 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
1192 if (label_iter == report_data->debugUtilsCmdBufLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001193 std::vector<LoggingLabelData> new_cmdbuf_labels;
1194 InsertLabelIntoLog(label_info, new_cmdbuf_labels);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001195 report_data->debugUtilsCmdBufLabels.insert({command_buffer, new_cmdbuf_labels});
Mark Young6ba8abe2017-11-09 10:37:04 -07001196 } else {
1197 // If the last thing was a label insert, we need to pop it off of the label vector before any
1198 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1199 // temporary location that exists until the next operation occurs. In this case, a
1200 // "vkCmdBeginDebugUtilsLabelEXT" has occurred erasing the inserted label.
1201 if (report_data->cmdBufLabelHasInsert) {
1202 report_data->cmdBufLabelHasInsert = false;
1203 label_iter->second.pop_back();
1204 }
1205 InsertLabelIntoLog(label_info, label_iter->second);
1206 }
1207 }
1208}
1209
Mark Young8504ba62018-03-21 13:35:34 -06001210static inline void EndCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001211 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001212 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
1213 if (label_iter != report_data->debugUtilsCmdBufLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001214 // If the last thing was a label insert, we need to pop it off of the label vector before any
1215 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1216 // temporary location that exists until the next operation occurs. In this case, a
1217 // "vkCmdEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
1218 if (report_data->cmdBufLabelHasInsert) {
1219 report_data->cmdBufLabelHasInsert = false;
1220 label_iter->second.pop_back();
1221 }
Shahbaz Youssefi10b94a62019-01-09 23:00:15 -05001222 // Guard against unbalanced markers.
1223 if (label_iter->second.size() > 0) {
1224 // Now pop the normal item
1225 label_iter->second.pop_back();
1226 }
Mark Young6ba8abe2017-11-09 10:37:04 -07001227 }
1228}
1229
Mark Young8504ba62018-03-21 13:35:34 -06001230static inline void InsertCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1231 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001232 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001233 if (nullptr != label_info && nullptr != label_info->pLabelName) {
Mark Lobodzinski12813302019-02-07 15:03:06 -07001234 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
1235 if (label_iter == report_data->debugUtilsCmdBufLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001236 std::vector<LoggingLabelData> new_cmdbuf_labels;
1237 InsertLabelIntoLog(label_info, new_cmdbuf_labels);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001238 report_data->debugUtilsCmdBufLabels.insert({command_buffer, new_cmdbuf_labels});
Mark Young6ba8abe2017-11-09 10:37:04 -07001239 } else {
1240 // If the last thing was a label insert, we need to pop it off of the label vector before any
1241 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1242 // temporary location that exists until the next operation occurs. In this case, a new
1243 // "vkCmdInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1244 if (report_data->cmdBufLabelHasInsert) {
1245 label_iter->second.pop_back();
1246 }
1247 // Insert this new label and mark it as one that has been "inserted" so we can remove it on
1248 // the next command buffer label operation.
1249 InsertLabelIntoLog(label_info, label_iter->second);
1250 report_data->cmdBufLabelHasInsert = true;
1251 }
1252 }
1253}
Mark Lobodzinski863d5de2017-05-22 10:10:07 -06001254
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001255#endif // LAYER_LOGGING_H