blob: d49e7aa391c52f1b8d5d1e67bccd02df0459ad56 [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 Lobodzinskic9d81652017-08-10 11:01:17 -060035#include <signal.h>
Karl Schultzd7f37542016-05-10 11:36:08 -060036#include <cinttypes>
Tobin Ehlis2d9deec2016-04-21 14:19:26 -060037#include <stdarg.h>
38#include <stdbool.h>
39#include <stdio.h>
40#include <unordered_map>
Mark Lobodzinski97c4d512016-05-19 15:27:18 -060041#include <vector>
Mark Young6ba8abe2017-11-09 10:37:04 -070042#include <sstream>
43#include <string>
44
Dave Houlton57ae22f2018-05-18 16:20:52 -060045// Suppress unused warning on Linux
46#if defined(__GNUC__)
Dave Houltoncfcecbf2018-05-31 16:20:57 -060047#define DECORATE_UNUSED __attribute__((unused))
48#else
49#define DECORATE_UNUSED
Dave Houlton57ae22f2018-05-18 16:20:52 -060050#endif
51
Mark Lobodzinski706e15a2018-12-12 15:35:29 -070052#if defined __ANDROID__
53#include <android/log.h>
54#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "VALIDATION", __VA_ARGS__))
55#else
56#define LOGCONSOLE(...) \
57 { \
58 printf(__VA_ARGS__); \
59 printf("\n"); \
60 }
61#endif
62
Dave Houltoncfcecbf2018-05-31 16:20:57 -060063static const char DECORATE_UNUSED *kVUIDUndefined = "VUID_Undefined";
Dave Houlton8e9f6542018-05-18 12:18:22 -060064
Dave Houltoncfcecbf2018-05-31 16:20:57 -060065#undef DECORATE_UNUSED
Dave Houlton57ae22f2018-05-18 16:20:52 -060066
Mark Young6ba8abe2017-11-09 10:37:04 -070067// TODO: Could be autogenerated for the specific handles for extra type safety...
68template <typename HANDLE_T>
69static inline uint64_t HandleToUint64(HANDLE_T *h) {
70 return reinterpret_cast<uint64_t>(h);
71}
72
73static inline uint64_t HandleToUint64(uint64_t h) { return h; }
74
75// Data we store per label for logging
76typedef struct _LoggingLabelData {
77 std::string name;
78 float color[4];
79} LoggingLabelData;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -060080
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -060081typedef struct _debug_report_data {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -060082 VkLayerDbgFunctionNode *debug_callback_list;
83 VkLayerDbgFunctionNode *default_debug_callback_list;
Mark Young6ba8abe2017-11-09 10:37:04 -070084 VkDebugUtilsMessageSeverityFlagsEXT active_severities;
85 VkDebugUtilsMessageTypeFlagsEXT active_types;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -060086 bool g_DEBUG_REPORT;
Mark Young6ba8abe2017-11-09 10:37:04 -070087 bool g_DEBUG_UTILS;
Tony Barbour3431dac2017-06-19 16:50:37 -060088 std::unordered_map<uint64_t, std::string> *debugObjectNameMap;
Mark Young6ba8abe2017-11-09 10:37:04 -070089 std::unordered_map<uint64_t, std::string> *debugUtilsObjectNameMap;
90 std::unordered_map<VkQueue, std::vector<LoggingLabelData>> *debugUtilsQueueLabels;
91 bool queueLabelHasInsert;
92 std::unordered_map<VkCommandBuffer, std::vector<LoggingLabelData>> *debugUtilsCmdBufLabels;
93 bool cmdBufLabelHasInsert;
Mark Lobodzinskiaaeed7c2019-02-07 10:19:40 -070094
95 void DebugReportSetUtilsObjectName(const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
96 if (pNameInfo->pObjectName) {
97 debugUtilsObjectNameMap->insert(
98 std::make_pair<uint64_t, std::string>((uint64_t &&) pNameInfo->objectHandle, pNameInfo->pObjectName));
99 } else {
100 debugUtilsObjectNameMap->erase(pNameInfo->objectHandle);
101 }
102 }
103
104 void DebugReportSetMarkerObjectName(const VkDebugMarkerObjectNameInfoEXT *pNameInfo) {
105 if (pNameInfo->pObjectName) {
106 debugObjectNameMap->insert(
107 std::make_pair<uint64_t, std::string>((uint64_t &&) pNameInfo->object, pNameInfo->pObjectName));
108 } else {
109 debugObjectNameMap->erase(pNameInfo->object);
110 }
111 }
112
113 std::string DebugReportGetUtilsObjectName(const uint64_t object) const {
114 std::string label = "";
115 auto utils_name_iter = debugUtilsObjectNameMap->find(object);
116 if (utils_name_iter != debugUtilsObjectNameMap->end()) {
117 label = utils_name_iter->second;
118 }
119 return label;
120 }
121
122 std::string DebugReportGetMarkerObjectName(const uint64_t object) const {
123 std::string label = "";
124 auto marker_name_iter = debugObjectNameMap->find(object);
125 if (marker_name_iter != debugObjectNameMap->end()) {
126 label = marker_name_iter->second;
127 }
128 return label;
129 }
130
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600131} debug_report_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600132
Tobin Ehlis8d6acde2017-02-08 07:40:40 -0700133template debug_report_data *GetLayerDataPtr<debug_report_data>(void *data_key,
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700134 std::unordered_map<void *, debug_report_data *> &data_map);
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600135
Mark Young6ba8abe2017-11-09 10:37:04 -0700136static inline void DebugReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec,
137 VkDebugUtilsMessageSeverityFlagsEXT *da_severity,
138 VkDebugUtilsMessageTypeFlagsEXT *da_type) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700139 *da_severity = 0;
Mark Youngfbaae712018-10-04 14:33:50 -0600140 *da_type = 0;
Mark Youngc2347792018-05-30 08:41:25 -0600141 // If it's explicitly listed as a performance warning, treat it as a performance message.
142 // Otherwise, treat it as a validation issue.
143 if ((dr_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600144 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
145 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
Mark Youngc2347792018-05-30 08:41:25 -0600146 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700147 if ((dr_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600148 *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 -0700149 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700150 }
151 if ((dr_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600152 *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700153 *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
Mark Young6ba8abe2017-11-09 10:37:04 -0700154 }
Mark Youngfbaae712018-10-04 14:33:50 -0600155 if ((dr_flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) != 0) {
156 *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_WARNING_BIT_EXT;
158 }
159 if ((dr_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) {
Mark Youngfbaae712018-10-04 14:33:50 -0600160 *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_ERROR_BIT_EXT;
162 }
163}
164
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600165// Forward Declarations
Mark Young6ba8abe2017-11-09 10:37:04 -0700166static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Dave Houlton407df732018-08-06 17:58:24 -0600167 uint64_t src_object, size_t location, const char *layer_prefix, const char *message,
168 const char *text_vuid);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600169
170// Add a debug message callback node structure to the specified callback linked list
Mark Young6ba8abe2017-11-09 10:37:04 -0700171static inline void AddDebugCallbackNode(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
172 VkLayerDbgFunctionNode *new_node) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600173 new_node->pNext = *list_head;
174 *list_head = new_node;
175}
176
Mark Young6ba8abe2017-11-09 10:37:04 -0700177// Remove specified debug messenger node structure from the specified linked list
178static inline void RemoveDebugUtilsMessenger(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
179 VkDebugUtilsMessengerEXT messenger) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600180 VkLayerDbgFunctionNode *cur_callback = *list_head;
Mark Youngfbaae712018-10-04 14:33:50 -0600181 VkLayerDbgFunctionNode *prev_callback = nullptr;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600182 bool matched = false;
Mark Young6ba8abe2017-11-09 10:37:04 -0700183 VkFlags local_severities = 0;
184 VkFlags local_types = 0;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600185
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600186 while (cur_callback) {
Mark Youngfbaae712018-10-04 14:33:50 -0600187 if (cur_callback->is_messenger) {
188 // If it's actually a messenger, then set it up for deletion.
189 if (cur_callback->messenger.messenger == messenger) {
190 matched = true;
191 if (*list_head == cur_callback) {
192 *list_head = cur_callback->pNext;
193 } else {
194 assert(nullptr != prev_callback);
195 prev_callback->pNext = cur_callback->pNext;
196 }
197 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
198 reinterpret_cast<uint64_t &>(cur_callback->messenger.messenger), 0, "DebugUtilsMessenger",
199 "Destroyed messenger\n", kVUIDUndefined);
200 } else {
201 // If it's not the one we're looking for, just keep the types/severities
202 local_severities |= cur_callback->messenger.messageSeverity;
203 local_types |= cur_callback->messenger.messageType;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600204 }
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600205 } else {
Mark Youngfbaae712018-10-04 14:33:50 -0600206 // If it's not a messenger, just keep the types/severities
207 VkFlags this_severities = 0;
208 VkFlags this_types = 0;
209 DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types);
210 local_severities |= this_severities;
211 local_types |= this_types;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600212 }
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600213 if (matched) {
Mark Youngfbaae712018-10-04 14:33:50 -0600214 free(cur_callback);
215 matched = false;
216 // Intentionally keep the last prev_callback, but select the proper cur_callback
217 if (nullptr != prev_callback) {
218 cur_callback = prev_callback->pNext;
219 } else {
220 cur_callback = *list_head;
221 }
222 } else {
223 prev_callback = cur_callback;
224 cur_callback = cur_callback->pNext;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600225 }
226 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700227 debug_data->active_severities = local_severities;
228 debug_data->active_types = local_types;
229}
230
231// Remove specified debug message callback node structure from the specified callback linked list
232static inline void RemoveDebugUtilsMessageCallback(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
233 VkDebugReportCallbackEXT callback) {
234 VkLayerDbgFunctionNode *cur_callback = *list_head;
Mark Youngfbaae712018-10-04 14:33:50 -0600235 VkLayerDbgFunctionNode *prev_callback = nullptr;
Mark Young6ba8abe2017-11-09 10:37:04 -0700236 bool matched = false;
237 VkFlags local_severities = 0;
238 VkFlags local_types = 0;
239
240 while (cur_callback) {
Mark Youngfbaae712018-10-04 14:33:50 -0600241 if (!cur_callback->is_messenger) {
242 // If it's actually a callback, then set it up for deletion.
243 if (cur_callback->report.msgCallback == callback) {
244 matched = true;
245 if (*list_head == cur_callback) {
246 *list_head = cur_callback->pNext;
247 } else {
248 assert(nullptr != prev_callback);
249 prev_callback->pNext = cur_callback->pNext;
250 }
251 debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
252 reinterpret_cast<uint64_t &>(cur_callback->report.msgCallback), 0, "DebugReport",
253 "Destroyed callback\n", kVUIDUndefined);
254 } else {
255 // If it's not the one we're looking for, just keep the types/severities
256 VkFlags this_severities = 0;
257 VkFlags this_types = 0;
258 DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types);
259 local_severities |= this_severities;
260 local_types |= this_types;
Mark Young6ba8abe2017-11-09 10:37:04 -0700261 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700262 } else {
Mark Youngfbaae712018-10-04 14:33:50 -0600263 // If it's not a callback, just keep the types/severities
264 local_severities |= cur_callback->messenger.messageSeverity;
265 local_types |= cur_callback->messenger.messageType;
Mark Young6ba8abe2017-11-09 10:37:04 -0700266 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700267 if (matched) {
Mark Youngfbaae712018-10-04 14:33:50 -0600268 free(cur_callback);
269 matched = false;
270 // Intentionally keep the last prev_callback, but select the proper cur_callback
271 if (nullptr != prev_callback) {
272 cur_callback = prev_callback->pNext;
273 } else {
274 cur_callback = *list_head;
275 }
276 } else {
277 prev_callback = cur_callback;
278 cur_callback = cur_callback->pNext;
Mark Young6ba8abe2017-11-09 10:37:04 -0700279 }
280 }
281 debug_data->active_severities = local_severities;
282 debug_data->active_types = local_types;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600283}
284
285// Removes all debug callback function nodes from the specified callback linked lists and frees their resources
286static inline void RemoveAllMessageCallbacks(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head) {
287 VkLayerDbgFunctionNode *current_callback = *list_head;
288 VkLayerDbgFunctionNode *prev_callback = current_callback;
289
290 while (current_callback) {
291 prev_callback = current_callback->pNext;
Mark Young6ba8abe2017-11-09 10:37:04 -0700292 if (!current_callback->is_messenger) {
293 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 -0600294 (uint64_t)current_callback->report.msgCallback, 0, "DebugReport",
295 "Debug Report callbacks not removed before DestroyInstance", kVUIDUndefined);
Mark Young6ba8abe2017-11-09 10:37:04 -0700296 } else {
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->messenger.messenger, 0, "Messenger",
299 "Debug messengers not removed before DestroyInstance", kVUIDUndefined);
Mark Young6ba8abe2017-11-09 10:37:04 -0700300 }
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600301 free(current_callback);
302 current_callback = prev_callback;
303 }
304 *list_head = NULL;
305}
306
Mark Young6ba8abe2017-11-09 10:37:04 -0700307static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Dave Houlton407df732018-08-06 17:58:24 -0600308 uint64_t src_object, size_t location, const char *layer_prefix, const char *message,
309 const char *text_vuid) {
Dustin Graves8f1eab92016-04-05 09:41:17 -0600310 bool bail = false;
Mark Young6ba8abe2017-11-09 10:37:04 -0700311 VkLayerDbgFunctionNode *layer_dbg_node = NULL;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600312
Mark Lobodzinski55a197f2016-06-21 15:54:57 -0600313 if (debug_data->debug_callback_list != NULL) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700314 layer_dbg_node = debug_data->debug_callback_list;
Mark Lobodzinski55a197f2016-06-21 15:54:57 -0600315 } else {
Mark Young6ba8abe2017-11-09 10:37:04 -0700316 layer_dbg_node = debug_data->default_debug_callback_list;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600317 }
318
Mark Young6ba8abe2017-11-09 10:37:04 -0700319 VkDebugUtilsMessageSeverityFlagsEXT severity;
320 VkDebugUtilsMessageTypeFlagsEXT types;
321 VkDebugUtilsMessengerCallbackDataEXT callback_data;
322 VkDebugUtilsObjectNameInfoEXT object_name_info;
323
324 // Convert the info to the VK_EXT_debug_utils form in case we need it.
325 DebugReportFlagsToAnnotFlags(msg_flags, true, &severity, &types);
326 object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
327 object_name_info.pNext = NULL;
328 object_name_info.objectType = convertDebugReportObjectToCoreObject(object_type);
329 object_name_info.objectHandle = (uint64_t)(uintptr_t)src_object;
330 object_name_info.pObjectName = NULL;
331
332 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
333 callback_data.pNext = NULL;
334 callback_data.flags = 0;
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700335 callback_data.pMessageIdName = text_vuid;
Dave Houlton407df732018-08-06 17:58:24 -0600336 callback_data.messageIdNumber = 0; // deprecated, validation layers use only the pMessageIdName
Mark Young6ba8abe2017-11-09 10:37:04 -0700337 callback_data.pMessage = message;
338 callback_data.queueLabelCount = 0;
339 callback_data.pQueueLabels = NULL;
340 callback_data.cmdBufLabelCount = 0;
341 callback_data.pCmdBufLabels = NULL;
342 callback_data.objectCount = 1;
343 callback_data.pObjects = &object_name_info;
344
345 VkDebugUtilsLabelEXT *queue_labels = nullptr;
346 VkDebugUtilsLabelEXT *cmd_buf_labels = nullptr;
347 std::string new_debug_report_message = "";
348 std::ostringstream oss;
Mark Young6ba8abe2017-11-09 10:37:04 -0700349
350 if (0 != src_object) {
Mark Young8504ba62018-03-21 13:35:34 -0600351 oss << "Object: 0x" << std::hex << src_object;
Mark Young6ba8abe2017-11-09 10:37:04 -0700352 // If this is a queue, add any queue labels to the callback data.
353 if (VK_OBJECT_TYPE_QUEUE == object_name_info.objectType) {
354 auto label_iter = debug_data->debugUtilsQueueLabels->find(reinterpret_cast<VkQueue>(src_object));
355 if (label_iter != debug_data->debugUtilsQueueLabels->end()) {
356 queue_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
357 if (nullptr != queue_labels) {
358 // Record the labels, but record them in reverse order since we want the
359 // most recent at the top.
360 uint32_t label_size = static_cast<uint32_t>(label_iter->second.size());
361 uint32_t last_index = label_size - 1;
362 for (uint32_t label = 0; label < label_size; ++label) {
363 queue_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
364 queue_labels[last_index - label].pNext = nullptr;
365 queue_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
366 queue_labels[last_index - label].color[0] = label_iter->second[label].color[0];
367 queue_labels[last_index - label].color[1] = label_iter->second[label].color[1];
368 queue_labels[last_index - label].color[2] = label_iter->second[label].color[2];
369 queue_labels[last_index - label].color[3] = label_iter->second[label].color[3];
370 }
371 callback_data.queueLabelCount = label_size;
372 callback_data.pQueueLabels = queue_labels;
373 }
374 }
375 // If this is a command buffer, add any command buffer labels to the callback data.
376 } else if (VK_OBJECT_TYPE_COMMAND_BUFFER == object_name_info.objectType) {
377 auto label_iter = debug_data->debugUtilsCmdBufLabels->find(reinterpret_cast<VkCommandBuffer>(src_object));
378 if (label_iter != debug_data->debugUtilsCmdBufLabels->end()) {
379 cmd_buf_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
380 if (nullptr != cmd_buf_labels) {
381 // Record the labels, but record them in reverse order since we want the
382 // most recent at the top.
383 uint32_t label_size = static_cast<uint32_t>(label_iter->second.size());
384 uint32_t last_index = label_size - 1;
385 for (uint32_t label = 0; label < label_size; ++label) {
386 cmd_buf_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
387 cmd_buf_labels[last_index - label].pNext = nullptr;
388 cmd_buf_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
389 cmd_buf_labels[last_index - label].color[0] = label_iter->second[label].color[0];
390 cmd_buf_labels[last_index - label].color[1] = label_iter->second[label].color[1];
391 cmd_buf_labels[last_index - label].color[2] = label_iter->second[label].color[2];
392 cmd_buf_labels[last_index - label].color[3] = label_iter->second[label].color[3];
393 }
394 callback_data.cmdBufLabelCount = label_size;
395 callback_data.pCmdBufLabels = cmd_buf_labels;
396 }
397 }
398 }
399 // Look for any debug utils or marker names to use for this object
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700400 object_name_info.pObjectName = NULL;
Mark Young6ba8abe2017-11-09 10:37:04 -0700401 auto utils_name_iter = debug_data->debugUtilsObjectNameMap->find(src_object);
402 if (utils_name_iter != debug_data->debugUtilsObjectNameMap->end()) {
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700403 object_name_info.pObjectName = utils_name_iter->second.c_str();
Mark Young6ba8abe2017-11-09 10:37:04 -0700404 } else {
405 auto marker_name_iter = debug_data->debugObjectNameMap->find(src_object);
406 if (marker_name_iter != debug_data->debugObjectNameMap->end()) {
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700407 object_name_info.pObjectName = marker_name_iter->second.c_str();
Mark Young6ba8abe2017-11-09 10:37:04 -0700408 }
409 }
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700410 if (NULL != object_name_info.pObjectName) {
411 oss << " (Name = " << object_name_info.pObjectName << " : 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)) {
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700507 auto it = debug_data->debugUtilsObjectNameMap->find(object_name_info.objectHandle);
508 if (it != debug_data->debugUtilsObjectNameMap->end()) {
509 object_name_info.pObjectName = it->second.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) {
516 auto it = debug_data->debugObjectNameMap->find(callback_data->pObjects[0].objectHandle);
John Zulauf536649b2018-05-01 13:28:27 -0600517 VkDebugReportObjectTypeEXT object_type = convertCoreObjectToDebugReportObject(callback_data->pObjects[0].objectType);
Tony Barbour3431dac2017-06-19 16:50:37 -0600518 if (it == debug_data->debugObjectNameMap->end()) {
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 {
525 std::string newMsg = "SrcObject name = ";
526 newMsg.append(it->second.c_str());
527 newMsg.append(" ");
Mark Young6ba8abe2017-11-09 10:37:04 -0700528 newMsg.append(callback_data->pMessage);
529 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
530 callback_data->messageIdNumber, callback_data->pMessageIdName,
531 newMsg.c_str(), layer_dbg_node->pUserData)) {
Tony Barbour3431dac2017-06-19 16:50:37 -0600532 bail = true;
533 }
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -0600534 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600535 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700536 layer_dbg_node = layer_dbg_node->pNext;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600537 }
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -0600538
539 return bail;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600540}
541
Mark Young6ba8abe2017-11-09 10:37:04 -0700542static inline debug_report_data *debug_utils_create_instance(
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700543 VkLayerInstanceDispatchTable *table, VkInstance inst, uint32_t extension_count,
Mark Young6ba8abe2017-11-09 10:37:04 -0700544 const char *const *enabled_extensions) // layer or extension name to be enabled
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600545{
Mark Youngaa1aa3a2016-07-05 16:41:50 -0600546 debug_report_data *debug_data = (debug_report_data *)malloc(sizeof(debug_report_data));
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700547 if (!debug_data) return NULL;
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600548
549 memset(debug_data, 0, sizeof(debug_report_data));
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600550 for (uint32_t i = 0; i < extension_count; i++) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600551 // TODO: Check other property fields
Mark Young6ba8abe2017-11-09 10:37:04 -0700552 if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600553 debug_data->g_DEBUG_REPORT = true;
Mark Young6ba8abe2017-11-09 10:37:04 -0700554 } else if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
555 debug_data->g_DEBUG_UTILS = true;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600556 }
557 }
Tony Barbour3431dac2017-06-19 16:50:37 -0600558 debug_data->debugObjectNameMap = new std::unordered_map<uint64_t, std::string>;
Mark Young6ba8abe2017-11-09 10:37:04 -0700559 debug_data->debugUtilsObjectNameMap = new std::unordered_map<uint64_t, std::string>;
560 debug_data->debugUtilsQueueLabels = new std::unordered_map<VkQueue, std::vector<LoggingLabelData>>;
561 debug_data->debugUtilsCmdBufLabels = new std::unordered_map<VkCommandBuffer, std::vector<LoggingLabelData>>;
562 debug_data->queueLabelHasInsert = false;
563 debug_data->cmdBufLabelHasInsert = false;
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600564 return debug_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600565}
566
Mark Young6ba8abe2017-11-09 10:37:04 -0700567static inline void layer_debug_utils_destroy_instance(debug_report_data *debug_data) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600568 if (debug_data) {
569 RemoveAllMessageCallbacks(debug_data, &debug_data->default_debug_callback_list);
570 RemoveAllMessageCallbacks(debug_data, &debug_data->debug_callback_list);
Tony Barbour3431dac2017-06-19 16:50:37 -0600571 delete debug_data->debugObjectNameMap;
Mark Young6ba8abe2017-11-09 10:37:04 -0700572 delete debug_data->debugUtilsObjectNameMap;
573 delete debug_data->debugUtilsQueueLabels;
574 delete debug_data->debugUtilsCmdBufLabels;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600575 free(debug_data);
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600576 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600577}
578
Mark Young6ba8abe2017-11-09 10:37:04 -0700579static inline debug_report_data *layer_debug_utils_create_device(debug_report_data *instance_debug_data, VkDevice device) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600580 // DEBUG_REPORT shares data between Instance and Device,
581 // so just return instance's data pointer
Courtney Goeltzenleuchterb9f0bf32015-06-14 09:50:18 -0600582 return instance_debug_data;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600583}
584
Mark Young6ba8abe2017-11-09 10:37:04 -0700585static inline void layer_debug_utils_destroy_device(VkDevice device) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600586 // Nothing to do since we're using instance data record
587}
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600588
Mark Young6ba8abe2017-11-09 10:37:04 -0700589static inline void layer_destroy_messenger_callback(debug_report_data *debug_data, VkDebugUtilsMessengerEXT messenger,
590 const VkAllocationCallbacks *allocator) {
591 RemoveDebugUtilsMessenger(debug_data, &debug_data->debug_callback_list, messenger);
592 RemoveDebugUtilsMessenger(debug_data, &debug_data->default_debug_callback_list, messenger);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600593}
594
Mark Young6ba8abe2017-11-09 10:37:04 -0700595static inline VkResult layer_create_messenger_callback(debug_report_data *debug_data, bool default_callback,
596 const VkDebugUtilsMessengerCreateInfoEXT *create_info,
597 const VkAllocationCallbacks *allocator,
598 VkDebugUtilsMessengerEXT *messenger) {
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700599 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700600 if (!pNewDbgFuncNode) return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young6ba8abe2017-11-09 10:37:04 -0700601 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
602 pNewDbgFuncNode->is_messenger = true;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600603
Tobin Ehliseb7715d2015-09-21 09:36:47 -0600604 // Handle of 0 is logging_callback so use allocated Node address as unique handle
Mark Young6ba8abe2017-11-09 10:37:04 -0700605 if (!(*messenger)) *messenger = (VkDebugUtilsMessengerEXT)pNewDbgFuncNode;
606 pNewDbgFuncNode->messenger.messenger = *messenger;
607 pNewDbgFuncNode->messenger.pfnUserCallback = create_info->pfnUserCallback;
608 pNewDbgFuncNode->messenger.messageSeverity = create_info->messageSeverity;
609 pNewDbgFuncNode->messenger.messageType = create_info->messageType;
610 pNewDbgFuncNode->pUserData = create_info->pUserData;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600611
Mark Young6ba8abe2017-11-09 10:37:04 -0700612 debug_data->active_severities |= create_info->messageSeverity;
613 debug_data->active_types |= create_info->messageType;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600614 if (default_callback) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700615 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600616 } else {
Mark Young6ba8abe2017-11-09 10:37:04 -0700617 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600618 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600619
Mark Young6ba8abe2017-11-09 10:37:04 -0700620 VkDebugUtilsMessengerCallbackDataEXT callback_data = {};
Mark Young6ba8abe2017-11-09 10:37:04 -0700621 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
622 callback_data.pNext = NULL;
623 callback_data.flags = 0;
624 callback_data.pMessageIdName = "Layer Internal Message";
625 callback_data.messageIdNumber = 0;
626 callback_data.pMessage = "Added messenger";
627 callback_data.queueLabelCount = 0;
628 callback_data.pQueueLabels = NULL;
629 callback_data.cmdBufLabelCount = 0;
630 callback_data.pCmdBufLabels = NULL;
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700631 callback_data.objectCount = 0;
632 callback_data.pObjects = NULL;
Mark Young6ba8abe2017-11-09 10:37:04 -0700633 debug_messenger_log_msg(debug_data, VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
Shannon McPherson7fbbe362018-12-03 11:57:42 -0700634 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, &callback_data, messenger);
Courtney Goeltzenleuchtere45acec2015-06-14 12:03:26 -0600635 return VK_SUCCESS;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600636}
637
Mark Young6ba8abe2017-11-09 10:37:04 -0700638static inline void layer_destroy_report_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback,
639 const VkAllocationCallbacks *allocator) {
640 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->debug_callback_list, callback);
641 RemoveDebugUtilsMessageCallback(debug_data, &debug_data->default_debug_callback_list, callback);
642}
643
644static inline VkResult layer_create_report_callback(debug_report_data *debug_data, bool default_callback,
645 const VkDebugReportCallbackCreateInfoEXT *create_info,
646 const VkAllocationCallbacks *allocator, VkDebugReportCallbackEXT *callback) {
647 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
648 if (!pNewDbgFuncNode) {
649 return VK_ERROR_OUT_OF_HOST_MEMORY;
650 }
651 memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
652 pNewDbgFuncNode->is_messenger = false;
653
654 // Handle of 0 is logging_callback so use allocated Node address as unique handle
655 if (!(*callback)) *callback = (VkDebugReportCallbackEXT)pNewDbgFuncNode;
656 pNewDbgFuncNode->report.msgCallback = *callback;
657 pNewDbgFuncNode->report.pfnMsgCallback = create_info->pfnCallback;
658 pNewDbgFuncNode->report.msgFlags = create_info->flags;
659 pNewDbgFuncNode->pUserData = create_info->pUserData;
660
661 VkFlags local_severity = 0;
662 VkFlags local_type = 0;
663 DebugReportFlagsToAnnotFlags(create_info->flags, true, &local_severity, &local_type);
664 debug_data->active_severities |= local_severity;
665 debug_data->active_types |= local_type;
666 if (default_callback) {
667 AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
668 } else {
669 AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600670 }
671
Mark Young6ba8abe2017-11-09 10:37:04 -0700672 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 -0600673 "DebugReport", "Added callback", kVUIDUndefined);
Mark Young6ba8abe2017-11-09 10:37:04 -0700674 return VK_SUCCESS;
675}
676
677static inline PFN_vkVoidFunction debug_utils_get_instance_proc_addr(debug_report_data *debug_data, const char *func_name) {
678 if (!debug_data) {
679 return NULL;
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600680 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700681 if (debug_data->g_DEBUG_REPORT) {
682 if (!strcmp(func_name, "vkCreateDebugReportCallbackEXT")) {
683 return (PFN_vkVoidFunction)vkCreateDebugReportCallbackEXT;
684 }
685 if (!strcmp(func_name, "vkDestroyDebugReportCallbackEXT")) {
686 return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT;
687 }
688 if (!strcmp(func_name, "vkDebugReportMessageEXT")) {
689 return (PFN_vkVoidFunction)vkDebugReportMessageEXT;
690 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600691 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700692 if (debug_data->g_DEBUG_UTILS) {
693 if (!strcmp(func_name, "vkCreateDebugUtilsMessengerEXT")) {
694 return (PFN_vkVoidFunction)vkCreateDebugUtilsMessengerEXT;
695 }
696 if (!strcmp(func_name, "vkDestroyDebugUtilsMessengerEXT")) {
697 return (PFN_vkVoidFunction)vkDestroyDebugUtilsMessengerEXT;
698 }
699 if (!strcmp(func_name, "vkSubmitDebugUtilsMessageEXT")) {
700 return (PFN_vkVoidFunction)vkSubmitDebugUtilsMessageEXT;
701 }
Courtney Goeltzenleuchter822e8d72015-11-30 15:28:25 -0700702 }
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600703 return NULL;
704}
705
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600706// This utility (called at vkCreateInstance() time), looks at a pNext chain.
707// It counts any VkDebugReportCallbackCreateInfoEXT structs that it finds. It
708// then allocates an array that can hold that many structs, as well as that
709// many VkDebugReportCallbackEXT handles. It then copies each
710// VkDebugReportCallbackCreateInfoEXT, and initializes each handle.
Mark Young6ba8abe2017-11-09 10:37:04 -0700711static inline VkResult layer_copy_tmp_report_callbacks(const void *pChain, uint32_t *num_callbacks,
712 VkDebugReportCallbackCreateInfoEXT **infos,
713 VkDebugReportCallbackEXT **callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600714 uint32_t n = *num_callbacks = 0;
715
716 const void *pNext = pChain;
717 while (pNext) {
718 // 1st, count the number VkDebugReportCallbackCreateInfoEXT:
719 if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
720 n++;
721 }
722 pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext;
723 }
724 if (n == 0) {
725 return VK_SUCCESS;
726 }
727
728 // 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT:
729 VkDebugReportCallbackCreateInfoEXT *pInfos = *infos =
730 ((VkDebugReportCallbackCreateInfoEXT *)malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT)));
731 if (!pInfos) {
732 return VK_ERROR_OUT_OF_HOST_MEMORY;
733 }
734 // 3rd, allocate memory for a unique handle for each callback:
735 VkDebugReportCallbackEXT *pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)malloc(n * sizeof(VkDebugReportCallbackEXT)));
736 if (!pCallbacks) {
737 free(pInfos);
738 return VK_ERROR_OUT_OF_HOST_MEMORY;
739 }
740 // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by
741 // vkDestroyInstance, and assign a unique handle to each callback (just
742 // use the address of the copied VkDebugReportCallbackCreateInfoEXT):
743 pNext = pChain;
744 while (pNext) {
745 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
746 memcpy(pInfos, pNext, sizeof(VkDebugReportCallbackCreateInfoEXT));
747 *pCallbacks++ = (VkDebugReportCallbackEXT)pInfos++;
748 }
749 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
750 }
751
752 *num_callbacks = n;
753 return VK_SUCCESS;
754}
755
Mark Young6ba8abe2017-11-09 10:37:04 -0700756// This utility frees the arrays allocated by layer_copy_tmp_report_callbacks()
757static inline void layer_free_tmp_report_callbacks(VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600758 free(infos);
759 free(callbacks);
760}
761
762// This utility enables all of the VkDebugReportCallbackCreateInfoEXT structs
Mark Young6ba8abe2017-11-09 10:37:04 -0700763// that were copied by layer_copy_tmp_report_callbacks()
764static inline VkResult layer_enable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
765 VkDebugReportCallbackCreateInfoEXT *infos,
766 VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600767 VkResult rtn = VK_SUCCESS;
768 for (uint32_t i = 0; i < num_callbacks; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700769 rtn = layer_create_report_callback(debug_data, false, &infos[i], NULL, &callbacks[i]);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600770 if (rtn != VK_SUCCESS) {
771 for (uint32_t j = 0; j < i; j++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700772 layer_destroy_report_callback(debug_data, callbacks[j], NULL);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600773 }
774 return rtn;
775 }
776 }
777 return rtn;
778}
779
780// This utility disables all of the VkDebugReportCallbackCreateInfoEXT structs
Mark Young6ba8abe2017-11-09 10:37:04 -0700781// that were copied by layer_copy_tmp_report_callbacks()
782static inline void layer_disable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
783 VkDebugReportCallbackEXT *callbacks) {
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600784 for (uint32_t i = 0; i < num_callbacks; i++) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700785 layer_destroy_report_callback(debug_data, callbacks[i], NULL);
786 }
787}
788
789// This utility (called at vkCreateInstance() time), looks at a pNext chain.
790// It counts any VkDebugUtilsMessengerCreateInfoEXT structs that it finds. It
791// then allocates an array that can hold that many structs, as well as that
792// many VkDebugUtilsMessengerEXT handles. It then copies each
793// VkDebugUtilsMessengerCreateInfoEXT, and initializes each handle.
Mark Young8504ba62018-03-21 13:35:34 -0600794static inline VkResult layer_copy_tmp_debug_messengers(const void *pChain, uint32_t *num_messengers,
795 VkDebugUtilsMessengerCreateInfoEXT **infos,
796 VkDebugUtilsMessengerEXT **messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700797 uint32_t n = *num_messengers = 0;
798
799 const void *pNext = pChain;
800 while (pNext) {
801 // 1st, count the number VkDebugUtilsMessengerCreateInfoEXT:
802 if (((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
803 n++;
804 }
805 pNext = (void *)((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->pNext;
806 }
807 if (n == 0) {
808 return VK_SUCCESS;
809 }
810
811 // 2nd, allocate memory for each VkDebugUtilsMessengerCreateInfoEXT:
812 VkDebugUtilsMessengerCreateInfoEXT *pInfos = *infos =
813 ((VkDebugUtilsMessengerCreateInfoEXT *)malloc(n * sizeof(VkDebugUtilsMessengerCreateInfoEXT)));
814 if (!pInfos) {
815 return VK_ERROR_OUT_OF_HOST_MEMORY;
816 }
817 // 3rd, allocate memory for a unique handle for each messenger:
818 VkDebugUtilsMessengerEXT *pMessengers = *messengers =
819 ((VkDebugUtilsMessengerEXT *)malloc(n * sizeof(VkDebugUtilsMessengerEXT)));
820 if (!pMessengers) {
821 free(pInfos);
822 return VK_ERROR_OUT_OF_HOST_MEMORY;
823 }
824 // 4th, copy each VkDebugUtilsMessengerCreateInfoEXT for use by
825 // vkDestroyInstance, and assign a unique handle to each callback (just
826 // use the address of the copied VkDebugUtilsMessengerCreateInfoEXT):
827 pNext = pChain;
828 while (pNext) {
829 if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
830 memcpy(pInfos, pNext, sizeof(VkDebugUtilsMessengerCreateInfoEXT));
831 *pMessengers++ = (VkDebugUtilsMessengerEXT)pInfos++;
832 }
833 pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
834 }
835
836 *num_messengers = n;
837 return VK_SUCCESS;
838}
839
840// This utility frees the arrays allocated by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600841static inline void layer_free_tmp_debug_messengers(VkDebugUtilsMessengerCreateInfoEXT *infos,
842 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700843 free(infos);
844 free(messengers);
845}
846
847// This utility enables all of the VkDebugUtilsMessengerCreateInfoEXT structs
848// that were copied by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600849static inline VkResult layer_enable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
850 VkDebugUtilsMessengerCreateInfoEXT *infos,
851 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700852 VkResult rtn = VK_SUCCESS;
853 for (uint32_t i = 0; i < num_messengers; i++) {
854 rtn = layer_create_messenger_callback(debug_data, false, &infos[i], NULL, &messengers[i]);
855 if (rtn != VK_SUCCESS) {
856 for (uint32_t j = 0; j < i; j++) {
857 layer_destroy_messenger_callback(debug_data, messengers[j], NULL);
858 }
859 return rtn;
860 }
861 }
862 return rtn;
863}
864
865// This utility disables all of the VkDebugUtilsMessengerCreateInfoEXT structs
866// that were copied by layer_copy_tmp_debug_messengers()
Mark Young8504ba62018-03-21 13:35:34 -0600867static inline void layer_disable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
868 VkDebugUtilsMessengerEXT *messengers) {
Mark Young6ba8abe2017-11-09 10:37:04 -0700869 for (uint32_t i = 0; i < num_messengers; i++) {
870 layer_destroy_messenger_callback(debug_data, messengers[i], NULL);
Ian Elliotted6b5ac2016-04-28 09:08:13 -0600871 }
872}
873
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600874// Checks if the message will get logged.
875// Allows layer to defer collecting & formating data if the
876// message will be discarded.
Mark Young6ba8abe2017-11-09 10:37:04 -0700877static inline bool will_log_msg(debug_report_data *debug_data, VkFlags msg_flags) {
878 VkFlags local_severity = 0;
879 VkFlags local_type = 0;
880 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
881 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600882 // Message is not wanted
Courtney Goeltzenleuchter6a564a12015-09-18 16:30:24 -0600883 return false;
884 }
885
886 return true;
887}
John Zulauf6664e272018-01-17 11:00:22 -0700888#ifndef WIN32
Mark Lobodzinski1bcbdf92018-02-07 10:00:22 -0700889static inline int string_sprintf(std::string *output, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
John Zulauf6664e272018-01-17 11:00:22 -0700890#endif
Mark Lobodzinski1bcbdf92018-02-07 10:00:22 -0700891static inline int string_sprintf(std::string *output, const char *fmt, ...) {
John Zulauf6664e272018-01-17 11:00:22 -0700892 std::string &formatted = *output;
893 va_list argptr;
894 va_start(argptr, fmt);
895 int reserve = vsnprintf(nullptr, 0, fmt, argptr);
896 va_end(argptr);
John Zulaufdeaa0132018-12-12 16:22:30 -0700897 formatted.reserve(reserve + 1); // Set the storage length long enough to hold the output + null
898 formatted.resize(reserve); // Set the *logical* length to be what vsprintf will write
John Zulauf6664e272018-01-17 11:00:22 -0700899 va_start(argptr, fmt);
900 int result = vsnprintf((char *)formatted.data(), formatted.capacity(), fmt, argptr);
901 va_end(argptr);
902 assert(result == reserve);
John Zulaufdeaa0132018-12-12 16:22:30 -0700903 assert((formatted.size() == strlen(formatted.c_str())));
John Zulauf6664e272018-01-17 11:00:22 -0700904 return result;
905}
Courtney Goeltzenleuchter6a564a12015-09-18 16:30:24 -0600906
Chris Forbes8a25bce2016-03-24 12:06:35 +1300907#ifdef WIN32
908static inline int vasprintf(char **strp, char const *fmt, va_list ap) {
909 *strp = nullptr;
910 int size = _vscprintf(fmt, ap);
911 if (size >= 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700912 *strp = (char *)malloc(size + 1);
Chris Forbes8a25bce2016-03-24 12:06:35 +1300913 if (!*strp) {
914 return -1;
915 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700916 _vsnprintf(*strp, size + 1, fmt, ap);
Chris Forbes8a25bce2016-03-24 12:06:35 +1300917 }
918 return size;
919}
920#endif
921
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700922// Output log message via DEBUG_REPORT. Takes format and variable arg list so that output string is only computed if a message
923// needs to be logged
Michael Lentine010f4692015-11-03 16:19:46 -0800924#ifndef WIN32
Mark Young6ba8abe2017-11-09 10:37:04 -0700925static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700926 uint64_t src_object, std::string vuid_text, const char *format, ...)
927 __attribute__((format(printf, 6, 7)));
Michael Lentine010f4692015-11-03 16:19:46 -0800928#endif
Mark Young6ba8abe2017-11-09 10:37:04 -0700929static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700930 uint64_t src_object, std::string vuid_text, const char *format, ...) {
931 VkFlags local_severity = 0;
932 VkFlags local_type = 0;
933 DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
934 if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
935 // Message is not wanted
936 return false;
937 }
938
939 va_list argptr;
940 va_start(argptr, format);
941 char *str;
942 if (-1 == vasprintf(&str, format, argptr)) {
943 // On failure, glibc vasprintf leaves str undefined
944 str = nullptr;
945 }
946 va_end(argptr);
947
Dave Houlton407df732018-08-06 17:58:24 -0600948 std::string str_plus_spec_text(str ? str : "Allocation failure");
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700949
Dave Houlton407df732018-08-06 17:58:24 -0600950 // Append the spec error text to the error message, unless it's an UNASSIGNED or UNDEFINED vuid
951 if ((vuid_text.find("UNASSIGNED-") == std::string::npos) && (vuid_text.find(kVUIDUndefined) == std::string::npos)) {
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600952 // Linear search makes no assumptions about the layout of the string table
953 // This is not fast, but it does not need to be at this point in the error reporting path
954 uint32_t num_vuids = sizeof(vuid_spec_text) / sizeof(vuid_spec_text_pair);
955 const char *spec_text = nullptr;
956 for (uint32_t i = 0; i < num_vuids; i++) {
957 if (0 == strcmp(vuid_text.c_str(), vuid_spec_text[i].vuid)) {
958 spec_text = vuid_spec_text[i].spec_text;
959 break;
960 }
961 }
962
963 if (nullptr == spec_text) {
Dave Houlton407df732018-08-06 17:58:24 -0600964 // If this happens, you've hit a VUID string that isn't defined in the spec's json file
965 // Try running 'vk_validation_stats -c' to look for invalid VUID strings in the repo code
966 assert(0);
967 } else {
968 str_plus_spec_text += " The Vulkan spec states: ";
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600969 str_plus_spec_text += spec_text;
Dave Houlton407df732018-08-06 17:58:24 -0600970 }
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700971 }
972
Dave Houlton8e9f6542018-05-18 12:18:22 -0600973 // Append layer prefix with VUID string, pass in recovered legacy numerical VUID
Dave Houlton407df732018-08-06 17:58:24 -0600974 bool result = debug_log_msg(debug_data, msg_flags, object_type, src_object, 0, "Validation", str_plus_spec_text.c_str(),
975 vuid_text.c_str());
Mark Lobodzinski316c18c2018-02-21 09:48:42 -0700976
977 free(str);
978 return result;
979}
980
Mark Young6ba8abe2017-11-09 10:37:04 -0700981static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_log_callback(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
982 uint64_t src_object, size_t location, int32_t msg_code,
983 const char *layer_prefix, const char *message, void *user_data) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -0700984 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -0700985 char msg_flag_string[30];
Courtney Goeltzenleuchter7d8503b2015-06-11 15:58:51 -0600986
Mark Young6ba8abe2017-11-09 10:37:04 -0700987 PrintMessageFlags(msg_flags, msg_flag_string);
Courtney Goeltzenleuchter2f25bb42015-06-14 11:29:24 -0600988
Mark Lobodzinski706e15a2018-12-12 15:35:29 -0700989 msg_buffer << layer_prefix << "(" << msg_flag_string << "): msg_code: " << msg_code << ": " << message << "\n";
990 const std::string tmp = msg_buffer.str();
991 const char *cstr = tmp.c_str();
992
993 fprintf((FILE *)user_data, "%s", cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -0700994 fflush((FILE *)user_data);
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -0600995
Mark Lobodzinski706e15a2018-12-12 15:35:29 -0700996#if defined __ANDROID__
997 LOGCONSOLE("%s", cstr);
998#endif
999
Courtney Goeltzenleuchter06640832015-09-04 13:52:24 -06001000 return false;
Courtney Goeltzenleuchter2f25bb42015-06-14 11:29:24 -06001001}
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001002
Mark Young6ba8abe2017-11-09 10:37:04 -07001003static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_win32_debug_output_msg(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
1004 uint64_t src_object, size_t location, int32_t msg_code,
1005 const char *layer_prefix, const char *message,
1006 void *user_data) {
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001007#ifdef WIN32
Mark Young6ba8abe2017-11-09 10:37:04 -07001008 char msg_flag_string[30];
Courtney Goeltzenleuchter5907ac42015-10-05 14:41:34 -06001009 char buf[2048];
1010
Mark Young6ba8abe2017-11-09 10:37:04 -07001011 PrintMessageFlags(msg_flags, msg_flag_string);
Mark Lobodzinskib1fd9d12018-03-30 14:26:00 -06001012 _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 -06001013
1014 OutputDebugString(buf);
1015#endif
1016
1017 return false;
1018}
1019
Mark Young6ba8abe2017-11-09 10:37:04 -07001020static inline VKAPI_ATTR VkBool32 VKAPI_CALL DebugBreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT obj_type,
1021 uint64_t src_object, size_t location, int32_t msg_code,
1022 const char *layer_prefix, const char *message, void *user_data) {
Mark Lobodzinskic9d81652017-08-10 11:01:17 -06001023#ifdef WIN32
1024 DebugBreak();
1025#else
1026 raise(SIGTRAP);
1027#endif
1028
1029 return false;
1030}
1031
Mark Young6ba8abe2017-11-09 10:37:04 -07001032static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_log_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
1033 VkDebugUtilsMessageTypeFlagsEXT message_type,
1034 const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
1035 void *user_data) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001036 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -07001037 char msg_severity[30];
1038 char msg_type[30];
1039
1040 PrintMessageSeverity(message_severity, msg_severity);
1041 PrintMessageType(message_type, msg_type);
1042
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001043 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
1044 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
1045 msg_buffer << " Objects: " << callback_data->objectCount << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001046 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001047 msg_buffer << " [" << obj << "] " << std::hex << std::showbase
1048 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
1049 << callback_data->pObjects[obj].objectType
1050 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
1051 << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001052 }
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001053 const std::string tmp = msg_buffer.str();
1054 const char *cstr = tmp.c_str();
1055 fprintf((FILE *)user_data, "%s", cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -07001056 fflush((FILE *)user_data);
1057
Mark Lobodzinski706e15a2018-12-12 15:35:29 -07001058#if defined __ANDROID__
1059 LOGCONSOLE("%s", cstr);
1060#endif
1061
Mark Young6ba8abe2017-11-09 10:37:04 -07001062 return false;
Petr Krause9388f62017-05-13 20:53:12 +02001063}
1064
Mark Young6ba8abe2017-11-09 10:37:04 -07001065static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_win32_debug_output_msg(
1066 VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type,
1067 const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data) {
1068#ifdef WIN32
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001069 std::ostringstream msg_buffer;
Mark Young6ba8abe2017-11-09 10:37:04 -07001070 char msg_severity[30];
1071 char msg_type[30];
Mark Lobodzinski863d5de2017-05-22 10:10:07 -06001072
Mark Young6ba8abe2017-11-09 10:37:04 -07001073 PrintMessageSeverity(message_severity, msg_severity);
1074 PrintMessageType(message_type, msg_type);
1075
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001076 msg_buffer << callback_data->pMessageIdName << "(" << msg_severity << " / " << msg_type
1077 << "): msgNum: " << callback_data->messageIdNumber << " - " << callback_data->pMessage << "\n";
1078 msg_buffer << " Objects: " << callback_data->objectCount << "\n";
1079
Mark Young8504ba62018-03-21 13:35:34 -06001080 for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001081 msg_buffer << " [" << obj << "] " << std::hex << std::showbase
1082 << HandleToUint64(callback_data->pObjects[obj].objectHandle) << ", type: " << std::dec << std::noshowbase
1083 << callback_data->pObjects[obj].objectType
1084 << ", name: " << (callback_data->pObjects[obj].pObjectName ? callback_data->pObjects[obj].pObjectName : "NULL")
1085 << "\n";
Mark Young8504ba62018-03-21 13:35:34 -06001086 }
Mark Lobodzinski3be125e2018-11-19 09:58:10 -07001087 const std::string tmp = msg_buffer.str();
1088 const char *cstr = tmp.c_str();
1089 OutputDebugString(cstr);
Mark Young6ba8abe2017-11-09 10:37:04 -07001090#endif
1091
1092 return false;
1093}
1094
1095// This utility converts from the VkDebugUtilsLabelEXT structure into the logging version of the structure.
1096// In the logging version, we only record what we absolutely need to convey back to the callbacks.
1097static inline void InsertLabelIntoLog(const VkDebugUtilsLabelEXT *utils_label, std::vector<LoggingLabelData> &log_vector) {
1098 LoggingLabelData log_label_data = {};
1099 log_label_data.name = utils_label->pLabelName;
1100 log_label_data.color[0] = utils_label->color[0];
1101 log_label_data.color[1] = utils_label->color[1];
1102 log_label_data.color[2] = utils_label->color[2];
1103 log_label_data.color[3] = utils_label->color[3];
1104 log_vector.push_back(log_label_data);
1105}
1106
Mark Young8504ba62018-03-21 13:35:34 -06001107static inline void BeginQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
1108 const VkDebugUtilsLabelEXT *label_info) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001109 if (nullptr != label_info && nullptr != label_info->pLabelName) {
1110 auto label_iter = report_data->debugUtilsQueueLabels->find(queue);
1111 if (label_iter == report_data->debugUtilsQueueLabels->end()) {
1112 std::vector<LoggingLabelData> new_queue_labels;
1113 InsertLabelIntoLog(label_info, new_queue_labels);
1114 report_data->debugUtilsQueueLabels->insert({queue, new_queue_labels});
1115 } else {
1116 // If the last thing was a label insert, we need to pop it off of the label vector before any
1117 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1118 // temporary location that exists until the next operation occurs. In this case, a new
1119 // "vkQueueBeginDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1120 if (report_data->queueLabelHasInsert) {
1121 report_data->queueLabelHasInsert = false;
1122 label_iter->second.pop_back();
1123 }
1124 InsertLabelIntoLog(label_info, label_iter->second);
1125 }
1126 }
1127}
1128
Mark Young8504ba62018-03-21 13:35:34 -06001129static inline void EndQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001130 auto label_iter = report_data->debugUtilsQueueLabels->find(queue);
1131 if (label_iter != report_data->debugUtilsQueueLabels->end()) {
1132 // If the last thing was a label insert, we need to pop it off of the label vector before any
1133 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1134 // temporary location that exists until the next operation occurs. In this case, a
1135 // "vkQueueEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
1136 if (report_data->queueLabelHasInsert) {
1137 report_data->queueLabelHasInsert = false;
1138 label_iter->second.pop_back();
1139 }
1140 // Now pop the normal item
1141 label_iter->second.pop_back();
1142 }
1143}
1144
Mark Young8504ba62018-03-21 13:35:34 -06001145static inline void InsertQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
1146 const VkDebugUtilsLabelEXT *label_info) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001147 if (nullptr != label_info && nullptr != label_info->pLabelName) {
1148 auto label_iter = report_data->debugUtilsQueueLabels->find(queue);
1149 if (label_iter == report_data->debugUtilsQueueLabels->end()) {
1150 std::vector<LoggingLabelData> new_queue_labels;
1151 InsertLabelIntoLog(label_info, new_queue_labels);
1152 report_data->debugUtilsQueueLabels->insert({queue, new_queue_labels});
1153 } else {
1154 // If the last thing was a label insert, we need to pop it off of the label vector before any
1155 // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1156 // temporary location that exists until the next operation occurs. In this case, a new
1157 // "vkQueueInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1158 if (report_data->queueLabelHasInsert) {
1159 label_iter->second.pop_back();
1160 }
1161 // Insert this new label and mark it as one that has been "inserted" so we can remove it on
1162 // the next queue label operation.
1163 InsertLabelIntoLog(label_info, label_iter->second);
1164 report_data->queueLabelHasInsert = true;
1165 }
1166 }
1167}
1168
Mark Young8504ba62018-03-21 13:35:34 -06001169static inline void BeginCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1170 const VkDebugUtilsLabelEXT *label_info) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001171 if (nullptr != label_info && nullptr != label_info->pLabelName) {
1172 auto label_iter = report_data->debugUtilsCmdBufLabels->find(command_buffer);
1173 if (label_iter == report_data->debugUtilsCmdBufLabels->end()) {
1174 std::vector<LoggingLabelData> new_cmdbuf_labels;
1175 InsertLabelIntoLog(label_info, new_cmdbuf_labels);
1176 report_data->debugUtilsCmdBufLabels->insert({command_buffer, new_cmdbuf_labels});
1177 } else {
1178 // If the last thing was a label insert, we need to pop it off of the label vector before any
1179 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1180 // temporary location that exists until the next operation occurs. In this case, a
1181 // "vkCmdBeginDebugUtilsLabelEXT" has occurred erasing the inserted label.
1182 if (report_data->cmdBufLabelHasInsert) {
1183 report_data->cmdBufLabelHasInsert = false;
1184 label_iter->second.pop_back();
1185 }
1186 InsertLabelIntoLog(label_info, label_iter->second);
1187 }
1188 }
1189}
1190
Mark Young8504ba62018-03-21 13:35:34 -06001191static inline void EndCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001192 auto label_iter = report_data->debugUtilsCmdBufLabels->find(command_buffer);
1193 if (label_iter != report_data->debugUtilsCmdBufLabels->end()) {
1194 // If the last thing was a label insert, we need to pop it off of the label vector before any
1195 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1196 // temporary location that exists until the next operation occurs. In this case, a
1197 // "vkCmdEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
1198 if (report_data->cmdBufLabelHasInsert) {
1199 report_data->cmdBufLabelHasInsert = false;
1200 label_iter->second.pop_back();
1201 }
Shahbaz Youssefi10b94a62019-01-09 23:00:15 -05001202 // Guard against unbalanced markers.
1203 if (label_iter->second.size() > 0) {
1204 // Now pop the normal item
1205 label_iter->second.pop_back();
1206 }
Mark Young6ba8abe2017-11-09 10:37:04 -07001207 }
1208}
1209
Mark Young8504ba62018-03-21 13:35:34 -06001210static inline void InsertCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1211 const VkDebugUtilsLabelEXT *label_info) {
Mark Young6ba8abe2017-11-09 10:37:04 -07001212 if (nullptr != label_info && nullptr != label_info->pLabelName) {
1213 auto label_iter = report_data->debugUtilsCmdBufLabels->find(command_buffer);
1214 if (label_iter == report_data->debugUtilsCmdBufLabels->end()) {
1215 std::vector<LoggingLabelData> new_cmdbuf_labels;
1216 InsertLabelIntoLog(label_info, new_cmdbuf_labels);
1217 report_data->debugUtilsCmdBufLabels->insert({command_buffer, new_cmdbuf_labels});
1218 } else {
1219 // If the last thing was a label insert, we need to pop it off of the label vector before any
1220 // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1221 // temporary location that exists until the next operation occurs. In this case, a new
1222 // "vkCmdInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1223 if (report_data->cmdBufLabelHasInsert) {
1224 label_iter->second.pop_back();
1225 }
1226 // Insert this new label and mark it as one that has been "inserted" so we can remove it on
1227 // the next command buffer label operation.
1228 InsertLabelIntoLog(label_info, label_iter->second);
1229 report_data->cmdBufLabelHasInsert = true;
1230 }
1231 }
1232}
Mark Lobodzinski863d5de2017-05-22 10:10:07 -06001233
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001234#endif // LAYER_LOGGING_H