blob: 8c98c18cd37b3ce4559015f6133cee02e2cb8030 [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;
Mark Lobodzinski5d98ba12019-03-25 13:35:01 -0600357 std::string object_label = {};
Mark Young6ba8abe2017-11-09 10:37:04 -0700358
359 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
360 callback_data.pNext = NULL;
361 callback_data.flags = 0;
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700362 callback_data.pMessageIdName = text_vuid;
Dave Houlton407df732018-08-06 17:58:24 -0600363 callback_data.messageIdNumber = 0; // deprecated, validation layers use only the pMessageIdName
Mark Young6ba8abe2017-11-09 10:37:04 -0700364 callback_data.pMessage = message;
365 callback_data.queueLabelCount = 0;
366 callback_data.pQueueLabels = NULL;
367 callback_data.cmdBufLabelCount = 0;
368 callback_data.pCmdBufLabels = NULL;
369 callback_data.objectCount = 1;
370 callback_data.pObjects = &object_name_info;
371
372 VkDebugUtilsLabelEXT *queue_labels = nullptr;
373 VkDebugUtilsLabelEXT *cmd_buf_labels = nullptr;
374 std::string new_debug_report_message = "";
375 std::ostringstream oss;
Mark Young6ba8abe2017-11-09 10:37:04 -0700376
377 if (0 != src_object) {
Mark Young8504ba62018-03-21 13:35:34 -0600378 oss << "Object: 0x" << std::hex << src_object;
Mark Young6ba8abe2017-11-09 10:37:04 -0700379 // If this is a queue, add any queue labels to the callback data.
380 if (VK_OBJECT_TYPE_QUEUE == object_name_info.objectType) {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700381 auto label_iter = debug_data->debugUtilsQueueLabels.find(reinterpret_cast<VkQueue>(src_object));
382 if (label_iter != debug_data->debugUtilsQueueLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700383 queue_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
384 if (nullptr != queue_labels) {
385 // Record the labels, but record them in reverse order since we want the
386 // most recent at the top.
387 uint32_t label_size = static_cast<uint32_t>(label_iter->second.size());
388 uint32_t last_index = label_size - 1;
389 for (uint32_t label = 0; label < label_size; ++label) {
390 queue_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
391 queue_labels[last_index - label].pNext = nullptr;
392 queue_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
393 queue_labels[last_index - label].color[0] = label_iter->second[label].color[0];
394 queue_labels[last_index - label].color[1] = label_iter->second[label].color[1];
395 queue_labels[last_index - label].color[2] = label_iter->second[label].color[2];
396 queue_labels[last_index - label].color[3] = label_iter->second[label].color[3];
397 }
398 callback_data.queueLabelCount = label_size;
399 callback_data.pQueueLabels = queue_labels;
400 }
401 }
402 // If this is a command buffer, add any command buffer labels to the callback data.
403 } else if (VK_OBJECT_TYPE_COMMAND_BUFFER == object_name_info.objectType) {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700404 auto label_iter = debug_data->debugUtilsCmdBufLabels.find(reinterpret_cast<VkCommandBuffer>(src_object));
405 if (label_iter != debug_data->debugUtilsCmdBufLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700406 cmd_buf_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
407 if (nullptr != cmd_buf_labels) {
408 // Record the labels, but record them in reverse order since we want the
409 // most recent at the top.
410 uint32_t label_size = static_cast<uint32_t>(label_iter->second.size());
411 uint32_t last_index = label_size - 1;
412 for (uint32_t label = 0; label < label_size; ++label) {
413 cmd_buf_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
414 cmd_buf_labels[last_index - label].pNext = nullptr;
415 cmd_buf_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
416 cmd_buf_labels[last_index - label].color[0] = label_iter->second[label].color[0];
417 cmd_buf_labels[last_index - label].color[1] = label_iter->second[label].color[1];
418 cmd_buf_labels[last_index - label].color[2] = label_iter->second[label].color[2];
419 cmd_buf_labels[last_index - label].color[3] = label_iter->second[label].color[3];
420 }
421 callback_data.cmdBufLabelCount = label_size;
422 callback_data.pCmdBufLabels = cmd_buf_labels;
423 }
424 }
425 }
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700426
Mark Young6ba8abe2017-11-09 10:37:04 -0700427 // Look for any debug utils or marker names to use for this object
Mark Lobodzinski5d98ba12019-03-25 13:35:01 -0600428 object_label = debug_data->DebugReportGetUtilsObjectName(src_object);
429 if (object_label.empty()) {
430 object_label = debug_data->DebugReportGetMarkerObjectName(src_object);
Mark Young6ba8abe2017-11-09 10:37:04 -0700431 }
Mark Lobodzinski5d98ba12019-03-25 13:35:01 -0600432 if (!object_label.empty()) {
433 object_name_info.pObjectName = object_label.c_str();
434 oss << " (Name = " << object_label << " : Type = ";
Mark Young8504ba62018-03-21 13:35:34 -0600435 } else {
436 oss << " (Type = ";
Mark Young6ba8abe2017-11-09 10:37:04 -0700437 }
Mark Young8504ba62018-03-21 13:35:34 -0600438 oss << std::to_string(object_type) << ")";
439 } else {
440 oss << "Object: VK_NULL_HANDLE (Type = " << std::to_string(object_type) << ")";
Mark Young6ba8abe2017-11-09 10:37:04 -0700441 }
442 new_debug_report_message += oss.str();
443 new_debug_report_message += " | ";
444 new_debug_report_message += message;
445
446 while (layer_dbg_node) {
Mark Young8504ba62018-03-21 13:35:34 -0600447 // If the app uses the VK_EXT_debug_report extension, call all of those registered callbacks.
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700448 if (!layer_dbg_node->is_messenger && (layer_dbg_node->report.msgFlags & msg_flags)) {
449 if (text_vuid != nullptr) {
450 // If a text vuid is supplied for the old debug report extension, prepend it to the message string
451 new_debug_report_message.insert(0, " ] ");
452 new_debug_report_message.insert(0, text_vuid);
453 new_debug_report_message.insert(0, " [ ");
454 }
455
Dave Houlton407df732018-08-06 17:58:24 -0600456 if (layer_dbg_node->report.pfnMsgCallback(msg_flags, object_type, src_object, location, 0, layer_prefix,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700457 new_debug_report_message.c_str(), layer_dbg_node->pUserData)) {
458 bail = true;
459 }
Mark Young8504ba62018-03-21 13:35:34 -0600460 // If the app uses the VK_EXT_debug_utils extension, call all of those registered callbacks.
Mark Young6ba8abe2017-11-09 10:37:04 -0700461 } else if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & severity) &&
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700462 (layer_dbg_node->messenger.messageType & types)) {
463 if (layer_dbg_node->messenger.pfnUserCallback(static_cast<VkDebugUtilsMessageSeverityFlagBitsEXT>(severity), types,
464 &callback_data, layer_dbg_node->pUserData)) {
465 bail = true;
466 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700467 }
468 layer_dbg_node = layer_dbg_node->pNext;
469 }
470
471 if (nullptr != queue_labels) {
472 delete[] queue_labels;
473 }
474 if (nullptr != cmd_buf_labels) {
475 delete[] cmd_buf_labels;
476 }
477
478 return bail;
479}
480
481static inline void DebugAnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,
482 VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags) {
483 *dr_flags = 0;
484
485 if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) {
486 *dr_flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
487 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) {
488 if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) {
489 *dr_flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
490 } else {
491 *dr_flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
492 }
493 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) {
494 *dr_flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
495 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) {
496 *dr_flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
497 }
498}
499
500static inline bool debug_messenger_log_msg(const debug_report_data *debug_data,
501 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
502 VkDebugUtilsMessageTypeFlagsEXT message_type,
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700503 VkDebugUtilsMessengerCallbackDataEXT *callback_data,
504 const VkDebugUtilsMessengerEXT *messenger) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700505 bool bail = false;
506 VkLayerDbgFunctionNode *layer_dbg_node = NULL;
507
508 if (debug_data->debug_callback_list != NULL) {
509 layer_dbg_node = debug_data->debug_callback_list;
510 } else {
511 layer_dbg_node = debug_data->default_debug_callback_list;
512 }
513
514 VkDebugReportFlagsEXT object_flags = 0;
515
516 DebugAnnotFlagsToReportFlags(message_severity, message_type, &object_flags);
517
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700518 VkDebugUtilsObjectNameInfoEXT object_name_info;
519 object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
520 object_name_info.pNext = NULL;
521 object_name_info.objectType = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT;
522 object_name_info.objectHandle = HandleToUint64(*messenger);
523 object_name_info.pObjectName = NULL;
524 callback_data->pObjects = &object_name_info;
525 callback_data->objectCount = 1;
526
Mark Young6ba8abe2017-11-09 10:37:04 -0700527 while (layer_dbg_node) {
528 if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & message_severity) &&
529 (layer_dbg_node->messenger.messageType & message_type)) {
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700530 std::string messenger_label = debug_data->DebugReportGetUtilsObjectName(object_name_info.objectHandle);
531 if (!messenger_label.empty()) {
532 object_name_info.pObjectName = messenger_label.c_str();
Mark Young6ba8abe2017-11-09 10:37:04 -0700533 }
534 if (layer_dbg_node->messenger.pfnUserCallback(message_severity, message_type, callback_data,
535 layer_dbg_node->pUserData)) {
536 bail = true;
537 }
538 } else if (!layer_dbg_node->is_messenger && layer_dbg_node->report.msgFlags & object_flags) {
John Zulauf536649b2018-05-01 13:28:27 -0600539 VkDebugReportObjectTypeEXT object_type = convertCoreObjectToDebugReportObject(callback_data->pObjects[0].objectType);
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700540 std::string marker_label = debug_data->DebugReportGetMarkerObjectName(object_name_info.objectHandle);
541 if (marker_label.empty()) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700542 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
543 callback_data->messageIdNumber, callback_data->pMessageIdName,
544 callback_data->pMessage, layer_dbg_node->pUserData)) {
Tony Barbour3431dac2017-06-19 16:50:37 -0600545 bail = true;
546 }
547 } else {
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700548 std::string newMsg = "SrcObject name = " + marker_label;
Tony Barbour3431dac2017-06-19 16:50:37 -0600549 newMsg.append(" ");
Mark Young6ba8abe2017-11-09 10:37:04 -0700550 newMsg.append(callback_data->pMessage);
551 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
552 callback_data->messageIdNumber, callback_data->pMessageIdName,
553 newMsg.c_str(), layer_dbg_node->pUserData)) {
Tony Barbour3431dac2017-06-19 16:50:37 -0600554 bail = true;
555 }
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -0600556 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600557 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700558 layer_dbg_node = layer_dbg_node->pNext;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600559 }
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -0600560
561 return bail;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600562}
563
Mark Young6ba8abe2017-11-09 10:37:04 -0700564static inline debug_report_data *debug_utils_create_instance(
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700565 VkLayerInstanceDispatchTable *table, VkInstance inst, uint32_t extension_count,
Mark Young6ba8abe2017-11-09 10:37:04 -0700566 const char *const *enabled_extensions) // layer or extension name to be enabled
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600567{
Mark Lobodzinski12813302019-02-07 15:03:06 -0700568 debug_report_data *debug_data = new debug_report_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600569 for (uint32_t i = 0; i < extension_count; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700570 if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600571 debug_data->g_DEBUG_REPORT = true;
Mark Young6ba8abe2017-11-09 10:37:04 -0700572 } else if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
573 debug_data->g_DEBUG_UTILS = true;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600574 }
575 }
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600576 return debug_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600577}
578
Mark Young6ba8abe2017-11-09 10:37:04 -0700579static inline void layer_debug_utils_destroy_instance(debug_report_data *debug_data) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600580 if (debug_data) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700581 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600582 RemoveAllMessageCallbacks(debug_data, &debug_data->default_debug_callback_list);
583 RemoveAllMessageCallbacks(debug_data, &debug_data->debug_callback_list);
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700584 lock.unlock();
Mark Lobodzinski12813302019-02-07 15:03:06 -0700585 delete (debug_data);
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600586 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600587}
588
Mark Young6ba8abe2017-11-09 10:37:04 -0700589static inline debug_report_data *layer_debug_utils_create_device(debug_report_data *instance_debug_data, VkDevice device) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600590 // DEBUG_REPORT shares data between Instance and Device,
591 // so just return instance's data pointer
Courtney Goeltzenleuchterb9f0bf32015-06-14 09:50:18 -0600592 return instance_debug_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600593}
594
Mark Young6ba8abe2017-11-09 10:37:04 -0700595static inline void layer_debug_utils_destroy_device(VkDevice device) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600596 // Nothing to do since we're using instance data record
597}
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600598
Mark Young6ba8abe2017-11-09 10:37:04 -0700599static inline void layer_destroy_messenger_callback(debug_report_data *debug_data, VkDebugUtilsMessengerEXT messenger,
600 const VkAllocationCallbacks *allocator) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700601 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -0700602 RemoveDebugUtilsMessenger(debug_data, &debug_data->debug_callback_list, messenger);
603 RemoveDebugUtilsMessenger(debug_data, &debug_data->default_debug_callback_list, messenger);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600604}
605
Mark Young6ba8abe2017-11-09 10:37:04 -0700606static inline VkResult layer_create_messenger_callback(debug_report_data *debug_data, bool default_callback,
607 const VkDebugUtilsMessengerCreateInfoEXT *create_info,
608 const VkAllocationCallbacks *allocator,
609 VkDebugUtilsMessengerEXT *messenger) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700610 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700611 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700612 if (!pNewDbgFuncNode) return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young6ba8abe2017-11-09 10:37:04 -0700613 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
614 pNewDbgFuncNode->is_messenger = true;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600615
Tobin Ehliseb7715d2015-09-21 09:36:47 -0600616 // Handle of 0 is logging_callback so use allocated Node address as unique handle
Mark Young6ba8abe2017-11-09 10:37:04 -0700617 if (!(*messenger)) *messenger = (VkDebugUtilsMessengerEXT)pNewDbgFuncNode;
618 pNewDbgFuncNode->messenger.messenger = *messenger;
619 pNewDbgFuncNode->messenger.pfnUserCallback = create_info->pfnUserCallback;
620 pNewDbgFuncNode->messenger.messageSeverity = create_info->messageSeverity;
621 pNewDbgFuncNode->messenger.messageType = create_info->messageType;
622 pNewDbgFuncNode->pUserData = create_info->pUserData;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600623
Mark Young6ba8abe2017-11-09 10:37:04 -0700624 debug_data->active_severities |= create_info->messageSeverity;
625 debug_data->active_types |= create_info->messageType;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600626 if (default_callback) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700627 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600628 } else {
Mark Young6ba8abe2017-11-09 10:37:04 -0700629 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600630 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600631
Mark Young6ba8abe2017-11-09 10:37:04 -0700632 VkDebugUtilsMessengerCallbackDataEXT callback_data = {};
Mark Young6ba8abe2017-11-09 10:37:04 -0700633 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
634 callback_data.pNext = NULL;
635 callback_data.flags = 0;
636 callback_data.pMessageIdName = "Layer Internal Message";
637 callback_data.messageIdNumber = 0;
638 callback_data.pMessage = "Added messenger";
639 callback_data.queueLabelCount = 0;
640 callback_data.pQueueLabels = NULL;
641 callback_data.cmdBufLabelCount = 0;
642 callback_data.pCmdBufLabels = NULL;
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700643 callback_data.objectCount = 0;
644 callback_data.pObjects = NULL;
Mark Young6ba8abe2017-11-09 10:37:04 -0700645 debug_messenger_log_msg(debug_data, VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700646 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, &callback_data, messenger);
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600647 return VK_SUCCESS;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600648}
649
Mark Young6ba8abe2017-11-09 10:37:04 -0700650static inline void layer_destroy_report_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback,
651 const VkAllocationCallbacks *allocator) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700652 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -0700653 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->debug_callback_list, callback);
654 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->default_debug_callback_list, callback);
655}
656
657static inline VkResult layer_create_report_callback(debug_report_data *debug_data, bool default_callback,
658 const VkDebugReportCallbackCreateInfoEXT *create_info,
659 const VkAllocationCallbacks *allocator, VkDebugReportCallbackEXT *callback) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700660 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -0700661 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
662 if (!pNewDbgFuncNode) {
663 return VK_ERROR_OUT_OF_HOST_MEMORY;
664 }
665 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
666 pNewDbgFuncNode->is_messenger = false;
667
668 // Handle of 0 is logging_callback so use allocated Node address as unique handle
669 if (!(*callback)) *callback = (VkDebugReportCallbackEXT)pNewDbgFuncNode;
670 pNewDbgFuncNode->report.msgCallback = *callback;
671 pNewDbgFuncNode->report.pfnMsgCallback = create_info->pfnCallback;
672 pNewDbgFuncNode->report.msgFlags = create_info->flags;
673 pNewDbgFuncNode->pUserData = create_info->pUserData;
674
675 VkFlags local_severity = 0;
676 VkFlags local_type = 0;
677 DebugReportFlagsToAnnotFlags(create_info->flags, true, &local_severity, &local_type);
678 debug_data->active_severities |= local_severity;
679 debug_data->active_types |= local_type;
680 if (default_callback) {
681 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
682 } else {
683 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600684 }
685
Mark Young6ba8abe2017-11-09 10:37:04 -0700686 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 -0600687 "DebugReport", "Added callback", kVUIDUndefined);
Mark Young6ba8abe2017-11-09 10:37:04 -0700688 return VK_SUCCESS;
689}
690
691static inline PFN_vkVoidFunction debug_utils_get_instance_proc_addr(debug_report_data *debug_data, const char *func_name) {
692 if (!debug_data) {
693 return NULL;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600694 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700695 if (debug_data->g_DEBUG_REPORT) {
696 if (!strcmp(func_name, "vkCreateDebugReportCallbackEXT")) {
697 return (PFN_vkVoidFunction)vkCreateDebugReportCallbackEXT;
698 }
699 if (!strcmp(func_name, "vkDestroyDebugReportCallbackEXT")) {
700 return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT;
701 }
702 if (!strcmp(func_name, "vkDebugReportMessageEXT")) {
703 return (PFN_vkVoidFunction)vkDebugReportMessageEXT;
704 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600705 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700706 if (debug_data->g_DEBUG_UTILS) {
707 if (!strcmp(func_name, "vkCreateDebugUtilsMessengerEXT")) {
708 return (PFN_vkVoidFunction)vkCreateDebugUtilsMessengerEXT;
709 }
710 if (!strcmp(func_name, "vkDestroyDebugUtilsMessengerEXT")) {
711 return (PFN_vkVoidFunction)vkDestroyDebugUtilsMessengerEXT;
712 }
713 if (!strcmp(func_name, "vkSubmitDebugUtilsMessageEXT")) {
714 return (PFN_vkVoidFunction)vkSubmitDebugUtilsMessageEXT;
715 }
Courtney Goeltzenleuchter822e8d72015-11-30 15:28:25 -0700716 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600717 return NULL;
718}
719
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600720// This utility (called at vkCreateInstance() time), looks at a pNext chain.
721// It counts any VkDebugReportCallbackCreateInfoEXT structs that it finds. It
722// then allocates an array that can hold that many structs, as well as that
723// many VkDebugReportCallbackEXT handles. It then copies each
724// VkDebugReportCallbackCreateInfoEXT, and initializes each handle.
Mark Young6ba8abe2017-11-09 10:37:04 -0700725static inline VkResult layer_copy_tmp_report_callbacks(const void *pChain, uint32_t *num_callbacks,
726 VkDebugReportCallbackCreateInfoEXT **infos,
727 VkDebugReportCallbackEXT **callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600728 uint32_t n = *num_callbacks = 0;
729
730 const void *pNext = pChain;
731 while (pNext) {
732 // 1st, count the number VkDebugReportCallbackCreateInfoEXT:
733 if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
734 n++;
735 }
736 pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext;
737 }
738 if (n == 0) {
739 return VK_SUCCESS;
740 }
741
742 // 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT:
743 VkDebugReportCallbackCreateInfoEXT *pInfos = *infos =
744 ((VkDebugReportCallbackCreateInfoEXT *)malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT)));
745 if (!pInfos) {
746 return VK_ERROR_OUT_OF_HOST_MEMORY;
747 }
748 // 3rd, allocate memory for a unique handle for each callback:
749 VkDebugReportCallbackEXT *pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)malloc(n * sizeof(VkDebugReportCallbackEXT)));
750 if (!pCallbacks) {
751 free(pInfos);
752 return VK_ERROR_OUT_OF_HOST_MEMORY;
753 }
754 // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by
755 // vkDestroyInstance, and assign a unique handle to each callback (just
756 // use the address of the copied VkDebugReportCallbackCreateInfoEXT):
757 pNext = pChain;
758 while (pNext) {
759 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
760 memcpy(pInfos, pNext, sizeof(VkDebugReportCallbackCreateInfoEXT));
761 *pCallbacks++ = (VkDebugReportCallbackEXT)pInfos++;
762 }
763 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
764 }
765
766 *num_callbacks = n;
767 return VK_SUCCESS;
768}
769
Mark Young6ba8abe2017-11-09 10:37:04 -0700770// This utility frees the arrays allocated by layer_copy_tmp_report_callbacks()
771static inline void layer_free_tmp_report_callbacks(VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600772 free(infos);
773 free(callbacks);
774}
775
776// This utility enables all of the VkDebugReportCallbackCreateInfoEXT structs
Mark Young6ba8abe2017-11-09 10:37:04 -0700777// that were copied by layer_copy_tmp_report_callbacks()
778static inline VkResult layer_enable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
779 VkDebugReportCallbackCreateInfoEXT *infos,
780 VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600781 VkResult rtn = VK_SUCCESS;
782 for (uint32_t i = 0; i < num_callbacks; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700783 rtn = layer_create_report_callback(debug_data, false, &infos[i], NULL, &callbacks[i]);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600784 if (rtn != VK_SUCCESS) {
785 for (uint32_t j = 0; j < i; j++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700786 layer_destroy_report_callback(debug_data, callbacks[j], NULL);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600787 }
788 return rtn;
789 }
790 }
791 return rtn;
792}
793
794// This utility disables all of the VkDebugReportCallbackCreateInfoEXT structs
Mark Young6ba8abe2017-11-09 10:37:04 -0700795// that were copied by layer_copy_tmp_report_callbacks()
796static inline void layer_disable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
797 VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600798 for (uint32_t i = 0; i < num_callbacks; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700799 layer_destroy_report_callback(debug_data, callbacks[i], NULL);
800 }
801}
802
803// This utility (called at vkCreateInstance() time), looks at a pNext chain.
804// It counts any VkDebugUtilsMessengerCreateInfoEXT structs that it finds. It
805// then allocates an array that can hold that many structs, as well as that
806// many VkDebugUtilsMessengerEXT handles. It then copies each
807// VkDebugUtilsMessengerCreateInfoEXT, and initializes each handle.
Mark Young8504ba62018-03-21 13:35:34 -0600808static inline VkResult layer_copy_tmp_debug_messengers(const void *pChain, uint32_t *num_messengers,
809 VkDebugUtilsMessengerCreateInfoEXT **infos,
810 VkDebugUtilsMessengerEXT **messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700811 uint32_t n = *num_messengers = 0;
812
813 const void *pNext = pChain;
814 while (pNext) {
815 // 1st, count the number VkDebugUtilsMessengerCreateInfoEXT:
816 if (((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
817 n++;
818 }
819 pNext = (void *)((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->pNext;
820 }
821 if (n == 0) {
822 return VK_SUCCESS;
823 }
824
825 // 2nd, allocate memory for each VkDebugUtilsMessengerCreateInfoEXT:
826 VkDebugUtilsMessengerCreateInfoEXT *pInfos = *infos =
827 ((VkDebugUtilsMessengerCreateInfoEXT *)malloc(n * sizeof(VkDebugUtilsMessengerCreateInfoEXT)));
828 if (!pInfos) {
829 return VK_ERROR_OUT_OF_HOST_MEMORY;
830 }
831 // 3rd, allocate memory for a unique handle for each messenger:
832 VkDebugUtilsMessengerEXT *pMessengers = *messengers =
833 ((VkDebugUtilsMessengerEXT *)malloc(n * sizeof(VkDebugUtilsMessengerEXT)));
834 if (!pMessengers) {
835 free(pInfos);
836 return VK_ERROR_OUT_OF_HOST_MEMORY;
837 }
838 // 4th, copy each VkDebugUtilsMessengerCreateInfoEXT for use by
839 // vkDestroyInstance, and assign a unique handle to each callback (just
840 // use the address of the copied VkDebugUtilsMessengerCreateInfoEXT):
841 pNext = pChain;
842 while (pNext) {
843 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
844 memcpy(pInfos, pNext, sizeof(VkDebugUtilsMessengerCreateInfoEXT));
845 *pMessengers++ = (VkDebugUtilsMessengerEXT)pInfos++;
846 }
847 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
848 }
849
850 *num_messengers = n;
851 return VK_SUCCESS;
852}
853
854// This utility frees the arrays allocated by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600855static inline void layer_free_tmp_debug_messengers(VkDebugUtilsMessengerCreateInfoEXT *infos,
856 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700857 free(infos);
858 free(messengers);
859}
860
861// This utility enables all of the VkDebugUtilsMessengerCreateInfoEXT structs
862// that were copied by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600863static inline VkResult layer_enable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
864 VkDebugUtilsMessengerCreateInfoEXT *infos,
865 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700866 VkResult rtn = VK_SUCCESS;
867 for (uint32_t i = 0; i < num_messengers; i++) {
868 rtn = layer_create_messenger_callback(debug_data, false, &infos[i], NULL, &messengers[i]);
869 if (rtn != VK_SUCCESS) {
870 for (uint32_t j = 0; j < i; j++) {
871 layer_destroy_messenger_callback(debug_data, messengers[j], NULL);
872 }
873 return rtn;
874 }
875 }
876 return rtn;
877}
878
879// This utility disables all of the VkDebugUtilsMessengerCreateInfoEXT structs
880// that were copied by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600881static inline void layer_disable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
882 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700883 for (uint32_t i = 0; i < num_messengers; i++) {
884 layer_destroy_messenger_callback(debug_data, messengers[i], NULL);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600885 }
886}
887
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600888// Checks if the message will get logged.
889// Allows layer to defer collecting & formating data if the
890// message will be discarded.
Mark Young6ba8abe2017-11-09 10:37:04 -0700891static inline bool will_log_msg(debug_report_data *debug_data, VkFlags msg_flags) {
892 VkFlags local_severity = 0;
893 VkFlags local_type = 0;
894 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
895 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600896 // Message is not wanted
Courtney Goeltzenleuchter6a564a12015-09-18 16:30:24 -0600897 return false;
898 }
899
900 return true;
901}
John Zulauf6664e272018-01-17 11:00:22 -0700902#ifndef WIN32
Mark Lobodzinski1bcbdf92018-02-07 10:00:22 -0700903static inline int string_sprintf(std::string *output, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
John Zulauf6664e272018-01-17 11:00:22 -0700904#endif
Mark Lobodzinski1bcbdf92018-02-07 10:00:22 -0700905static inline int string_sprintf(std::string *output, const char *fmt, ...) {
John Zulauf6664e272018-01-17 11:00:22 -0700906 std::string &formatted = *output;
907 va_list argptr;
908 va_start(argptr, fmt);
909 int reserve = vsnprintf(nullptr, 0, fmt, argptr);
910 va_end(argptr);
John Zulaufdeaa0132018-12-12 16:22:30 -0700911 formatted.reserve(reserve + 1); // Set the storage length long enough to hold the output + null
912 formatted.resize(reserve); // Set the *logical* length to be what vsprintf will write
John Zulauf6664e272018-01-17 11:00:22 -0700913 va_start(argptr, fmt);
914 int result = vsnprintf((char *)formatted.data(), formatted.capacity(), fmt, argptr);
915 va_end(argptr);
916 assert(result == reserve);
John Zulaufdeaa0132018-12-12 16:22:30 -0700917 assert((formatted.size() == strlen(formatted.c_str())));
John Zulauf6664e272018-01-17 11:00:22 -0700918 return result;
919}
Courtney Goeltzenleuchter6a564a12015-09-18 16:30:24 -0600920
Chris Forbes8a25bce2016-03-24 12:06:35 +1300921#ifdef WIN32
922static inline int vasprintf(char **strp, char const *fmt, va_list ap) {
923 *strp = nullptr;
924 int size = _vscprintf(fmt, ap);
925 if (size >= 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700926 *strp = (char *)malloc(size + 1);
Chris Forbes8a25bce2016-03-24 12:06:35 +1300927 if (!*strp) {
928 return -1;
929 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700930 _vsnprintf(*strp, size + 1, fmt, ap);
Chris Forbes8a25bce2016-03-24 12:06:35 +1300931 }
932 return size;
933}
934#endif
935
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700936// Output log message via DEBUG_REPORT. Takes format and variable arg list so that output string is only computed if a message
937// needs to be logged
Michael Lentine010f4692015-11-03 16:19:46 -0800938#ifndef WIN32
Mark Young6ba8abe2017-11-09 10:37:04 -0700939static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700940 uint64_t src_object, std::string vuid_text, const char *format, ...)
941 __attribute__((format(printf, 6, 7)));
Michael Lentine010f4692015-11-03 16:19:46 -0800942#endif
Mark Young6ba8abe2017-11-09 10:37:04 -0700943static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700944 uint64_t src_object, std::string vuid_text, const char *format, ...) {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700945 if (!debug_data) return false;
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700946 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700947 VkFlags local_severity = 0;
948 VkFlags local_type = 0;
949 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
950 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
951 // Message is not wanted
952 return false;
953 }
954
955 va_list argptr;
956 va_start(argptr, format);
957 char *str;
958 if (-1 == vasprintf(&str, format, argptr)) {
959 // On failure, glibc vasprintf leaves str undefined
960 str = nullptr;
961 }
962 va_end(argptr);
963
Dave Houlton407df732018-08-06 17:58:24 -0600964 std::string str_plus_spec_text(str ? str : "Allocation failure");
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700965
Dave Houlton407df732018-08-06 17:58:24 -0600966 // Append the spec error text to the error message, unless it's an UNASSIGNED or UNDEFINED vuid
967 if ((vuid_text.find("UNASSIGNED-") == std::string::npos) && (vuid_text.find(kVUIDUndefined) == std::string::npos)) {
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600968 // Linear search makes no assumptions about the layout of the string table
969 // This is not fast, but it does not need to be at this point in the error reporting path
970 uint32_t num_vuids = sizeof(vuid_spec_text) / sizeof(vuid_spec_text_pair);
971 const char *spec_text = nullptr;
972 for (uint32_t i = 0; i < num_vuids; i++) {
973 if (0 == strcmp(vuid_text.c_str(), vuid_spec_text[i].vuid)) {
974 spec_text = vuid_spec_text[i].spec_text;
975 break;
976 }
977 }
978
979 if (nullptr == spec_text) {
Dave Houlton407df732018-08-06 17:58:24 -0600980 // If this happens, you've hit a VUID string that isn't defined in the spec's json file
981 // Try running 'vk_validation_stats -c' to look for invalid VUID strings in the repo code
982 assert(0);
983 } else {
984 str_plus_spec_text += " The Vulkan spec states: ";
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600985 str_plus_spec_text += spec_text;
Dave Houlton407df732018-08-06 17:58:24 -0600986 }
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700987 }
988
Dave Houlton8e9f6542018-05-18 12:18:22 -0600989 // Append layer prefix with VUID string, pass in recovered legacy numerical VUID
Dave Houlton407df732018-08-06 17:58:24 -0600990 bool result = debug_log_msg(debug_data, msg_flags, object_type, src_object, 0, "Validation", str_plus_spec_text.c_str(),
991 vuid_text.c_str());
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700992
993 free(str);
994 return result;
995}
996
Mark Young6ba8abe2017-11-09 10:37:04 -0700997static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_log_callback(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
998 uint64_t src_object, size_t location, int32_t msg_code,
999 const char *layer_prefix, const char *message, void *user_data) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001000 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -07001001 char msg_flag_string[30];
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -06001002
Mark Young6ba8abe2017-11-09 10:37:04 -07001003 PrintMessageFlags(msg_flags, msg_flag_string);
Courtney Goeltzenleuchter2f25bb42015-06-14 11:29:24 -06001004
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001005 msg_buffer << layer_prefix << "(" << msg_flag_string << "): msg_code: " << msg_code << ": " << message << "\n";
1006 const std::string tmp = msg_buffer.str();
1007 const char *cstr = tmp.c_str();
1008
1009 fprintf((FILE *)user_data, "%s", cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -07001010 fflush((FILE *)user_data);
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -06001011
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001012#if defined __ANDROID__
1013 LOGCONSOLE("%s", cstr);
1014#endif
1015
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -06001016 return false;
Courtney Goeltzenleuchter2f25bb42015-06-14 11:29:24 -06001017}
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001018
Mark Young6ba8abe2017-11-09 10:37:04 -07001019static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_win32_debug_output_msg(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
1020 uint64_t src_object, size_t location, int32_t msg_code,
1021 const char *layer_prefix, const char *message,
1022 void *user_data) {
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001023#ifdef WIN32
Mark Young6ba8abe2017-11-09 10:37:04 -07001024 char msg_flag_string[30];
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001025 char buf[2048];
1026
Mark Young6ba8abe2017-11-09 10:37:04 -07001027 PrintMessageFlags(msg_flags, msg_flag_string);
Mark Lobodzinskib1fd9d12018-03-30 14:26:00 -06001028 _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 -06001029
1030 OutputDebugString(buf);
1031#endif
1032
1033 return false;
1034}
1035
Mark Young6ba8abe2017-11-09 10:37:04 -07001036static inline VKAPI_ATTR VkBool32 VKAPI_CALL DebugBreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT obj_type,
1037 uint64_t src_object, size_t location, int32_t msg_code,
1038 const char *layer_prefix, const char *message, void *user_data) {
Mark Lobodzinskic9d81652017-08-10 11:01:17 -06001039#ifdef WIN32
1040 DebugBreak();
1041#else
1042 raise(SIGTRAP);
1043#endif
1044
1045 return false;
1046}
1047
Mark Young6ba8abe2017-11-09 10:37:04 -07001048static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_log_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
1049 VkDebugUtilsMessageTypeFlagsEXT message_type,
1050 const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
1051 void *user_data) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001052 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -07001053 char msg_severity[30];
1054 char msg_type[30];
1055
1056 PrintMessageSeverity(message_severity, msg_severity);
1057 PrintMessageType(message_type, msg_type);
1058
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001059 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
1060 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
1061 msg_buffer << " Objects: " << callback_data->objectCount << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001062 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001063 msg_buffer << " [" << obj << "] " << std::hex << std::showbase
1064 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
1065 << callback_data->pObjects[obj].objectType
1066 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
1067 << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001068 }
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001069 const std::string tmp = msg_buffer.str();
1070 const char *cstr = tmp.c_str();
1071 fprintf((FILE *)user_data, "%s", cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -07001072 fflush((FILE *)user_data);
1073
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001074#if defined __ANDROID__
1075 LOGCONSOLE("%s", cstr);
1076#endif
1077
Mark Young6ba8abe2017-11-09 10:37:04 -07001078 return false;
Petr Krause9388f62017-05-13 20:53:12 +02001079}
1080
Mark Young6ba8abe2017-11-09 10:37:04 -07001081static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_win32_debug_output_msg(
1082 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type,
1083 const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data) {
1084#ifdef WIN32
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001085 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -07001086 char msg_severity[30];
1087 char msg_type[30];
Mark Lobodzinski863d5de2017-05-22 10:10:07 -06001088
Mark Young6ba8abe2017-11-09 10:37:04 -07001089 PrintMessageSeverity(message_severity, msg_severity);
1090 PrintMessageType(message_type, msg_type);
1091
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001092 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
1093 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
1094 msg_buffer << " Objects: " << callback_data->objectCount << "\n";
1095
Mark Young8504ba62018-03-21 13:35:34 -06001096 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001097 msg_buffer << " [" << obj << "] " << std::hex << std::showbase
1098 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
1099 << callback_data->pObjects[obj].objectType
1100 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
1101 << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001102 }
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001103 const std::string tmp = msg_buffer.str();
1104 const char *cstr = tmp.c_str();
1105 OutputDebugString(cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -07001106#endif
1107
1108 return false;
1109}
1110
1111// This utility converts from the VkDebugUtilsLabelEXT structure into the logging version of the structure.
1112// In the logging version, we only record what we absolutely need to convey back to the callbacks.
1113static inline void InsertLabelIntoLog(const VkDebugUtilsLabelEXT *utils_label, std::vector<LoggingLabelData> &log_vector) {
1114 LoggingLabelData log_label_data = {};
1115 log_label_data.name = utils_label->pLabelName;
1116 log_label_data.color[0] = utils_label->color[0];
1117 log_label_data.color[1] = utils_label->color[1];
1118 log_label_data.color[2] = utils_label->color[2];
1119 log_label_data.color[3] = utils_label->color[3];
1120 log_vector.push_back(log_label_data);
1121}
1122
Mark Young8504ba62018-03-21 13:35:34 -06001123static inline void BeginQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
1124 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001125 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001126 if (nullptr != label_info && nullptr != label_info->pLabelName) {
Mark Lobodzinski12813302019-02-07 15:03:06 -07001127 auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
1128 if (label_iter == report_data->debugUtilsQueueLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001129 std::vector<LoggingLabelData> new_queue_labels;
1130 InsertLabelIntoLog(label_info, new_queue_labels);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001131 report_data->debugUtilsQueueLabels.insert({queue, new_queue_labels});
Mark Young6ba8abe2017-11-09 10:37:04 -07001132 } else {
1133 // If the last thing was a label insert, we need to pop it off of the label vector before any
1134 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1135 // temporary location that exists until the next operation occurs. In this case, a new
1136 // "vkQueueBeginDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1137 if (report_data->queueLabelHasInsert) {
1138 report_data->queueLabelHasInsert = false;
1139 label_iter->second.pop_back();
1140 }
1141 InsertLabelIntoLog(label_info, label_iter->second);
1142 }
1143 }
1144}
1145
Mark Young8504ba62018-03-21 13:35:34 -06001146static inline void EndQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001147 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001148 auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
1149 if (label_iter != report_data->debugUtilsQueueLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001150 // If the last thing was a label insert, we need to pop it off of the label vector before any
1151 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1152 // temporary location that exists until the next operation occurs. In this case, a
1153 // "vkQueueEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
1154 if (report_data->queueLabelHasInsert) {
1155 report_data->queueLabelHasInsert = false;
1156 label_iter->second.pop_back();
1157 }
1158 // Now pop the normal item
1159 label_iter->second.pop_back();
1160 }
1161}
1162
Mark Young8504ba62018-03-21 13:35:34 -06001163static inline void InsertQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
1164 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001165 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001166 if (nullptr != label_info && nullptr != label_info->pLabelName) {
Mark Lobodzinski12813302019-02-07 15:03:06 -07001167 auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
1168 if (label_iter == report_data->debugUtilsQueueLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001169 std::vector<LoggingLabelData> new_queue_labels;
1170 InsertLabelIntoLog(label_info, new_queue_labels);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001171 report_data->debugUtilsQueueLabels.insert({queue, new_queue_labels});
Mark Young6ba8abe2017-11-09 10:37:04 -07001172 } else {
1173 // If the last thing was a label insert, we need to pop it off of the label vector before any
1174 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1175 // temporary location that exists until the next operation occurs. In this case, a new
1176 // "vkQueueInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1177 if (report_data->queueLabelHasInsert) {
1178 label_iter->second.pop_back();
1179 }
1180 // Insert this new label and mark it as one that has been "inserted" so we can remove it on
1181 // the next queue label operation.
1182 InsertLabelIntoLog(label_info, label_iter->second);
1183 report_data->queueLabelHasInsert = true;
1184 }
1185 }
1186}
1187
Mark Young8504ba62018-03-21 13:35:34 -06001188static inline void BeginCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1189 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001190 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001191 if (nullptr != label_info && nullptr != label_info->pLabelName) {
Mark Lobodzinski12813302019-02-07 15:03:06 -07001192 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
1193 if (label_iter == report_data->debugUtilsCmdBufLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001194 std::vector<LoggingLabelData> new_cmdbuf_labels;
1195 InsertLabelIntoLog(label_info, new_cmdbuf_labels);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001196 report_data->debugUtilsCmdBufLabels.insert({command_buffer, new_cmdbuf_labels});
Mark Young6ba8abe2017-11-09 10:37:04 -07001197 } else {
1198 // If the last thing was a label insert, we need to pop it off of the label vector before any
1199 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1200 // temporary location that exists until the next operation occurs. In this case, a
1201 // "vkCmdBeginDebugUtilsLabelEXT" has occurred erasing the inserted label.
1202 if (report_data->cmdBufLabelHasInsert) {
1203 report_data->cmdBufLabelHasInsert = false;
1204 label_iter->second.pop_back();
1205 }
1206 InsertLabelIntoLog(label_info, label_iter->second);
1207 }
1208 }
1209}
1210
Mark Young8504ba62018-03-21 13:35:34 -06001211static inline void EndCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001212 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001213 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
1214 if (label_iter != report_data->debugUtilsCmdBufLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001215 // If the last thing was a label insert, we need to pop it off of the label vector before any
1216 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1217 // temporary location that exists until the next operation occurs. In this case, a
1218 // "vkCmdEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
1219 if (report_data->cmdBufLabelHasInsert) {
1220 report_data->cmdBufLabelHasInsert = false;
1221 label_iter->second.pop_back();
1222 }
Shahbaz Youssefi10b94a62019-01-09 23:00:15 -05001223 // Guard against unbalanced markers.
1224 if (label_iter->second.size() > 0) {
1225 // Now pop the normal item
1226 label_iter->second.pop_back();
1227 }
Mark Young6ba8abe2017-11-09 10:37:04 -07001228 }
1229}
1230
Mark Young8504ba62018-03-21 13:35:34 -06001231static inline void InsertCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1232 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001233 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001234 if (nullptr != label_info && nullptr != label_info->pLabelName) {
Mark Lobodzinski12813302019-02-07 15:03:06 -07001235 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
1236 if (label_iter == report_data->debugUtilsCmdBufLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001237 std::vector<LoggingLabelData> new_cmdbuf_labels;
1238 InsertLabelIntoLog(label_info, new_cmdbuf_labels);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001239 report_data->debugUtilsCmdBufLabels.insert({command_buffer, new_cmdbuf_labels});
Mark Young6ba8abe2017-11-09 10:37:04 -07001240 } else {
1241 // If the last thing was a label insert, we need to pop it off of the label vector before any
1242 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1243 // temporary location that exists until the next operation occurs. In this case, a new
1244 // "vkCmdInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1245 if (report_data->cmdBufLabelHasInsert) {
1246 label_iter->second.pop_back();
1247 }
1248 // Insert this new label and mark it as one that has been "inserted" so we can remove it on
1249 // the next command buffer label operation.
1250 InsertLabelIntoLog(label_info, label_iter->second);
1251 report_data->cmdBufLabelHasInsert = true;
1252 }
1253 }
1254}
Mark Lobodzinski863d5de2017-05-22 10:10:07 -06001255
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001256#endif // LAYER_LOGGING_H