blob: 67ca767e7aafea3e2bd1ab1d495635bfb6f4237a [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
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600135} debug_report_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600136
Tobin Ehlis8d6acde2017-02-08 07:40:40 -0700137template debug_report_data *GetLayerDataPtr<debug_report_data>(void *data_key,
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700138 std::unordered_map<void *, debug_report_data *> &data_map);
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600139
Mark Young6ba8abe2017-11-09 10:37:04 -0700140static inline void DebugReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec,
141 VkDebugUtilsMessageSeverityFlagsEXT *da_severity,
142 VkDebugUtilsMessageTypeFlagsEXT *da_type) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700143 *da_severity = 0;
Mark Youngfbaae712018-10-04 14:33:50 -0600144 *da_type = 0;
Mark Youngc2347792018-05-30 08:41:25 -0600145 // If it's explicitly listed as a performance warning, treat it as a performance message.
146 // Otherwise, treat it as a validation issue.
147 if ((dr_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600148 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
149 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
Mark Youngc2347792018-05-30 08:41:25 -0600150 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700151 if ((dr_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600152 *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 -0700153 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700154 }
155 if ((dr_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600156 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700157 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700158 }
Mark Youngfbaae712018-10-04 14:33:50 -0600159 if ((dr_flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) != 0) {
160 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700161 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
162 }
163 if ((dr_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600164 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700165 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
166 }
167}
168
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600169// Forward Declarations
Mark Young6ba8abe2017-11-09 10:37:04 -0700170static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Dave Houlton407df732018-08-06 17:58:24 -0600171 uint64_t src_object, size_t location, const char *layer_prefix, const char *message,
172 const char *text_vuid);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600173
174// Add a debug message callback node structure to the specified callback linked list
Mark Young6ba8abe2017-11-09 10:37:04 -0700175static inline void AddDebugCallbackNode(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
176 VkLayerDbgFunctionNode *new_node) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600177 new_node->pNext = *list_head;
178 *list_head = new_node;
179}
180
Mark Young6ba8abe2017-11-09 10:37:04 -0700181// Remove specified debug messenger node structure from the specified linked list
182static inline void RemoveDebugUtilsMessenger(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
183 VkDebugUtilsMessengerEXT messenger) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600184 VkLayerDbgFunctionNode *cur_callback = *list_head;
Mark Youngfbaae712018-10-04 14:33:50 -0600185 VkLayerDbgFunctionNode *prev_callback = nullptr;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600186 bool matched = false;
Mark Young6ba8abe2017-11-09 10:37:04 -0700187 VkFlags local_severities = 0;
188 VkFlags local_types = 0;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600189
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600190 while (cur_callback) {
Mark Youngfbaae712018-10-04 14:33:50 -0600191 if (cur_callback->is_messenger) {
192 // If it's actually a messenger, then set it up for deletion.
193 if (cur_callback->messenger.messenger == messenger) {
194 matched = true;
195 if (*list_head == cur_callback) {
196 *list_head = cur_callback->pNext;
197 } else {
198 assert(nullptr != prev_callback);
199 prev_callback->pNext = cur_callback->pNext;
200 }
201 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
202 reinterpret_cast<uint64_t &>(cur_callback->messenger.messenger), 0, "DebugUtilsMessenger",
203 "Destroyed messenger\n", kVUIDUndefined);
204 } else {
205 // If it's not the one we're looking for, just keep the types/severities
206 local_severities |= cur_callback->messenger.messageSeverity;
207 local_types |= cur_callback->messenger.messageType;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600208 }
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600209 } else {
Mark Youngfbaae712018-10-04 14:33:50 -0600210 // If it's not a messenger, just keep the types/severities
211 VkFlags this_severities = 0;
212 VkFlags this_types = 0;
213 DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types);
214 local_severities |= this_severities;
215 local_types |= this_types;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600216 }
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600217 if (matched) {
Mark Youngfbaae712018-10-04 14:33:50 -0600218 free(cur_callback);
219 matched = false;
220 // Intentionally keep the last prev_callback, but select the proper cur_callback
221 if (nullptr != prev_callback) {
222 cur_callback = prev_callback->pNext;
223 } else {
224 cur_callback = *list_head;
225 }
226 } else {
227 prev_callback = cur_callback;
228 cur_callback = cur_callback->pNext;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600229 }
230 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700231 debug_data->active_severities = local_severities;
232 debug_data->active_types = local_types;
233}
234
235// Remove specified debug message callback node structure from the specified callback linked list
236static inline void RemoveDebugUtilsMessageCallback(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
237 VkDebugReportCallbackEXT callback) {
238 VkLayerDbgFunctionNode *cur_callback = *list_head;
Mark Youngfbaae712018-10-04 14:33:50 -0600239 VkLayerDbgFunctionNode *prev_callback = nullptr;
Mark Young6ba8abe2017-11-09 10:37:04 -0700240 bool matched = false;
241 VkFlags local_severities = 0;
242 VkFlags local_types = 0;
243
244 while (cur_callback) {
Mark Youngfbaae712018-10-04 14:33:50 -0600245 if (!cur_callback->is_messenger) {
246 // If it's actually a callback, then set it up for deletion.
247 if (cur_callback->report.msgCallback == callback) {
248 matched = true;
249 if (*list_head == cur_callback) {
250 *list_head = cur_callback->pNext;
251 } else {
252 assert(nullptr != prev_callback);
253 prev_callback->pNext = cur_callback->pNext;
254 }
255 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
256 reinterpret_cast<uint64_t &>(cur_callback->report.msgCallback), 0, "DebugReport",
257 "Destroyed callback\n", kVUIDUndefined);
258 } else {
259 // If it's not the one we're looking for, just keep the types/severities
260 VkFlags this_severities = 0;
261 VkFlags this_types = 0;
262 DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types);
263 local_severities |= this_severities;
264 local_types |= this_types;
Mark Young6ba8abe2017-11-09 10:37:04 -0700265 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700266 } else {
Mark Youngfbaae712018-10-04 14:33:50 -0600267 // If it's not a callback, just keep the types/severities
268 local_severities |= cur_callback->messenger.messageSeverity;
269 local_types |= cur_callback->messenger.messageType;
Mark Young6ba8abe2017-11-09 10:37:04 -0700270 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700271 if (matched) {
Mark Youngfbaae712018-10-04 14:33:50 -0600272 free(cur_callback);
273 matched = false;
274 // Intentionally keep the last prev_callback, but select the proper cur_callback
275 if (nullptr != prev_callback) {
276 cur_callback = prev_callback->pNext;
277 } else {
278 cur_callback = *list_head;
279 }
280 } else {
281 prev_callback = cur_callback;
282 cur_callback = cur_callback->pNext;
Mark Young6ba8abe2017-11-09 10:37:04 -0700283 }
284 }
285 debug_data->active_severities = local_severities;
286 debug_data->active_types = local_types;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600287}
288
289// Removes all debug callback function nodes from the specified callback linked lists and frees their resources
290static inline void RemoveAllMessageCallbacks(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head) {
291 VkLayerDbgFunctionNode *current_callback = *list_head;
292 VkLayerDbgFunctionNode *prev_callback = current_callback;
293
294 while (current_callback) {
295 prev_callback = current_callback->pNext;
Mark Young6ba8abe2017-11-09 10:37:04 -0700296 if (!current_callback->is_messenger) {
297 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 -0600298 (uint64_t)current_callback->report.msgCallback, 0, "DebugReport",
299 "Debug Report callbacks not removed before DestroyInstance", kVUIDUndefined);
Mark Young6ba8abe2017-11-09 10:37:04 -0700300 } else {
301 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 -0600302 (uint64_t)current_callback->messenger.messenger, 0, "Messenger",
303 "Debug messengers not removed before DestroyInstance", kVUIDUndefined);
Mark Young6ba8abe2017-11-09 10:37:04 -0700304 }
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600305 free(current_callback);
306 current_callback = prev_callback;
307 }
308 *list_head = NULL;
309}
310
Mark Young6ba8abe2017-11-09 10:37:04 -0700311static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Dave Houlton407df732018-08-06 17:58:24 -0600312 uint64_t src_object, size_t location, const char *layer_prefix, const char *message,
313 const char *text_vuid) {
Dustin Graves8f1eab92016-04-05 09:41:17 -0600314 bool bail = false;
Mark Young6ba8abe2017-11-09 10:37:04 -0700315 VkLayerDbgFunctionNode *layer_dbg_node = NULL;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600316
Mark Lobodzinski55a197f2016-06-21 15:54:57 -0600317 if (debug_data->debug_callback_list != NULL) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700318 layer_dbg_node = debug_data->debug_callback_list;
Mark Lobodzinski55a197f2016-06-21 15:54:57 -0600319 } else {
Mark Young6ba8abe2017-11-09 10:37:04 -0700320 layer_dbg_node = debug_data->default_debug_callback_list;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600321 }
322
Mark Young6ba8abe2017-11-09 10:37:04 -0700323 VkDebugUtilsMessageSeverityFlagsEXT severity;
324 VkDebugUtilsMessageTypeFlagsEXT types;
325 VkDebugUtilsMessengerCallbackDataEXT callback_data;
326 VkDebugUtilsObjectNameInfoEXT object_name_info;
327
328 // Convert the info to the VK_EXT_debug_utils form in case we need it.
329 DebugReportFlagsToAnnotFlags(msg_flags, true, &severity, &types);
330 object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
331 object_name_info.pNext = NULL;
332 object_name_info.objectType = convertDebugReportObjectToCoreObject(object_type);
333 object_name_info.objectHandle = (uint64_t)(uintptr_t)src_object;
334 object_name_info.pObjectName = NULL;
335
336 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
337 callback_data.pNext = NULL;
338 callback_data.flags = 0;
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700339 callback_data.pMessageIdName = text_vuid;
Dave Houlton407df732018-08-06 17:58:24 -0600340 callback_data.messageIdNumber = 0; // deprecated, validation layers use only the pMessageIdName
Mark Young6ba8abe2017-11-09 10:37:04 -0700341 callback_data.pMessage = message;
342 callback_data.queueLabelCount = 0;
343 callback_data.pQueueLabels = NULL;
344 callback_data.cmdBufLabelCount = 0;
345 callback_data.pCmdBufLabels = NULL;
346 callback_data.objectCount = 1;
347 callback_data.pObjects = &object_name_info;
348
349 VkDebugUtilsLabelEXT *queue_labels = nullptr;
350 VkDebugUtilsLabelEXT *cmd_buf_labels = nullptr;
351 std::string new_debug_report_message = "";
352 std::ostringstream oss;
Mark Young6ba8abe2017-11-09 10:37:04 -0700353
354 if (0 != src_object) {
Mark Young8504ba62018-03-21 13:35:34 -0600355 oss << "Object: 0x" << std::hex << src_object;
Mark Young6ba8abe2017-11-09 10:37:04 -0700356 // If this is a queue, add any queue labels to the callback data.
357 if (VK_OBJECT_TYPE_QUEUE == object_name_info.objectType) {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700358 auto label_iter = debug_data->debugUtilsQueueLabels.find(reinterpret_cast<VkQueue>(src_object));
359 if (label_iter != debug_data->debugUtilsQueueLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700360 queue_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
361 if (nullptr != queue_labels) {
362 // Record the labels, but record them in reverse order since we want the
363 // most recent at the top.
364 uint32_t label_size = static_cast<uint32_t>(label_iter->second.size());
365 uint32_t last_index = label_size - 1;
366 for (uint32_t label = 0; label < label_size; ++label) {
367 queue_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
368 queue_labels[last_index - label].pNext = nullptr;
369 queue_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
370 queue_labels[last_index - label].color[0] = label_iter->second[label].color[0];
371 queue_labels[last_index - label].color[1] = label_iter->second[label].color[1];
372 queue_labels[last_index - label].color[2] = label_iter->second[label].color[2];
373 queue_labels[last_index - label].color[3] = label_iter->second[label].color[3];
374 }
375 callback_data.queueLabelCount = label_size;
376 callback_data.pQueueLabels = queue_labels;
377 }
378 }
379 // If this is a command buffer, add any command buffer labels to the callback data.
380 } else if (VK_OBJECT_TYPE_COMMAND_BUFFER == object_name_info.objectType) {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700381 auto label_iter = debug_data->debugUtilsCmdBufLabels.find(reinterpret_cast<VkCommandBuffer>(src_object));
382 if (label_iter != debug_data->debugUtilsCmdBufLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700383 cmd_buf_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
384 if (nullptr != cmd_buf_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 cmd_buf_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
391 cmd_buf_labels[last_index - label].pNext = nullptr;
392 cmd_buf_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
393 cmd_buf_labels[last_index - label].color[0] = label_iter->second[label].color[0];
394 cmd_buf_labels[last_index - label].color[1] = label_iter->second[label].color[1];
395 cmd_buf_labels[last_index - label].color[2] = label_iter->second[label].color[2];
396 cmd_buf_labels[last_index - label].color[3] = label_iter->second[label].color[3];
397 }
398 callback_data.cmdBufLabelCount = label_size;
399 callback_data.pCmdBufLabels = cmd_buf_labels;
400 }
401 }
402 }
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700403
Mark Young6ba8abe2017-11-09 10:37:04 -0700404 // Look for any debug utils or marker names to use for this object
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700405 std::string label = debug_data->DebugReportGetUtilsObjectName(src_object);
406 if (label.empty()) {
407 label = debug_data->DebugReportGetMarkerObjectName(src_object);
Mark Young6ba8abe2017-11-09 10:37:04 -0700408 }
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700409 if (!label.empty()) {
410 object_name_info.pObjectName = label.c_str();
411 oss << " (Name = " << label << " : Type = ";
Mark Young8504ba62018-03-21 13:35:34 -0600412 } else {
413 oss << " (Type = ";
Mark Young6ba8abe2017-11-09 10:37:04 -0700414 }
Mark Young8504ba62018-03-21 13:35:34 -0600415 oss << std::to_string(object_type) << ")";
416 } else {
417 oss << "Object: VK_NULL_HANDLE (Type = " << std::to_string(object_type) << ")";
Mark Young6ba8abe2017-11-09 10:37:04 -0700418 }
419 new_debug_report_message += oss.str();
420 new_debug_report_message += " | ";
421 new_debug_report_message += message;
422
423 while (layer_dbg_node) {
Mark Young8504ba62018-03-21 13:35:34 -0600424 // If the app uses the VK_EXT_debug_report extension, call all of those registered callbacks.
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700425 if (!layer_dbg_node->is_messenger && (layer_dbg_node->report.msgFlags & msg_flags)) {
426 if (text_vuid != nullptr) {
427 // If a text vuid is supplied for the old debug report extension, prepend it to the message string
428 new_debug_report_message.insert(0, " ] ");
429 new_debug_report_message.insert(0, text_vuid);
430 new_debug_report_message.insert(0, " [ ");
431 }
432
Dave Houlton407df732018-08-06 17:58:24 -0600433 if (layer_dbg_node->report.pfnMsgCallback(msg_flags, object_type, src_object, location, 0, layer_prefix,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700434 new_debug_report_message.c_str(), layer_dbg_node->pUserData)) {
435 bail = true;
436 }
Mark Young8504ba62018-03-21 13:35:34 -0600437 // If the app uses the VK_EXT_debug_utils extension, call all of those registered callbacks.
Mark Young6ba8abe2017-11-09 10:37:04 -0700438 } else if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & severity) &&
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700439 (layer_dbg_node->messenger.messageType & types)) {
440 if (layer_dbg_node->messenger.pfnUserCallback(static_cast<VkDebugUtilsMessageSeverityFlagBitsEXT>(severity), types,
441 &callback_data, layer_dbg_node->pUserData)) {
442 bail = true;
443 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700444 }
445 layer_dbg_node = layer_dbg_node->pNext;
446 }
447
448 if (nullptr != queue_labels) {
449 delete[] queue_labels;
450 }
451 if (nullptr != cmd_buf_labels) {
452 delete[] cmd_buf_labels;
453 }
454
455 return bail;
456}
457
458static inline void DebugAnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,
459 VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags) {
460 *dr_flags = 0;
461
462 if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) {
463 *dr_flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
464 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) {
465 if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) {
466 *dr_flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
467 } else {
468 *dr_flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
469 }
470 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) {
471 *dr_flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
472 } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) {
473 *dr_flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
474 }
475}
476
477static inline bool debug_messenger_log_msg(const debug_report_data *debug_data,
478 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
479 VkDebugUtilsMessageTypeFlagsEXT message_type,
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700480 VkDebugUtilsMessengerCallbackDataEXT *callback_data,
481 const VkDebugUtilsMessengerEXT *messenger) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700482 bool bail = false;
483 VkLayerDbgFunctionNode *layer_dbg_node = NULL;
484
485 if (debug_data->debug_callback_list != NULL) {
486 layer_dbg_node = debug_data->debug_callback_list;
487 } else {
488 layer_dbg_node = debug_data->default_debug_callback_list;
489 }
490
491 VkDebugReportFlagsEXT object_flags = 0;
492
493 DebugAnnotFlagsToReportFlags(message_severity, message_type, &object_flags);
494
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700495 VkDebugUtilsObjectNameInfoEXT object_name_info;
496 object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
497 object_name_info.pNext = NULL;
498 object_name_info.objectType = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT;
499 object_name_info.objectHandle = HandleToUint64(*messenger);
500 object_name_info.pObjectName = NULL;
501 callback_data->pObjects = &object_name_info;
502 callback_data->objectCount = 1;
503
Mark Young6ba8abe2017-11-09 10:37:04 -0700504 while (layer_dbg_node) {
505 if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & message_severity) &&
506 (layer_dbg_node->messenger.messageType & message_type)) {
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700507 std::string messenger_label = debug_data->DebugReportGetUtilsObjectName(object_name_info.objectHandle);
508 if (!messenger_label.empty()) {
509 object_name_info.pObjectName = messenger_label.c_str();
Mark Young6ba8abe2017-11-09 10:37:04 -0700510 }
511 if (layer_dbg_node->messenger.pfnUserCallback(message_severity, message_type, callback_data,
512 layer_dbg_node->pUserData)) {
513 bail = true;
514 }
515 } else if (!layer_dbg_node->is_messenger && layer_dbg_node->report.msgFlags & object_flags) {
John Zulauf536649b2018-05-01 13:28:27 -0600516 VkDebugReportObjectTypeEXT object_type = convertCoreObjectToDebugReportObject(callback_data->pObjects[0].objectType);
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700517 std::string marker_label = debug_data->DebugReportGetMarkerObjectName(object_name_info.objectHandle);
518 if (marker_label.empty()) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700519 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
520 callback_data->messageIdNumber, callback_data->pMessageIdName,
521 callback_data->pMessage, layer_dbg_node->pUserData)) {
Tony Barbour3431dac2017-06-19 16:50:37 -0600522 bail = true;
523 }
524 } else {
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700525 std::string newMsg = "SrcObject name = " + marker_label;
Tony Barbour3431dac2017-06-19 16:50:37 -0600526 newMsg.append(" ");
Mark Young6ba8abe2017-11-09 10:37:04 -0700527 newMsg.append(callback_data->pMessage);
528 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
529 callback_data->messageIdNumber, callback_data->pMessageIdName,
530 newMsg.c_str(), layer_dbg_node->pUserData)) {
Tony Barbour3431dac2017-06-19 16:50:37 -0600531 bail = true;
532 }
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -0600533 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600534 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700535 layer_dbg_node = layer_dbg_node->pNext;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600536 }
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -0600537
538 return bail;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600539}
540
Mark Young6ba8abe2017-11-09 10:37:04 -0700541static inline debug_report_data *debug_utils_create_instance(
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700542 VkLayerInstanceDispatchTable *table, VkInstance inst, uint32_t extension_count,
Mark Young6ba8abe2017-11-09 10:37:04 -0700543 const char *const *enabled_extensions) // layer or extension name to be enabled
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600544{
Mark Lobodzinski12813302019-02-07 15:03:06 -0700545 debug_report_data *debug_data = new debug_report_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600546 for (uint32_t i = 0; i < extension_count; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700547 if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600548 debug_data->g_DEBUG_REPORT = true;
Mark Young6ba8abe2017-11-09 10:37:04 -0700549 } else if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
550 debug_data->g_DEBUG_UTILS = true;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600551 }
552 }
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600553 return debug_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600554}
555
Mark Young6ba8abe2017-11-09 10:37:04 -0700556static inline void layer_debug_utils_destroy_instance(debug_report_data *debug_data) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600557 if (debug_data) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700558 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600559 RemoveAllMessageCallbacks(debug_data, &debug_data->default_debug_callback_list);
560 RemoveAllMessageCallbacks(debug_data, &debug_data->debug_callback_list);
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700561 lock.unlock();
Mark Lobodzinski12813302019-02-07 15:03:06 -0700562 delete (debug_data);
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600563 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600564}
565
Mark Young6ba8abe2017-11-09 10:37:04 -0700566static inline debug_report_data *layer_debug_utils_create_device(debug_report_data *instance_debug_data, VkDevice device) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600567 // DEBUG_REPORT shares data between Instance and Device,
568 // so just return instance's data pointer
Courtney Goeltzenleuchterb9f0bf32015-06-14 09:50:18 -0600569 return instance_debug_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600570}
571
Mark Young6ba8abe2017-11-09 10:37:04 -0700572static inline void layer_debug_utils_destroy_device(VkDevice device) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600573 // Nothing to do since we're using instance data record
574}
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600575
Mark Young6ba8abe2017-11-09 10:37:04 -0700576static inline void layer_destroy_messenger_callback(debug_report_data *debug_data, VkDebugUtilsMessengerEXT messenger,
577 const VkAllocationCallbacks *allocator) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700578 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -0700579 RemoveDebugUtilsMessenger(debug_data, &debug_data->debug_callback_list, messenger);
580 RemoveDebugUtilsMessenger(debug_data, &debug_data->default_debug_callback_list, messenger);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600581}
582
Mark Young6ba8abe2017-11-09 10:37:04 -0700583static inline VkResult layer_create_messenger_callback(debug_report_data *debug_data, bool default_callback,
584 const VkDebugUtilsMessengerCreateInfoEXT *create_info,
585 const VkAllocationCallbacks *allocator,
586 VkDebugUtilsMessengerEXT *messenger) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700587 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700588 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700589 if (!pNewDbgFuncNode) return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young6ba8abe2017-11-09 10:37:04 -0700590 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
591 pNewDbgFuncNode->is_messenger = true;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600592
Tobin Ehliseb7715d2015-09-21 09:36:47 -0600593 // Handle of 0 is logging_callback so use allocated Node address as unique handle
Mark Young6ba8abe2017-11-09 10:37:04 -0700594 if (!(*messenger)) *messenger = (VkDebugUtilsMessengerEXT)pNewDbgFuncNode;
595 pNewDbgFuncNode->messenger.messenger = *messenger;
596 pNewDbgFuncNode->messenger.pfnUserCallback = create_info->pfnUserCallback;
597 pNewDbgFuncNode->messenger.messageSeverity = create_info->messageSeverity;
598 pNewDbgFuncNode->messenger.messageType = create_info->messageType;
599 pNewDbgFuncNode->pUserData = create_info->pUserData;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600600
Mark Young6ba8abe2017-11-09 10:37:04 -0700601 debug_data->active_severities |= create_info->messageSeverity;
602 debug_data->active_types |= create_info->messageType;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600603 if (default_callback) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700604 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600605 } else {
Mark Young6ba8abe2017-11-09 10:37:04 -0700606 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600607 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600608
Mark Young6ba8abe2017-11-09 10:37:04 -0700609 VkDebugUtilsMessengerCallbackDataEXT callback_data = {};
Mark Young6ba8abe2017-11-09 10:37:04 -0700610 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
611 callback_data.pNext = NULL;
612 callback_data.flags = 0;
613 callback_data.pMessageIdName = "Layer Internal Message";
614 callback_data.messageIdNumber = 0;
615 callback_data.pMessage = "Added messenger";
616 callback_data.queueLabelCount = 0;
617 callback_data.pQueueLabels = NULL;
618 callback_data.cmdBufLabelCount = 0;
619 callback_data.pCmdBufLabels = NULL;
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700620 callback_data.objectCount = 0;
621 callback_data.pObjects = NULL;
Mark Young6ba8abe2017-11-09 10:37:04 -0700622 debug_messenger_log_msg(debug_data, VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700623 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, &callback_data, messenger);
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600624 return VK_SUCCESS;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600625}
626
Mark Young6ba8abe2017-11-09 10:37:04 -0700627static inline void layer_destroy_report_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback,
628 const VkAllocationCallbacks *allocator) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700629 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -0700630 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->debug_callback_list, callback);
631 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->default_debug_callback_list, callback);
632}
633
634static inline VkResult layer_create_report_callback(debug_report_data *debug_data, bool default_callback,
635 const VkDebugReportCallbackCreateInfoEXT *create_info,
636 const VkAllocationCallbacks *allocator, VkDebugReportCallbackEXT *callback) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700637 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -0700638 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
639 if (!pNewDbgFuncNode) {
640 return VK_ERROR_OUT_OF_HOST_MEMORY;
641 }
642 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
643 pNewDbgFuncNode->is_messenger = false;
644
645 // Handle of 0 is logging_callback so use allocated Node address as unique handle
646 if (!(*callback)) *callback = (VkDebugReportCallbackEXT)pNewDbgFuncNode;
647 pNewDbgFuncNode->report.msgCallback = *callback;
648 pNewDbgFuncNode->report.pfnMsgCallback = create_info->pfnCallback;
649 pNewDbgFuncNode->report.msgFlags = create_info->flags;
650 pNewDbgFuncNode->pUserData = create_info->pUserData;
651
652 VkFlags local_severity = 0;
653 VkFlags local_type = 0;
654 DebugReportFlagsToAnnotFlags(create_info->flags, true, &local_severity, &local_type);
655 debug_data->active_severities |= local_severity;
656 debug_data->active_types |= local_type;
657 if (default_callback) {
658 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
659 } else {
660 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600661 }
662
Mark Young6ba8abe2017-11-09 10:37:04 -0700663 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 -0600664 "DebugReport", "Added callback", kVUIDUndefined);
Mark Young6ba8abe2017-11-09 10:37:04 -0700665 return VK_SUCCESS;
666}
667
668static inline PFN_vkVoidFunction debug_utils_get_instance_proc_addr(debug_report_data *debug_data, const char *func_name) {
669 if (!debug_data) {
670 return NULL;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600671 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700672 if (debug_data->g_DEBUG_REPORT) {
673 if (!strcmp(func_name, "vkCreateDebugReportCallbackEXT")) {
674 return (PFN_vkVoidFunction)vkCreateDebugReportCallbackEXT;
675 }
676 if (!strcmp(func_name, "vkDestroyDebugReportCallbackEXT")) {
677 return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT;
678 }
679 if (!strcmp(func_name, "vkDebugReportMessageEXT")) {
680 return (PFN_vkVoidFunction)vkDebugReportMessageEXT;
681 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600682 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700683 if (debug_data->g_DEBUG_UTILS) {
684 if (!strcmp(func_name, "vkCreateDebugUtilsMessengerEXT")) {
685 return (PFN_vkVoidFunction)vkCreateDebugUtilsMessengerEXT;
686 }
687 if (!strcmp(func_name, "vkDestroyDebugUtilsMessengerEXT")) {
688 return (PFN_vkVoidFunction)vkDestroyDebugUtilsMessengerEXT;
689 }
690 if (!strcmp(func_name, "vkSubmitDebugUtilsMessageEXT")) {
691 return (PFN_vkVoidFunction)vkSubmitDebugUtilsMessageEXT;
692 }
Courtney Goeltzenleuchter822e8d72015-11-30 15:28:25 -0700693 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600694 return NULL;
695}
696
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600697// This utility (called at vkCreateInstance() time), looks at a pNext chain.
698// It counts any VkDebugReportCallbackCreateInfoEXT structs that it finds. It
699// then allocates an array that can hold that many structs, as well as that
700// many VkDebugReportCallbackEXT handles. It then copies each
701// VkDebugReportCallbackCreateInfoEXT, and initializes each handle.
Mark Young6ba8abe2017-11-09 10:37:04 -0700702static inline VkResult layer_copy_tmp_report_callbacks(const void *pChain, uint32_t *num_callbacks,
703 VkDebugReportCallbackCreateInfoEXT **infos,
704 VkDebugReportCallbackEXT **callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600705 uint32_t n = *num_callbacks = 0;
706
707 const void *pNext = pChain;
708 while (pNext) {
709 // 1st, count the number VkDebugReportCallbackCreateInfoEXT:
710 if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
711 n++;
712 }
713 pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext;
714 }
715 if (n == 0) {
716 return VK_SUCCESS;
717 }
718
719 // 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT:
720 VkDebugReportCallbackCreateInfoEXT *pInfos = *infos =
721 ((VkDebugReportCallbackCreateInfoEXT *)malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT)));
722 if (!pInfos) {
723 return VK_ERROR_OUT_OF_HOST_MEMORY;
724 }
725 // 3rd, allocate memory for a unique handle for each callback:
726 VkDebugReportCallbackEXT *pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)malloc(n * sizeof(VkDebugReportCallbackEXT)));
727 if (!pCallbacks) {
728 free(pInfos);
729 return VK_ERROR_OUT_OF_HOST_MEMORY;
730 }
731 // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by
732 // vkDestroyInstance, and assign a unique handle to each callback (just
733 // use the address of the copied VkDebugReportCallbackCreateInfoEXT):
734 pNext = pChain;
735 while (pNext) {
736 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
737 memcpy(pInfos, pNext, sizeof(VkDebugReportCallbackCreateInfoEXT));
738 *pCallbacks++ = (VkDebugReportCallbackEXT)pInfos++;
739 }
740 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
741 }
742
743 *num_callbacks = n;
744 return VK_SUCCESS;
745}
746
Mark Young6ba8abe2017-11-09 10:37:04 -0700747// This utility frees the arrays allocated by layer_copy_tmp_report_callbacks()
748static inline void layer_free_tmp_report_callbacks(VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600749 free(infos);
750 free(callbacks);
751}
752
753// This utility enables all of the VkDebugReportCallbackCreateInfoEXT structs
Mark Young6ba8abe2017-11-09 10:37:04 -0700754// that were copied by layer_copy_tmp_report_callbacks()
755static inline VkResult layer_enable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
756 VkDebugReportCallbackCreateInfoEXT *infos,
757 VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600758 VkResult rtn = VK_SUCCESS;
759 for (uint32_t i = 0; i < num_callbacks; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700760 rtn = layer_create_report_callback(debug_data, false, &infos[i], NULL, &callbacks[i]);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600761 if (rtn != VK_SUCCESS) {
762 for (uint32_t j = 0; j < i; j++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700763 layer_destroy_report_callback(debug_data, callbacks[j], NULL);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600764 }
765 return rtn;
766 }
767 }
768 return rtn;
769}
770
771// This utility disables all of the VkDebugReportCallbackCreateInfoEXT structs
Mark Young6ba8abe2017-11-09 10:37:04 -0700772// that were copied by layer_copy_tmp_report_callbacks()
773static inline void layer_disable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
774 VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600775 for (uint32_t i = 0; i < num_callbacks; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700776 layer_destroy_report_callback(debug_data, callbacks[i], NULL);
777 }
778}
779
780// This utility (called at vkCreateInstance() time), looks at a pNext chain.
781// It counts any VkDebugUtilsMessengerCreateInfoEXT structs that it finds. It
782// then allocates an array that can hold that many structs, as well as that
783// many VkDebugUtilsMessengerEXT handles. It then copies each
784// VkDebugUtilsMessengerCreateInfoEXT, and initializes each handle.
Mark Young8504ba62018-03-21 13:35:34 -0600785static inline VkResult layer_copy_tmp_debug_messengers(const void *pChain, uint32_t *num_messengers,
786 VkDebugUtilsMessengerCreateInfoEXT **infos,
787 VkDebugUtilsMessengerEXT **messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700788 uint32_t n = *num_messengers = 0;
789
790 const void *pNext = pChain;
791 while (pNext) {
792 // 1st, count the number VkDebugUtilsMessengerCreateInfoEXT:
793 if (((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
794 n++;
795 }
796 pNext = (void *)((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->pNext;
797 }
798 if (n == 0) {
799 return VK_SUCCESS;
800 }
801
802 // 2nd, allocate memory for each VkDebugUtilsMessengerCreateInfoEXT:
803 VkDebugUtilsMessengerCreateInfoEXT *pInfos = *infos =
804 ((VkDebugUtilsMessengerCreateInfoEXT *)malloc(n * sizeof(VkDebugUtilsMessengerCreateInfoEXT)));
805 if (!pInfos) {
806 return VK_ERROR_OUT_OF_HOST_MEMORY;
807 }
808 // 3rd, allocate memory for a unique handle for each messenger:
809 VkDebugUtilsMessengerEXT *pMessengers = *messengers =
810 ((VkDebugUtilsMessengerEXT *)malloc(n * sizeof(VkDebugUtilsMessengerEXT)));
811 if (!pMessengers) {
812 free(pInfos);
813 return VK_ERROR_OUT_OF_HOST_MEMORY;
814 }
815 // 4th, copy each VkDebugUtilsMessengerCreateInfoEXT for use by
816 // vkDestroyInstance, and assign a unique handle to each callback (just
817 // use the address of the copied VkDebugUtilsMessengerCreateInfoEXT):
818 pNext = pChain;
819 while (pNext) {
820 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
821 memcpy(pInfos, pNext, sizeof(VkDebugUtilsMessengerCreateInfoEXT));
822 *pMessengers++ = (VkDebugUtilsMessengerEXT)pInfos++;
823 }
824 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
825 }
826
827 *num_messengers = n;
828 return VK_SUCCESS;
829}
830
831// This utility frees the arrays allocated by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600832static inline void layer_free_tmp_debug_messengers(VkDebugUtilsMessengerCreateInfoEXT *infos,
833 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700834 free(infos);
835 free(messengers);
836}
837
838// This utility enables all of the VkDebugUtilsMessengerCreateInfoEXT structs
839// that were copied by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600840static inline VkResult layer_enable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
841 VkDebugUtilsMessengerCreateInfoEXT *infos,
842 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700843 VkResult rtn = VK_SUCCESS;
844 for (uint32_t i = 0; i < num_messengers; i++) {
845 rtn = layer_create_messenger_callback(debug_data, false, &infos[i], NULL, &messengers[i]);
846 if (rtn != VK_SUCCESS) {
847 for (uint32_t j = 0; j < i; j++) {
848 layer_destroy_messenger_callback(debug_data, messengers[j], NULL);
849 }
850 return rtn;
851 }
852 }
853 return rtn;
854}
855
856// This utility disables all of the VkDebugUtilsMessengerCreateInfoEXT structs
857// that were copied by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600858static inline void layer_disable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
859 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700860 for (uint32_t i = 0; i < num_messengers; i++) {
861 layer_destroy_messenger_callback(debug_data, messengers[i], NULL);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600862 }
863}
864
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600865// Checks if the message will get logged.
866// Allows layer to defer collecting & formating data if the
867// message will be discarded.
Mark Young6ba8abe2017-11-09 10:37:04 -0700868static inline bool will_log_msg(debug_report_data *debug_data, VkFlags msg_flags) {
869 VkFlags local_severity = 0;
870 VkFlags local_type = 0;
871 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
872 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600873 // Message is not wanted
Courtney Goeltzenleuchter6a564a12015-09-18 16:30:24 -0600874 return false;
875 }
876
877 return true;
878}
John Zulauf6664e272018-01-17 11:00:22 -0700879#ifndef WIN32
Mark Lobodzinski1bcbdf92018-02-07 10:00:22 -0700880static inline int string_sprintf(std::string *output, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
John Zulauf6664e272018-01-17 11:00:22 -0700881#endif
Mark Lobodzinski1bcbdf92018-02-07 10:00:22 -0700882static inline int string_sprintf(std::string *output, const char *fmt, ...) {
John Zulauf6664e272018-01-17 11:00:22 -0700883 std::string &formatted = *output;
884 va_list argptr;
885 va_start(argptr, fmt);
886 int reserve = vsnprintf(nullptr, 0, fmt, argptr);
887 va_end(argptr);
John Zulaufdeaa0132018-12-12 16:22:30 -0700888 formatted.reserve(reserve + 1); // Set the storage length long enough to hold the output + null
889 formatted.resize(reserve); // Set the *logical* length to be what vsprintf will write
John Zulauf6664e272018-01-17 11:00:22 -0700890 va_start(argptr, fmt);
891 int result = vsnprintf((char *)formatted.data(), formatted.capacity(), fmt, argptr);
892 va_end(argptr);
893 assert(result == reserve);
John Zulaufdeaa0132018-12-12 16:22:30 -0700894 assert((formatted.size() == strlen(formatted.c_str())));
John Zulauf6664e272018-01-17 11:00:22 -0700895 return result;
896}
Courtney Goeltzenleuchter6a564a12015-09-18 16:30:24 -0600897
Chris Forbes8a25bce2016-03-24 12:06:35 +1300898#ifdef WIN32
899static inline int vasprintf(char **strp, char const *fmt, va_list ap) {
900 *strp = nullptr;
901 int size = _vscprintf(fmt, ap);
902 if (size >= 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700903 *strp = (char *)malloc(size + 1);
Chris Forbes8a25bce2016-03-24 12:06:35 +1300904 if (!*strp) {
905 return -1;
906 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700907 _vsnprintf(*strp, size + 1, fmt, ap);
Chris Forbes8a25bce2016-03-24 12:06:35 +1300908 }
909 return size;
910}
911#endif
912
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700913// Output log message via DEBUG_REPORT. Takes format and variable arg list so that output string is only computed if a message
914// needs to be logged
Michael Lentine010f4692015-11-03 16:19:46 -0800915#ifndef WIN32
Mark Young6ba8abe2017-11-09 10:37:04 -0700916static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700917 uint64_t src_object, std::string vuid_text, const char *format, ...)
918 __attribute__((format(printf, 6, 7)));
Michael Lentine010f4692015-11-03 16:19:46 -0800919#endif
Mark Young6ba8abe2017-11-09 10:37:04 -0700920static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700921 uint64_t src_object, std::string vuid_text, const char *format, ...) {
Mark Lobodzinski12813302019-02-07 15:03:06 -0700922 if (!debug_data) return false;
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -0700923 std::unique_lock<std::mutex> lock(debug_data->debug_report_mutex);
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700924 VkFlags local_severity = 0;
925 VkFlags local_type = 0;
926 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
927 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
928 // Message is not wanted
929 return false;
930 }
931
932 va_list argptr;
933 va_start(argptr, format);
934 char *str;
935 if (-1 == vasprintf(&str, format, argptr)) {
936 // On failure, glibc vasprintf leaves str undefined
937 str = nullptr;
938 }
939 va_end(argptr);
940
Dave Houlton407df732018-08-06 17:58:24 -0600941 std::string str_plus_spec_text(str ? str : "Allocation failure");
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700942
Dave Houlton407df732018-08-06 17:58:24 -0600943 // Append the spec error text to the error message, unless it's an UNASSIGNED or UNDEFINED vuid
944 if ((vuid_text.find("UNASSIGNED-") == std::string::npos) && (vuid_text.find(kVUIDUndefined) == std::string::npos)) {
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600945 // Linear search makes no assumptions about the layout of the string table
946 // This is not fast, but it does not need to be at this point in the error reporting path
947 uint32_t num_vuids = sizeof(vuid_spec_text) / sizeof(vuid_spec_text_pair);
948 const char *spec_text = nullptr;
949 for (uint32_t i = 0; i < num_vuids; i++) {
950 if (0 == strcmp(vuid_text.c_str(), vuid_spec_text[i].vuid)) {
951 spec_text = vuid_spec_text[i].spec_text;
952 break;
953 }
954 }
955
956 if (nullptr == spec_text) {
Dave Houlton407df732018-08-06 17:58:24 -0600957 // If this happens, you've hit a VUID string that isn't defined in the spec's json file
958 // Try running 'vk_validation_stats -c' to look for invalid VUID strings in the repo code
959 assert(0);
960 } else {
961 str_plus_spec_text += " The Vulkan spec states: ";
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600962 str_plus_spec_text += spec_text;
Dave Houlton407df732018-08-06 17:58:24 -0600963 }
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700964 }
965
Dave Houlton8e9f6542018-05-18 12:18:22 -0600966 // Append layer prefix with VUID string, pass in recovered legacy numerical VUID
Dave Houlton407df732018-08-06 17:58:24 -0600967 bool result = debug_log_msg(debug_data, msg_flags, object_type, src_object, 0, "Validation", str_plus_spec_text.c_str(),
968 vuid_text.c_str());
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700969
970 free(str);
971 return result;
972}
973
Mark Young6ba8abe2017-11-09 10:37:04 -0700974static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_log_callback(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
975 uint64_t src_object, size_t location, int32_t msg_code,
976 const char *layer_prefix, const char *message, void *user_data) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -0700977 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -0700978 char msg_flag_string[30];
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600979
Mark Young6ba8abe2017-11-09 10:37:04 -0700980 PrintMessageFlags(msg_flags, msg_flag_string);
Courtney Goeltzenleuchter2f25bb42015-06-14 11:29:24 -0600981
Mark Lobodzinski706e15a2018-12-12 15:35:29 -0700982 msg_buffer << layer_prefix << "(" << msg_flag_string << "): msg_code: " << msg_code << ": " << message << "\n";
983 const std::string tmp = msg_buffer.str();
984 const char *cstr = tmp.c_str();
985
986 fprintf((FILE *)user_data, "%s", cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -0700987 fflush((FILE *)user_data);
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -0600988
Mark Lobodzinski706e15a2018-12-12 15:35:29 -0700989#if defined __ANDROID__
990 LOGCONSOLE("%s", cstr);
991#endif
992
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -0600993 return false;
Courtney Goeltzenleuchter2f25bb42015-06-14 11:29:24 -0600994}
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -0600995
Mark Young6ba8abe2017-11-09 10:37:04 -0700996static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_win32_debug_output_msg(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,
999 void *user_data) {
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001000#ifdef WIN32
Mark Young6ba8abe2017-11-09 10:37:04 -07001001 char msg_flag_string[30];
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001002 char buf[2048];
1003
Mark Young6ba8abe2017-11-09 10:37:04 -07001004 PrintMessageFlags(msg_flags, msg_flag_string);
Mark Lobodzinskib1fd9d12018-03-30 14:26:00 -06001005 _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 -06001006
1007 OutputDebugString(buf);
1008#endif
1009
1010 return false;
1011}
1012
Mark Young6ba8abe2017-11-09 10:37:04 -07001013static inline VKAPI_ATTR VkBool32 VKAPI_CALL DebugBreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT obj_type,
1014 uint64_t src_object, size_t location, int32_t msg_code,
1015 const char *layer_prefix, const char *message, void *user_data) {
Mark Lobodzinskic9d81652017-08-10 11:01:17 -06001016#ifdef WIN32
1017 DebugBreak();
1018#else
1019 raise(SIGTRAP);
1020#endif
1021
1022 return false;
1023}
1024
Mark Young6ba8abe2017-11-09 10:37:04 -07001025static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_log_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
1026 VkDebugUtilsMessageTypeFlagsEXT message_type,
1027 const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
1028 void *user_data) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001029 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -07001030 char msg_severity[30];
1031 char msg_type[30];
1032
1033 PrintMessageSeverity(message_severity, msg_severity);
1034 PrintMessageType(message_type, msg_type);
1035
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001036 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
1037 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
1038 msg_buffer << " Objects: " << callback_data->objectCount << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001039 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001040 msg_buffer << " [" << obj << "] " << std::hex << std::showbase
1041 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
1042 << callback_data->pObjects[obj].objectType
1043 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
1044 << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001045 }
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001046 const std::string tmp = msg_buffer.str();
1047 const char *cstr = tmp.c_str();
1048 fprintf((FILE *)user_data, "%s", cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -07001049 fflush((FILE *)user_data);
1050
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001051#if defined __ANDROID__
1052 LOGCONSOLE("%s", cstr);
1053#endif
1054
Mark Young6ba8abe2017-11-09 10:37:04 -07001055 return false;
Petr Krause9388f62017-05-13 20:53:12 +02001056}
1057
Mark Young6ba8abe2017-11-09 10:37:04 -07001058static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_win32_debug_output_msg(
1059 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type,
1060 const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data) {
1061#ifdef WIN32
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001062 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -07001063 char msg_severity[30];
1064 char msg_type[30];
Mark Lobodzinski863d5de2017-05-22 10:10:07 -06001065
Mark Young6ba8abe2017-11-09 10:37:04 -07001066 PrintMessageSeverity(message_severity, msg_severity);
1067 PrintMessageType(message_type, msg_type);
1068
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001069 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
1070 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
1071 msg_buffer << " Objects: " << callback_data->objectCount << "\n";
1072
Mark Young8504ba62018-03-21 13:35:34 -06001073 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001074 msg_buffer << " [" << obj << "] " << std::hex << std::showbase
1075 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
1076 << callback_data->pObjects[obj].objectType
1077 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
1078 << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001079 }
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001080 const std::string tmp = msg_buffer.str();
1081 const char *cstr = tmp.c_str();
1082 OutputDebugString(cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -07001083#endif
1084
1085 return false;
1086}
1087
1088// This utility converts from the VkDebugUtilsLabelEXT structure into the logging version of the structure.
1089// In the logging version, we only record what we absolutely need to convey back to the callbacks.
1090static inline void InsertLabelIntoLog(const VkDebugUtilsLabelEXT *utils_label, std::vector<LoggingLabelData> &log_vector) {
1091 LoggingLabelData log_label_data = {};
1092 log_label_data.name = utils_label->pLabelName;
1093 log_label_data.color[0] = utils_label->color[0];
1094 log_label_data.color[1] = utils_label->color[1];
1095 log_label_data.color[2] = utils_label->color[2];
1096 log_label_data.color[3] = utils_label->color[3];
1097 log_vector.push_back(log_label_data);
1098}
1099
Mark Young8504ba62018-03-21 13:35:34 -06001100static inline void BeginQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
1101 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001102 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001103 if (nullptr != label_info && nullptr != label_info->pLabelName) {
Mark Lobodzinski12813302019-02-07 15:03:06 -07001104 auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
1105 if (label_iter == report_data->debugUtilsQueueLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001106 std::vector<LoggingLabelData> new_queue_labels;
1107 InsertLabelIntoLog(label_info, new_queue_labels);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001108 report_data->debugUtilsQueueLabels.insert({queue, new_queue_labels});
Mark Young6ba8abe2017-11-09 10:37:04 -07001109 } else {
1110 // If the last thing was a label insert, we need to pop it off of the label vector before any
1111 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1112 // temporary location that exists until the next operation occurs. In this case, a new
1113 // "vkQueueBeginDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1114 if (report_data->queueLabelHasInsert) {
1115 report_data->queueLabelHasInsert = false;
1116 label_iter->second.pop_back();
1117 }
1118 InsertLabelIntoLog(label_info, label_iter->second);
1119 }
1120 }
1121}
1122
Mark Young8504ba62018-03-21 13:35:34 -06001123static inline void EndQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001124 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001125 auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
1126 if (label_iter != report_data->debugUtilsQueueLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001127 // If the last thing was a label insert, we need to pop it off of the label vector before any
1128 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1129 // temporary location that exists until the next operation occurs. In this case, a
1130 // "vkQueueEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
1131 if (report_data->queueLabelHasInsert) {
1132 report_data->queueLabelHasInsert = false;
1133 label_iter->second.pop_back();
1134 }
1135 // Now pop the normal item
1136 label_iter->second.pop_back();
1137 }
1138}
1139
Mark Young8504ba62018-03-21 13:35:34 -06001140static inline void InsertQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
1141 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001142 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001143 if (nullptr != label_info && nullptr != label_info->pLabelName) {
Mark Lobodzinski12813302019-02-07 15:03:06 -07001144 auto label_iter = report_data->debugUtilsQueueLabels.find(queue);
1145 if (label_iter == report_data->debugUtilsQueueLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001146 std::vector<LoggingLabelData> new_queue_labels;
1147 InsertLabelIntoLog(label_info, new_queue_labels);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001148 report_data->debugUtilsQueueLabels.insert({queue, new_queue_labels});
Mark Young6ba8abe2017-11-09 10:37:04 -07001149 } else {
1150 // 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 new
1153 // "vkQueueInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1154 if (report_data->queueLabelHasInsert) {
1155 label_iter->second.pop_back();
1156 }
1157 // Insert this new label and mark it as one that has been "inserted" so we can remove it on
1158 // the next queue label operation.
1159 InsertLabelIntoLog(label_info, label_iter->second);
1160 report_data->queueLabelHasInsert = true;
1161 }
1162 }
1163}
1164
Mark Young8504ba62018-03-21 13:35:34 -06001165static inline void BeginCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1166 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001167 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001168 if (nullptr != label_info && nullptr != label_info->pLabelName) {
Mark Lobodzinski12813302019-02-07 15:03:06 -07001169 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
1170 if (label_iter == report_data->debugUtilsCmdBufLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001171 std::vector<LoggingLabelData> new_cmdbuf_labels;
1172 InsertLabelIntoLog(label_info, new_cmdbuf_labels);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001173 report_data->debugUtilsCmdBufLabels.insert({command_buffer, new_cmdbuf_labels});
Mark Young6ba8abe2017-11-09 10:37:04 -07001174 } else {
1175 // If the last thing was a label insert, we need to pop it off of the label vector before any
1176 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1177 // temporary location that exists until the next operation occurs. In this case, a
1178 // "vkCmdBeginDebugUtilsLabelEXT" has occurred erasing the inserted label.
1179 if (report_data->cmdBufLabelHasInsert) {
1180 report_data->cmdBufLabelHasInsert = false;
1181 label_iter->second.pop_back();
1182 }
1183 InsertLabelIntoLog(label_info, label_iter->second);
1184 }
1185 }
1186}
1187
Mark Young8504ba62018-03-21 13:35:34 -06001188static inline void EndCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001189 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001190 auto label_iter = report_data->debugUtilsCmdBufLabels.find(command_buffer);
1191 if (label_iter != report_data->debugUtilsCmdBufLabels.end()) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001192 // If the last thing was a label insert, we need to pop it off of the label vector before any
1193 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1194 // temporary location that exists until the next operation occurs. In this case, a
1195 // "vkCmdEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
1196 if (report_data->cmdBufLabelHasInsert) {
1197 report_data->cmdBufLabelHasInsert = false;
1198 label_iter->second.pop_back();
1199 }
Shahbaz Youssefi10b94a62019-01-09 23:00:15 -05001200 // Guard against unbalanced markers.
1201 if (label_iter->second.size() > 0) {
1202 // Now pop the normal item
1203 label_iter->second.pop_back();
1204 }
Mark Young6ba8abe2017-11-09 10:37:04 -07001205 }
1206}
1207
Mark Young8504ba62018-03-21 13:35:34 -06001208static inline void InsertCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1209 const VkDebugUtilsLabelEXT *label_info) {
Mark Lobodzinski25ac7b02019-02-07 13:22:56 -07001210 std::unique_lock<std::mutex> lock(report_data->debug_report_mutex);
Mark Young6ba8abe2017-11-09 10:37:04 -07001211 if (nullptr != label_info && nullptr != label_info->pLabelName) {
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 std::vector<LoggingLabelData> new_cmdbuf_labels;
1215 InsertLabelIntoLog(label_info, new_cmdbuf_labels);
Mark Lobodzinski12813302019-02-07 15:03:06 -07001216 report_data->debugUtilsCmdBufLabels.insert({command_buffer, new_cmdbuf_labels});
Mark Young6ba8abe2017-11-09 10:37:04 -07001217 } else {
1218 // If the last thing was a label insert, we need to pop it off of the label vector before any
1219 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1220 // temporary location that exists until the next operation occurs. In this case, a new
1221 // "vkCmdInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1222 if (report_data->cmdBufLabelHasInsert) {
1223 label_iter->second.pop_back();
1224 }
1225 // Insert this new label and mark it as one that has been "inserted" so we can remove it on
1226 // the next command buffer label operation.
1227 InsertLabelIntoLog(label_info, label_iter->second);
1228 report_data->cmdBufLabelHasInsert = true;
1229 }
1230 }
1231}
Mark Lobodzinski863d5de2017-05-22 10:10:07 -06001232
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001233#endif // LAYER_LOGGING_H