1 /* Copyright (c) 2015-2017 The Khronos Group Inc.
2  * Copyright (c) 2015-2017 Valve Corporation
3  * Copyright (c) 2015-2017 LunarG, Inc.
4  *
5  * 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
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * 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.
16  *
17  * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
18  * Author: Tobin Ehlis <tobin@lunarg.com>
19  * Author: Mark Young <marky@lunarg.com>
20  *
21  */
22 
23 #ifndef LAYER_LOGGING_H
24 #define LAYER_LOGGING_H
25 
26 #include "vk_loader_layer.h"
27 #include "vk_layer_config.h"
28 #include "vk_layer_data.h"
29 #include "vk_layer_table.h"
30 #include "vk_loader_platform.h"
31 #include "vulkan/vk_layer.h"
32 #include "vk_object_types.h"
33 #include <signal.h>
34 #include <cinttypes>
35 #include <stdarg.h>
36 #include <stdbool.h>
37 #include <stdio.h>
38 #include <unordered_map>
39 #include <vector>
40 #include <sstream>
41 #include <string>
42 
43 // TODO: Could be autogenerated for the specific handles for extra type safety...
44 template <typename HANDLE_T>
HandleToUint64(HANDLE_T * h)45 static inline uint64_t HandleToUint64(HANDLE_T *h) {
46     return reinterpret_cast<uint64_t>(h);
47 }
48 
HandleToUint64(uint64_t h)49 static inline uint64_t HandleToUint64(uint64_t h) { return h; }
50 
51 // Data we store per label for logging
52 typedef struct _LoggingLabelData {
53     std::string name;
54     float color[4];
55 } LoggingLabelData;
56 
57 typedef struct _debug_report_data {
58     VkLayerDbgFunctionNode *debug_callback_list;
59     VkLayerDbgFunctionNode *default_debug_callback_list;
60     VkDebugUtilsMessageSeverityFlagsEXT active_severities;
61     VkDebugUtilsMessageTypeFlagsEXT active_types;
62     bool g_DEBUG_REPORT;
63     bool g_DEBUG_UTILS;
64     std::unordered_map<uint64_t, std::string> *debugObjectNameMap;
65     std::unordered_map<uint64_t, std::string> *debugUtilsObjectNameMap;
66     std::unordered_map<VkQueue, std::vector<LoggingLabelData>> *debugUtilsQueueLabels;
67     bool queueLabelHasInsert;
68     std::unordered_map<VkCommandBuffer, std::vector<LoggingLabelData>> *debugUtilsCmdBufLabels;
69     bool cmdBufLabelHasInsert;
70 } debug_report_data;
71 
72 template debug_report_data *GetLayerDataPtr<debug_report_data>(void *data_key,
73                                                                std::unordered_map<void *, debug_report_data *> &data_map);
74 
DebugReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags,bool default_flag_is_spec,VkDebugUtilsMessageSeverityFlagsEXT * da_severity,VkDebugUtilsMessageTypeFlagsEXT * da_type)75 static inline void DebugReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec,
76                                                 VkDebugUtilsMessageSeverityFlagsEXT *da_severity,
77                                                 VkDebugUtilsMessageTypeFlagsEXT *da_type) {
78     // All layer warnings are spec warnings currently.  At least as far as anything not specifically
79     // called out.  In the future, we'll label things using the new split severity and type values.
80     *da_type = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
81     *da_severity = 0;
82     if ((dr_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0) {
83         *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
84         *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
85     }
86     if ((dr_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0) {
87         *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
88         *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
89     }
90     if ((dr_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0) {
91         *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
92         *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
93     }
94     if ((dr_flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) != 0) {
95         *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
96     }
97     if ((dr_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) {
98         *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
99     }
100 }
101 
102 // Forward Declarations
103 static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
104                                  uint64_t src_object, size_t location, int32_t msg_code, const char *layer_prefix,
105                                  const char *message, const char *text_vuid = NULL);
106 
107 // Add a debug message callback node structure to the specified callback linked list
AddDebugCallbackNode(debug_report_data * debug_data,VkLayerDbgFunctionNode ** list_head,VkLayerDbgFunctionNode * new_node)108 static inline void AddDebugCallbackNode(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
109                                         VkLayerDbgFunctionNode *new_node) {
110     new_node->pNext = *list_head;
111     *list_head = new_node;
112 }
113 
114 // Remove specified debug messenger node structure from the specified linked list
RemoveDebugUtilsMessenger(debug_report_data * debug_data,VkLayerDbgFunctionNode ** list_head,VkDebugUtilsMessengerEXT messenger)115 static inline void RemoveDebugUtilsMessenger(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
116                                              VkDebugUtilsMessengerEXT messenger) {
117     VkLayerDbgFunctionNode *cur_callback = *list_head;
118     VkLayerDbgFunctionNode *prev_callback = cur_callback;
119     bool matched = false;
120     VkFlags local_severities = 0;
121     VkFlags local_types = 0;
122 
123     while (cur_callback) {
124         if (cur_callback->is_messenger && cur_callback->messenger.messenger == messenger) {
125             matched = true;
126             prev_callback->pNext = cur_callback->pNext;
127             if (*list_head == cur_callback) {
128                 *list_head = cur_callback->pNext;
129             }
130             debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
131                           reinterpret_cast<uint64_t &>(cur_callback->messenger.messenger), 0, 0, "DebugUtilsMessenger",
132                           "Destroyed messenger\n");
133         } else {
134             matched = false;
135             local_severities |= cur_callback->messenger.messageSeverity;
136             local_types |= cur_callback->messenger.messageType;
137         }
138         prev_callback = cur_callback;
139         cur_callback = cur_callback->pNext;
140         if (matched) {
141             free(prev_callback);
142         }
143     }
144     debug_data->active_severities = local_severities;
145     debug_data->active_types = local_types;
146 }
147 
148 // Remove specified debug message callback node structure from the specified callback linked list
RemoveDebugUtilsMessageCallback(debug_report_data * debug_data,VkLayerDbgFunctionNode ** list_head,VkDebugReportCallbackEXT callback)149 static inline void RemoveDebugUtilsMessageCallback(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
150                                                    VkDebugReportCallbackEXT callback) {
151     VkLayerDbgFunctionNode *cur_callback = *list_head;
152     VkLayerDbgFunctionNode *prev_callback = cur_callback;
153     bool matched = false;
154     VkFlags local_severities = 0;
155     VkFlags local_types = 0;
156 
157     while (cur_callback) {
158         if (!cur_callback->is_messenger && cur_callback->report.msgCallback == callback) {
159             matched = true;
160             prev_callback->pNext = cur_callback->pNext;
161             if (*list_head == cur_callback) {
162                 *list_head = cur_callback->pNext;
163             }
164             debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
165                           reinterpret_cast<uint64_t &>(cur_callback->report.msgCallback), 0, 0, "DebugReport",
166                           "Destroyed callback\n");
167         } else {
168             matched = false;
169             VkFlags this_severities = 0;
170             VkFlags this_types = 0;
171             DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types);
172             local_severities |= this_severities;
173             local_types |= this_types;
174         }
175         prev_callback = cur_callback;
176         cur_callback = cur_callback->pNext;
177         if (matched) {
178             free(prev_callback);
179         }
180     }
181     debug_data->active_severities = local_severities;
182     debug_data->active_types = local_types;
183 }
184 
185 // Removes all debug callback function nodes from the specified callback linked lists and frees their resources
RemoveAllMessageCallbacks(debug_report_data * debug_data,VkLayerDbgFunctionNode ** list_head)186 static inline void RemoveAllMessageCallbacks(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head) {
187     VkLayerDbgFunctionNode *current_callback = *list_head;
188     VkLayerDbgFunctionNode *prev_callback = current_callback;
189 
190     while (current_callback) {
191         prev_callback = current_callback->pNext;
192         if (!current_callback->is_messenger) {
193             debug_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
194                           (uint64_t)current_callback->report.msgCallback, 0, 0, "DebugReport",
195                           "Debug Report callbacks not removed before DestroyInstance");
196         } else {
197             debug_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
198                           (uint64_t)current_callback->messenger.messenger, 0, 0, "Messenger",
199                           "Debug messengers not removed before DestroyInstance");
200         }
201         free(current_callback);
202         current_callback = prev_callback;
203     }
204     *list_head = NULL;
205 }
206 
207 // Note that text_vuid is a default parameter, and is optional.  See the above forward declaration
debug_log_msg(const debug_report_data * debug_data,VkFlags msg_flags,VkDebugReportObjectTypeEXT object_type,uint64_t src_object,size_t location,int32_t msg_code,const char * layer_prefix,const char * message,const char * text_vuid)208 static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
209                                  uint64_t src_object, size_t location, int32_t msg_code, const char *layer_prefix,
210                                  const char *message, const char *text_vuid) {
211     bool bail = false;
212     VkLayerDbgFunctionNode *layer_dbg_node = NULL;
213 
214     if (debug_data->debug_callback_list != NULL) {
215         layer_dbg_node = debug_data->debug_callback_list;
216     } else {
217         layer_dbg_node = debug_data->default_debug_callback_list;
218     }
219 
220     VkDebugUtilsMessageSeverityFlagsEXT severity;
221     VkDebugUtilsMessageTypeFlagsEXT types;
222     VkDebugUtilsMessengerCallbackDataEXT callback_data;
223     VkDebugUtilsObjectNameInfoEXT object_name_info;
224 
225     // Convert the info to the VK_EXT_debug_utils form in case we need it.
226     DebugReportFlagsToAnnotFlags(msg_flags, true, &severity, &types);
227     object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
228     object_name_info.pNext = NULL;
229     object_name_info.objectType = convertDebugReportObjectToCoreObject(object_type);
230     object_name_info.objectHandle = (uint64_t)(uintptr_t)src_object;
231     object_name_info.pObjectName = NULL;
232 
233     callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
234     callback_data.pNext = NULL;
235     callback_data.flags = 0;
236     callback_data.pMessageIdName = text_vuid;
237     callback_data.messageIdNumber = msg_code;
238     callback_data.pMessage = message;
239     callback_data.queueLabelCount = 0;
240     callback_data.pQueueLabels = NULL;
241     callback_data.cmdBufLabelCount = 0;
242     callback_data.pCmdBufLabels = NULL;
243     callback_data.objectCount = 1;
244     callback_data.pObjects = &object_name_info;
245 
246     VkDebugUtilsLabelEXT *queue_labels = nullptr;
247     VkDebugUtilsLabelEXT *cmd_buf_labels = nullptr;
248     std::string new_debug_report_message = "";
249     std::ostringstream oss;
250 
251     if (0 != src_object) {
252         oss << "Object: 0x" << std::hex << src_object;
253         // If this is a queue, add any queue labels to the callback data.
254         if (VK_OBJECT_TYPE_QUEUE == object_name_info.objectType) {
255             auto label_iter = debug_data->debugUtilsQueueLabels->find(reinterpret_cast<VkQueue>(src_object));
256             if (label_iter != debug_data->debugUtilsQueueLabels->end()) {
257                 queue_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
258                 if (nullptr != queue_labels) {
259                     // Record the labels, but record them in reverse order since we want the
260                     // most recent at the top.
261                     uint32_t label_size = static_cast<uint32_t>(label_iter->second.size());
262                     uint32_t last_index = label_size - 1;
263                     for (uint32_t label = 0; label < label_size; ++label) {
264                         queue_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
265                         queue_labels[last_index - label].pNext = nullptr;
266                         queue_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
267                         queue_labels[last_index - label].color[0] = label_iter->second[label].color[0];
268                         queue_labels[last_index - label].color[1] = label_iter->second[label].color[1];
269                         queue_labels[last_index - label].color[2] = label_iter->second[label].color[2];
270                         queue_labels[last_index - label].color[3] = label_iter->second[label].color[3];
271                     }
272                     callback_data.queueLabelCount = label_size;
273                     callback_data.pQueueLabels = queue_labels;
274                 }
275             }
276             // If this is a command buffer, add any command buffer labels to the callback data.
277         } else if (VK_OBJECT_TYPE_COMMAND_BUFFER == object_name_info.objectType) {
278             auto label_iter = debug_data->debugUtilsCmdBufLabels->find(reinterpret_cast<VkCommandBuffer>(src_object));
279             if (label_iter != debug_data->debugUtilsCmdBufLabels->end()) {
280                 cmd_buf_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
281                 if (nullptr != cmd_buf_labels) {
282                     // Record the labels, but record them in reverse order since we want the
283                     // most recent at the top.
284                     uint32_t label_size = static_cast<uint32_t>(label_iter->second.size());
285                     uint32_t last_index = label_size - 1;
286                     for (uint32_t label = 0; label < label_size; ++label) {
287                         cmd_buf_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
288                         cmd_buf_labels[last_index - label].pNext = nullptr;
289                         cmd_buf_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
290                         cmd_buf_labels[last_index - label].color[0] = label_iter->second[label].color[0];
291                         cmd_buf_labels[last_index - label].color[1] = label_iter->second[label].color[1];
292                         cmd_buf_labels[last_index - label].color[2] = label_iter->second[label].color[2];
293                         cmd_buf_labels[last_index - label].color[3] = label_iter->second[label].color[3];
294                     }
295                     callback_data.cmdBufLabelCount = label_size;
296                     callback_data.pCmdBufLabels = cmd_buf_labels;
297                 }
298             }
299         }
300         // Look for any debug utils or marker names to use for this object
301         object_name_info.pObjectName = NULL;
302         auto utils_name_iter = debug_data->debugUtilsObjectNameMap->find(src_object);
303         if (utils_name_iter != debug_data->debugUtilsObjectNameMap->end()) {
304             object_name_info.pObjectName = utils_name_iter->second.c_str();
305         } else {
306             auto marker_name_iter = debug_data->debugObjectNameMap->find(src_object);
307             if (marker_name_iter != debug_data->debugObjectNameMap->end()) {
308                 object_name_info.pObjectName = marker_name_iter->second.c_str();
309             }
310         }
311         if (NULL != object_name_info.pObjectName) {
312             oss << " (Name = " << object_name_info.pObjectName << " : Type = ";
313         } else {
314             oss << " (Type = ";
315         }
316         oss << std::to_string(object_type) << ")";
317     } else {
318         oss << "Object: VK_NULL_HANDLE (Type = " << std::to_string(object_type) << ")";
319     }
320     new_debug_report_message += oss.str();
321     new_debug_report_message += " | ";
322     new_debug_report_message += message;
323 
324     while (layer_dbg_node) {
325         // If the app uses the VK_EXT_debug_report extension, call all of those registered callbacks.
326         if (!layer_dbg_node->is_messenger && (layer_dbg_node->report.msgFlags & msg_flags)) {
327             if (text_vuid != nullptr) {
328                 // If a text vuid is supplied for the old debug report extension, prepend it to the message string
329                 new_debug_report_message.insert(0, " ] ");
330                 new_debug_report_message.insert(0, text_vuid);
331                 new_debug_report_message.insert(0, " [ ");
332             }
333 
334             if (layer_dbg_node->report.pfnMsgCallback(msg_flags, object_type, src_object, location, msg_code, layer_prefix,
335                                                       new_debug_report_message.c_str(), layer_dbg_node->pUserData)) {
336                 bail = true;
337             }
338             // If the app uses the VK_EXT_debug_utils extension, call all of those registered callbacks.
339         } else if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & severity) &&
340                    (layer_dbg_node->messenger.messageType & types)) {
341             if (layer_dbg_node->messenger.pfnUserCallback(static_cast<VkDebugUtilsMessageSeverityFlagBitsEXT>(severity), types,
342                                                           &callback_data, layer_dbg_node->pUserData)) {
343                 bail = true;
344             }
345         }
346         layer_dbg_node = layer_dbg_node->pNext;
347     }
348 
349     if (nullptr != queue_labels) {
350         delete[] queue_labels;
351     }
352     if (nullptr != cmd_buf_labels) {
353         delete[] cmd_buf_labels;
354     }
355 
356     return bail;
357 }
358 
DebugAnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,VkDebugUtilsMessageTypeFlagsEXT da_type,VkDebugReportFlagsEXT * dr_flags)359 static inline void DebugAnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,
360                                                 VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags) {
361     *dr_flags = 0;
362 
363     if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) {
364         *dr_flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
365     } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) {
366         if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) {
367             *dr_flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
368         } else {
369             *dr_flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
370         }
371     } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) {
372         *dr_flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
373     } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) {
374         *dr_flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
375     }
376 }
377 
debug_messenger_log_msg(const debug_report_data * debug_data,VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,VkDebugUtilsMessageTypeFlagsEXT message_type,VkDebugUtilsMessengerCallbackDataEXT * callback_data,const VkDebugUtilsMessengerEXT * messenger)378 static inline bool debug_messenger_log_msg(const debug_report_data *debug_data,
379                                            VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
380                                            VkDebugUtilsMessageTypeFlagsEXT message_type,
381                                            VkDebugUtilsMessengerCallbackDataEXT *callback_data,
382                                            const VkDebugUtilsMessengerEXT *messenger) {
383     bool bail = false;
384     VkLayerDbgFunctionNode *layer_dbg_node = NULL;
385 
386     if (debug_data->debug_callback_list != NULL) {
387         layer_dbg_node = debug_data->debug_callback_list;
388     } else {
389         layer_dbg_node = debug_data->default_debug_callback_list;
390     }
391 
392     VkDebugReportFlagsEXT object_flags = 0;
393 
394     DebugAnnotFlagsToReportFlags(message_severity, message_type, &object_flags);
395 
396     VkDebugUtilsObjectNameInfoEXT object_name_info;
397     object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
398     object_name_info.pNext = NULL;
399     object_name_info.objectType = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT;
400     object_name_info.objectHandle = HandleToUint64(*messenger);
401     object_name_info.pObjectName = NULL;
402     callback_data->pObjects = &object_name_info;
403     callback_data->objectCount = 1;
404 
405     while (layer_dbg_node) {
406         if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & message_severity) &&
407             (layer_dbg_node->messenger.messageType & message_type)) {
408             auto it = debug_data->debugUtilsObjectNameMap->find(object_name_info.objectHandle);
409             if (it != debug_data->debugUtilsObjectNameMap->end()) {
410                 object_name_info.pObjectName = it->second.c_str();
411             }
412             if (layer_dbg_node->messenger.pfnUserCallback(message_severity, message_type, callback_data,
413                                                           layer_dbg_node->pUserData)) {
414                 bail = true;
415             }
416         } else if (!layer_dbg_node->is_messenger && layer_dbg_node->report.msgFlags & object_flags) {
417             auto it = debug_data->debugObjectNameMap->find(callback_data->pObjects[0].objectHandle);
418             VkDebugReportObjectTypeEXT object_type = convertCoreObjectToDebugReportObject(callback_data->pObjects[0].objectType);
419             if (it == debug_data->debugObjectNameMap->end()) {
420                 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
421                                                           callback_data->messageIdNumber, callback_data->pMessageIdName,
422                                                           callback_data->pMessage, layer_dbg_node->pUserData)) {
423                     bail = true;
424                 }
425             } else {
426                 std::string newMsg = "SrcObject name = ";
427                 newMsg.append(it->second.c_str());
428                 newMsg.append(" ");
429                 newMsg.append(callback_data->pMessage);
430                 if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
431                                                           callback_data->messageIdNumber, callback_data->pMessageIdName,
432                                                           newMsg.c_str(), layer_dbg_node->pUserData)) {
433                     bail = true;
434                 }
435             }
436         }
437         layer_dbg_node = layer_dbg_node->pNext;
438     }
439 
440     return bail;
441 }
442 
debug_utils_create_instance(VkLayerInstanceDispatchTable * table,VkInstance inst,uint32_t extension_count,const char * const * enabled_extensions)443 static inline debug_report_data *debug_utils_create_instance(
444     VkLayerInstanceDispatchTable *table, VkInstance inst, uint32_t extension_count,
445     const char *const *enabled_extensions)  // layer or extension name to be enabled
446 {
447     debug_report_data *debug_data = (debug_report_data *)malloc(sizeof(debug_report_data));
448     if (!debug_data) return NULL;
449 
450     memset(debug_data, 0, sizeof(debug_report_data));
451     for (uint32_t i = 0; i < extension_count; i++) {
452         // TODO: Check other property fields
453         if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
454             debug_data->g_DEBUG_REPORT = true;
455         } else if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
456             debug_data->g_DEBUG_UTILS = true;
457         }
458     }
459     debug_data->debugObjectNameMap = new std::unordered_map<uint64_t, std::string>;
460     debug_data->debugUtilsObjectNameMap = new std::unordered_map<uint64_t, std::string>;
461     debug_data->debugUtilsQueueLabels = new std::unordered_map<VkQueue, std::vector<LoggingLabelData>>;
462     debug_data->debugUtilsCmdBufLabels = new std::unordered_map<VkCommandBuffer, std::vector<LoggingLabelData>>;
463     debug_data->queueLabelHasInsert = false;
464     debug_data->cmdBufLabelHasInsert = false;
465     return debug_data;
466 }
467 
layer_debug_utils_destroy_instance(debug_report_data * debug_data)468 static inline void layer_debug_utils_destroy_instance(debug_report_data *debug_data) {
469     if (debug_data) {
470         RemoveAllMessageCallbacks(debug_data, &debug_data->default_debug_callback_list);
471         RemoveAllMessageCallbacks(debug_data, &debug_data->debug_callback_list);
472         delete debug_data->debugObjectNameMap;
473         delete debug_data->debugUtilsObjectNameMap;
474         delete debug_data->debugUtilsQueueLabels;
475         delete debug_data->debugUtilsCmdBufLabels;
476         free(debug_data);
477     }
478 }
479 
layer_debug_utils_create_device(debug_report_data * instance_debug_data,VkDevice device)480 static inline debug_report_data *layer_debug_utils_create_device(debug_report_data *instance_debug_data, VkDevice device) {
481     // DEBUG_REPORT shares data between Instance and Device,
482     // so just return instance's data pointer
483     return instance_debug_data;
484 }
485 
layer_debug_utils_destroy_device(VkDevice device)486 static inline void layer_debug_utils_destroy_device(VkDevice device) {
487     // Nothing to do since we're using instance data record
488 }
489 
layer_destroy_messenger_callback(debug_report_data * debug_data,VkDebugUtilsMessengerEXT messenger,const VkAllocationCallbacks * allocator)490 static inline void layer_destroy_messenger_callback(debug_report_data *debug_data, VkDebugUtilsMessengerEXT messenger,
491                                                     const VkAllocationCallbacks *allocator) {
492     RemoveDebugUtilsMessenger(debug_data, &debug_data->debug_callback_list, messenger);
493     RemoveDebugUtilsMessenger(debug_data, &debug_data->default_debug_callback_list, messenger);
494 }
495 
layer_create_messenger_callback(debug_report_data * debug_data,bool default_callback,const VkDebugUtilsMessengerCreateInfoEXT * create_info,const VkAllocationCallbacks * allocator,VkDebugUtilsMessengerEXT * messenger)496 static inline VkResult layer_create_messenger_callback(debug_report_data *debug_data, bool default_callback,
497                                                        const VkDebugUtilsMessengerCreateInfoEXT *create_info,
498                                                        const VkAllocationCallbacks *allocator,
499                                                        VkDebugUtilsMessengerEXT *messenger) {
500     VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
501     if (!pNewDbgFuncNode) return VK_ERROR_OUT_OF_HOST_MEMORY;
502     memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
503     pNewDbgFuncNode->is_messenger = true;
504 
505     // Handle of 0 is logging_callback so use allocated Node address as unique handle
506     if (!(*messenger)) *messenger = (VkDebugUtilsMessengerEXT)pNewDbgFuncNode;
507     pNewDbgFuncNode->messenger.messenger = *messenger;
508     pNewDbgFuncNode->messenger.pfnUserCallback = create_info->pfnUserCallback;
509     pNewDbgFuncNode->messenger.messageSeverity = create_info->messageSeverity;
510     pNewDbgFuncNode->messenger.messageType = create_info->messageType;
511     pNewDbgFuncNode->pUserData = create_info->pUserData;
512 
513     debug_data->active_severities |= create_info->messageSeverity;
514     debug_data->active_types |= create_info->messageType;
515     if (default_callback) {
516         AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
517     } else {
518         AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
519     }
520 
521     VkDebugUtilsMessengerCallbackDataEXT callback_data = {};
522     callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
523     callback_data.pNext = NULL;
524     callback_data.flags = 0;
525     callback_data.pMessageIdName = "Layer Internal Message";
526     callback_data.messageIdNumber = 0;
527     callback_data.pMessage = "Added messenger";
528     callback_data.queueLabelCount = 0;
529     callback_data.pQueueLabels = NULL;
530     callback_data.cmdBufLabelCount = 0;
531     callback_data.pCmdBufLabels = NULL;
532     callback_data.objectCount = 0;
533     callback_data.pObjects = NULL;
534     debug_messenger_log_msg(debug_data, VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
535                             VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, &callback_data, messenger);
536     return VK_SUCCESS;
537 }
538 
layer_destroy_report_callback(debug_report_data * debug_data,VkDebugReportCallbackEXT callback,const VkAllocationCallbacks * allocator)539 static inline void layer_destroy_report_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback,
540                                                  const VkAllocationCallbacks *allocator) {
541     RemoveDebugUtilsMessageCallback(debug_data, &debug_data->debug_callback_list, callback);
542     RemoveDebugUtilsMessageCallback(debug_data, &debug_data->default_debug_callback_list, callback);
543 }
544 
layer_create_report_callback(debug_report_data * debug_data,bool default_callback,const VkDebugReportCallbackCreateInfoEXT * create_info,const VkAllocationCallbacks * allocator,VkDebugReportCallbackEXT * callback)545 static inline VkResult layer_create_report_callback(debug_report_data *debug_data, bool default_callback,
546                                                     const VkDebugReportCallbackCreateInfoEXT *create_info,
547                                                     const VkAllocationCallbacks *allocator, VkDebugReportCallbackEXT *callback) {
548     VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
549     if (!pNewDbgFuncNode) {
550         return VK_ERROR_OUT_OF_HOST_MEMORY;
551     }
552     memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
553     pNewDbgFuncNode->is_messenger = false;
554 
555     // Handle of 0 is logging_callback so use allocated Node address as unique handle
556     if (!(*callback)) *callback = (VkDebugReportCallbackEXT)pNewDbgFuncNode;
557     pNewDbgFuncNode->report.msgCallback = *callback;
558     pNewDbgFuncNode->report.pfnMsgCallback = create_info->pfnCallback;
559     pNewDbgFuncNode->report.msgFlags = create_info->flags;
560     pNewDbgFuncNode->pUserData = create_info->pUserData;
561 
562     VkFlags local_severity = 0;
563     VkFlags local_type = 0;
564     DebugReportFlagsToAnnotFlags(create_info->flags, true, &local_severity, &local_type);
565     debug_data->active_severities |= local_severity;
566     debug_data->active_types |= local_type;
567     if (default_callback) {
568         AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
569     } else {
570         AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
571     }
572 
573     debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, (uint64_t)*callback, 0,
574                   0, "DebugReport", "Added callback");
575     return VK_SUCCESS;
576 }
577 
debug_utils_get_instance_proc_addr(debug_report_data * debug_data,const char * func_name)578 static inline PFN_vkVoidFunction debug_utils_get_instance_proc_addr(debug_report_data *debug_data, const char *func_name) {
579     if (!debug_data) {
580         return NULL;
581     }
582     if (debug_data->g_DEBUG_REPORT) {
583         if (!strcmp(func_name, "vkCreateDebugReportCallbackEXT")) {
584             return (PFN_vkVoidFunction)vkCreateDebugReportCallbackEXT;
585         }
586         if (!strcmp(func_name, "vkDestroyDebugReportCallbackEXT")) {
587             return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT;
588         }
589         if (!strcmp(func_name, "vkDebugReportMessageEXT")) {
590             return (PFN_vkVoidFunction)vkDebugReportMessageEXT;
591         }
592     }
593     if (debug_data->g_DEBUG_UTILS) {
594         if (!strcmp(func_name, "vkCreateDebugUtilsMessengerEXT")) {
595             return (PFN_vkVoidFunction)vkCreateDebugUtilsMessengerEXT;
596         }
597         if (!strcmp(func_name, "vkDestroyDebugUtilsMessengerEXT")) {
598             return (PFN_vkVoidFunction)vkDestroyDebugUtilsMessengerEXT;
599         }
600         if (!strcmp(func_name, "vkSubmitDebugUtilsMessageEXT")) {
601             return (PFN_vkVoidFunction)vkSubmitDebugUtilsMessageEXT;
602         }
603     }
604     return NULL;
605 }
606 
607 // This utility (called at vkCreateInstance() time), looks at a pNext chain.
608 // It counts any VkDebugReportCallbackCreateInfoEXT structs that it finds.  It
609 // then allocates an array that can hold that many structs, as well as that
610 // many VkDebugReportCallbackEXT handles.  It then copies each
611 // VkDebugReportCallbackCreateInfoEXT, and initializes each handle.
layer_copy_tmp_report_callbacks(const void * pChain,uint32_t * num_callbacks,VkDebugReportCallbackCreateInfoEXT ** infos,VkDebugReportCallbackEXT ** callbacks)612 static inline VkResult layer_copy_tmp_report_callbacks(const void *pChain, uint32_t *num_callbacks,
613                                                        VkDebugReportCallbackCreateInfoEXT **infos,
614                                                        VkDebugReportCallbackEXT **callbacks) {
615     uint32_t n = *num_callbacks = 0;
616 
617     const void *pNext = pChain;
618     while (pNext) {
619         // 1st, count the number VkDebugReportCallbackCreateInfoEXT:
620         if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
621             n++;
622         }
623         pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext;
624     }
625     if (n == 0) {
626         return VK_SUCCESS;
627     }
628 
629     // 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT:
630     VkDebugReportCallbackCreateInfoEXT *pInfos = *infos =
631         ((VkDebugReportCallbackCreateInfoEXT *)malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT)));
632     if (!pInfos) {
633         return VK_ERROR_OUT_OF_HOST_MEMORY;
634     }
635     // 3rd, allocate memory for a unique handle for each callback:
636     VkDebugReportCallbackEXT *pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)malloc(n * sizeof(VkDebugReportCallbackEXT)));
637     if (!pCallbacks) {
638         free(pInfos);
639         return VK_ERROR_OUT_OF_HOST_MEMORY;
640     }
641     // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by
642     // vkDestroyInstance, and assign a unique handle to each callback (just
643     // use the address of the copied VkDebugReportCallbackCreateInfoEXT):
644     pNext = pChain;
645     while (pNext) {
646         if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
647             memcpy(pInfos, pNext, sizeof(VkDebugReportCallbackCreateInfoEXT));
648             *pCallbacks++ = (VkDebugReportCallbackEXT)pInfos++;
649         }
650         pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
651     }
652 
653     *num_callbacks = n;
654     return VK_SUCCESS;
655 }
656 
657 // This utility frees the arrays allocated by layer_copy_tmp_report_callbacks()
layer_free_tmp_report_callbacks(VkDebugReportCallbackCreateInfoEXT * infos,VkDebugReportCallbackEXT * callbacks)658 static inline void layer_free_tmp_report_callbacks(VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) {
659     free(infos);
660     free(callbacks);
661 }
662 
663 // This utility enables all of the VkDebugReportCallbackCreateInfoEXT structs
664 // that were copied by layer_copy_tmp_report_callbacks()
layer_enable_tmp_report_callbacks(debug_report_data * debug_data,uint32_t num_callbacks,VkDebugReportCallbackCreateInfoEXT * infos,VkDebugReportCallbackEXT * callbacks)665 static inline VkResult layer_enable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
666                                                          VkDebugReportCallbackCreateInfoEXT *infos,
667                                                          VkDebugReportCallbackEXT *callbacks) {
668     VkResult rtn = VK_SUCCESS;
669     for (uint32_t i = 0; i < num_callbacks; i++) {
670         rtn = layer_create_report_callback(debug_data, false, &infos[i], NULL, &callbacks[i]);
671         if (rtn != VK_SUCCESS) {
672             for (uint32_t j = 0; j < i; j++) {
673                 layer_destroy_report_callback(debug_data, callbacks[j], NULL);
674             }
675             return rtn;
676         }
677     }
678     return rtn;
679 }
680 
681 // This utility disables all of the VkDebugReportCallbackCreateInfoEXT structs
682 // that were copied by layer_copy_tmp_report_callbacks()
layer_disable_tmp_report_callbacks(debug_report_data * debug_data,uint32_t num_callbacks,VkDebugReportCallbackEXT * callbacks)683 static inline void layer_disable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
684                                                       VkDebugReportCallbackEXT *callbacks) {
685     for (uint32_t i = 0; i < num_callbacks; i++) {
686         layer_destroy_report_callback(debug_data, callbacks[i], NULL);
687     }
688 }
689 
690 // This utility (called at vkCreateInstance() time), looks at a pNext chain.
691 // It counts any VkDebugUtilsMessengerCreateInfoEXT structs that it finds.  It
692 // then allocates an array that can hold that many structs, as well as that
693 // many VkDebugUtilsMessengerEXT handles.  It then copies each
694 // VkDebugUtilsMessengerCreateInfoEXT, and initializes each handle.
layer_copy_tmp_debug_messengers(const void * pChain,uint32_t * num_messengers,VkDebugUtilsMessengerCreateInfoEXT ** infos,VkDebugUtilsMessengerEXT ** messengers)695 static inline VkResult layer_copy_tmp_debug_messengers(const void *pChain, uint32_t *num_messengers,
696                                                        VkDebugUtilsMessengerCreateInfoEXT **infos,
697                                                        VkDebugUtilsMessengerEXT **messengers) {
698     uint32_t n = *num_messengers = 0;
699 
700     const void *pNext = pChain;
701     while (pNext) {
702         // 1st, count the number VkDebugUtilsMessengerCreateInfoEXT:
703         if (((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
704             n++;
705         }
706         pNext = (void *)((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->pNext;
707     }
708     if (n == 0) {
709         return VK_SUCCESS;
710     }
711 
712     // 2nd, allocate memory for each VkDebugUtilsMessengerCreateInfoEXT:
713     VkDebugUtilsMessengerCreateInfoEXT *pInfos = *infos =
714         ((VkDebugUtilsMessengerCreateInfoEXT *)malloc(n * sizeof(VkDebugUtilsMessengerCreateInfoEXT)));
715     if (!pInfos) {
716         return VK_ERROR_OUT_OF_HOST_MEMORY;
717     }
718     // 3rd, allocate memory for a unique handle for each messenger:
719     VkDebugUtilsMessengerEXT *pMessengers = *messengers =
720         ((VkDebugUtilsMessengerEXT *)malloc(n * sizeof(VkDebugUtilsMessengerEXT)));
721     if (!pMessengers) {
722         free(pInfos);
723         return VK_ERROR_OUT_OF_HOST_MEMORY;
724     }
725     // 4th, copy each VkDebugUtilsMessengerCreateInfoEXT for use by
726     // vkDestroyInstance, and assign a unique handle to each callback (just
727     // use the address of the copied VkDebugUtilsMessengerCreateInfoEXT):
728     pNext = pChain;
729     while (pNext) {
730         if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
731             memcpy(pInfos, pNext, sizeof(VkDebugUtilsMessengerCreateInfoEXT));
732             *pMessengers++ = (VkDebugUtilsMessengerEXT)pInfos++;
733         }
734         pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
735     }
736 
737     *num_messengers = n;
738     return VK_SUCCESS;
739 }
740 
741 // This utility frees the arrays allocated by layer_copy_tmp_debug_messengers()
layer_free_tmp_debug_messengers(VkDebugUtilsMessengerCreateInfoEXT * infos,VkDebugUtilsMessengerEXT * messengers)742 static inline void layer_free_tmp_debug_messengers(VkDebugUtilsMessengerCreateInfoEXT *infos,
743                                                    VkDebugUtilsMessengerEXT *messengers) {
744     free(infos);
745     free(messengers);
746 }
747 
748 // This utility enables all of the VkDebugUtilsMessengerCreateInfoEXT structs
749 // that were copied by layer_copy_tmp_debug_messengers()
layer_enable_tmp_debug_messengers(debug_report_data * debug_data,uint32_t num_messengers,VkDebugUtilsMessengerCreateInfoEXT * infos,VkDebugUtilsMessengerEXT * messengers)750 static inline VkResult layer_enable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
751                                                          VkDebugUtilsMessengerCreateInfoEXT *infos,
752                                                          VkDebugUtilsMessengerEXT *messengers) {
753     VkResult rtn = VK_SUCCESS;
754     for (uint32_t i = 0; i < num_messengers; i++) {
755         rtn = layer_create_messenger_callback(debug_data, false, &infos[i], NULL, &messengers[i]);
756         if (rtn != VK_SUCCESS) {
757             for (uint32_t j = 0; j < i; j++) {
758                 layer_destroy_messenger_callback(debug_data, messengers[j], NULL);
759             }
760             return rtn;
761         }
762     }
763     return rtn;
764 }
765 
766 // This utility disables all of the VkDebugUtilsMessengerCreateInfoEXT structs
767 // that were copied by layer_copy_tmp_debug_messengers()
layer_disable_tmp_debug_messengers(debug_report_data * debug_data,uint32_t num_messengers,VkDebugUtilsMessengerEXT * messengers)768 static inline void layer_disable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
769                                                       VkDebugUtilsMessengerEXT *messengers) {
770     for (uint32_t i = 0; i < num_messengers; i++) {
771         layer_destroy_messenger_callback(debug_data, messengers[i], NULL);
772     }
773 }
774 
775 // Checks if the message will get logged.
776 // Allows layer to defer collecting & formating data if the
777 // message will be discarded.
will_log_msg(debug_report_data * debug_data,VkFlags msg_flags)778 static inline bool will_log_msg(debug_report_data *debug_data, VkFlags msg_flags) {
779     VkFlags local_severity = 0;
780     VkFlags local_type = 0;
781     DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
782     if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
783         // Message is not wanted
784         return false;
785     }
786 
787     return true;
788 }
789 #ifndef WIN32
790 static inline int string_sprintf(std::string *output, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
791 #endif
string_sprintf(std::string * output,const char * fmt,...)792 static inline int string_sprintf(std::string *output, const char *fmt, ...) {
793     std::string &formatted = *output;
794     va_list argptr;
795     va_start(argptr, fmt);
796     int reserve = vsnprintf(nullptr, 0, fmt, argptr);
797     va_end(argptr);
798     formatted.reserve(reserve + 1);
799     va_start(argptr, fmt);
800     int result = vsnprintf((char *)formatted.data(), formatted.capacity(), fmt, argptr);
801     va_end(argptr);
802     assert(result == reserve);
803     return result;
804 }
805 
806 #ifdef WIN32
vasprintf(char ** strp,char const * fmt,va_list ap)807 static inline int vasprintf(char **strp, char const *fmt, va_list ap) {
808     *strp = nullptr;
809     int size = _vscprintf(fmt, ap);
810     if (size >= 0) {
811         *strp = (char *)malloc(size + 1);
812         if (!*strp) {
813             return -1;
814         }
815         _vsnprintf(*strp, size + 1, fmt, ap);
816     }
817     return size;
818 }
819 #endif
820 
821 // Output log message via DEBUG_REPORT. Takes format and variable arg list so that output string is only computed if a message
822 // needs to be logged
823 #ifndef WIN32
824 static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
825                            uint64_t src_object, int32_t msg_code, const char *format, ...) __attribute__((format(printf, 6, 7)));
826 static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
827                            uint64_t src_object, std::string vuid_text, const char *format, ...)
828     __attribute__((format(printf, 6, 7)));
829 #endif
log_msg(const debug_report_data * debug_data,VkFlags msg_flags,VkDebugReportObjectTypeEXT object_type,uint64_t src_object,int32_t msg_code,const char * format,...)830 static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
831                            uint64_t src_object, int32_t msg_code, const char *format, ...) {
832     VkFlags local_severity = 0;
833     VkFlags local_type = 0;
834     DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
835     if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
836         // Message is not wanted
837         return false;
838     }
839 
840     va_list argptr;
841     va_start(argptr, format);
842     char *str;
843     if (-1 == vasprintf(&str, format, argptr)) {
844         // On failure, glibc vasprintf leaves str undefined
845         str = nullptr;
846     }
847     va_end(argptr);
848 
849     std::string str_plus_spec_text(str);
850 
851     bool result = debug_log_msg(debug_data, msg_flags, object_type, src_object, 0, msg_code, "Validation",
852                                 str_plus_spec_text.c_str() ? str_plus_spec_text.c_str() : "Allocation failure");
853     free(str);
854     return result;
855 }
856 
857 // Overload of log_msg that takes a VUID string in place of a numerical VUID abstraction
log_msg(const debug_report_data * debug_data,VkFlags msg_flags,VkDebugReportObjectTypeEXT object_type,uint64_t src_object,std::string vuid_text,const char * format,...)858 static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
859                            uint64_t src_object, std::string vuid_text, const char *format, ...) {
860     VkFlags local_severity = 0;
861     VkFlags local_type = 0;
862     DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
863     if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
864         // Message is not wanted
865         return false;
866     }
867 
868     va_list argptr;
869     va_start(argptr, format);
870     char *str;
871     if (-1 == vasprintf(&str, format, argptr)) {
872         // On failure, glibc vasprintf leaves str undefined
873         str = nullptr;
874     }
875     va_end(argptr);
876 
877     std::string str_plus_spec_text(str);
878 
879     // Append layer prefix with VUID string, pass in UNDEFINED for numerical VUID
880     static const int UNDEFINED_VUID = -1;
881     bool result = debug_log_msg(debug_data, msg_flags, object_type, src_object, 0, UNDEFINED_VUID, "Validation",
882                                 str_plus_spec_text.c_str() ? str_plus_spec_text.c_str() : "Allocation failure", vuid_text.c_str());
883 
884     free(str);
885     return result;
886 }
887 
report_log_callback(VkFlags msg_flags,VkDebugReportObjectTypeEXT obj_type,uint64_t src_object,size_t location,int32_t msg_code,const char * layer_prefix,const char * message,void * user_data)888 static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_log_callback(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
889                                                                  uint64_t src_object, size_t location, int32_t msg_code,
890                                                                  const char *layer_prefix, const char *message, void *user_data) {
891     char msg_flag_string[30];
892 
893     PrintMessageFlags(msg_flags, msg_flag_string);
894 
895     fprintf((FILE *)user_data, "%s(%s): msg_code: %d: %s\n", layer_prefix, msg_flag_string, msg_code, message);
896     fflush((FILE *)user_data);
897 
898     return false;
899 }
900 
report_win32_debug_output_msg(VkFlags msg_flags,VkDebugReportObjectTypeEXT obj_type,uint64_t src_object,size_t location,int32_t msg_code,const char * layer_prefix,const char * message,void * user_data)901 static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_win32_debug_output_msg(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
902                                                                            uint64_t src_object, size_t location, int32_t msg_code,
903                                                                            const char *layer_prefix, const char *message,
904                                                                            void *user_data) {
905 #ifdef WIN32
906     char msg_flag_string[30];
907     char buf[2048];
908 
909     PrintMessageFlags(msg_flags, msg_flag_string);
910     _snprintf(buf, sizeof(buf) - 1, "%s (%s): msg_code: %d: %s\n", layer_prefix, msg_flag_string, msg_code, message);
911 
912     OutputDebugString(buf);
913 #endif
914 
915     return false;
916 }
917 
DebugBreakCallback(VkFlags msgFlags,VkDebugReportObjectTypeEXT obj_type,uint64_t src_object,size_t location,int32_t msg_code,const char * layer_prefix,const char * message,void * user_data)918 static inline VKAPI_ATTR VkBool32 VKAPI_CALL DebugBreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT obj_type,
919                                                                 uint64_t src_object, size_t location, int32_t msg_code,
920                                                                 const char *layer_prefix, const char *message, void *user_data) {
921 #ifdef WIN32
922     DebugBreak();
923 #else
924     raise(SIGTRAP);
925 #endif
926 
927     return false;
928 }
929 
messenger_log_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,VkDebugUtilsMessageTypeFlagsEXT message_type,const VkDebugUtilsMessengerCallbackDataEXT * callback_data,void * user_data)930 static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_log_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
931                                                                     VkDebugUtilsMessageTypeFlagsEXT message_type,
932                                                                     const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
933                                                                     void *user_data) {
934     char msg_severity[30];
935     char msg_type[30];
936 
937     PrintMessageSeverity(message_severity, msg_severity);
938     PrintMessageType(message_type, msg_type);
939 
940     fprintf((FILE *)user_data, "%s(%s / %s): msgNum: %d - %s\n", callback_data->pMessageIdName, msg_severity, msg_type,
941             callback_data->messageIdNumber, callback_data->pMessage);
942     fprintf((FILE *)user_data, "    Objects: %d\n", callback_data->objectCount);
943     for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
944         fprintf((FILE *)user_data, "       [%d] 0x%" PRIx64 ", type: %d, name: %s\n", obj,
945                 callback_data->pObjects[obj].objectHandle, callback_data->pObjects[obj].objectType,
946                 callback_data->pObjects[obj].pObjectName);
947     }
948     fflush((FILE *)user_data);
949 
950     return false;
951 }
952 
messenger_win32_debug_output_msg(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,VkDebugUtilsMessageTypeFlagsEXT message_type,const VkDebugUtilsMessengerCallbackDataEXT * callback_data,void * user_data)953 static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_win32_debug_output_msg(
954     VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type,
955     const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data) {
956 #ifdef WIN32
957     char buf[2048];
958     char msg_severity[30];
959     char msg_type[30];
960 
961     PrintMessageSeverity(message_severity, msg_severity);
962     PrintMessageType(message_type, msg_type);
963 
964     size_t buffer_space = sizeof(buf) - 1;
965     size_t remaining_space = buffer_space;
966     _snprintf(buf, sizeof(buf) - 1, "%s(%s / %s): msgNum: %d - %s\n", callback_data->pMessageIdName, msg_severity, msg_type,
967               callback_data->messageIdNumber, callback_data->pMessage);
968     remaining_space = buffer_space - strlen(buf);
969     _snprintf(buf, remaining_space, "    Objects: %d\n", callback_data->objectCount);
970     for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
971         remaining_space = buffer_space - strlen(buf);
972         if (remaining_space > 0) {
973             _snprintf(buf, remaining_space, "       [%d] 0x%" PRIx64 ", type: %d, name: %s\n", obj,
974                       callback_data->pObjects[obj].objectHandle, callback_data->pObjects[obj].objectType,
975                       callback_data->pObjects[obj].pObjectName);
976         }
977     }
978     OutputDebugString(buf);
979 #endif
980 
981     return false;
982 }
983 
984 // This utility converts from the VkDebugUtilsLabelEXT structure into the logging version of the structure.
985 // In the logging version, we only record what we absolutely need to convey back to the callbacks.
InsertLabelIntoLog(const VkDebugUtilsLabelEXT * utils_label,std::vector<LoggingLabelData> & log_vector)986 static inline void InsertLabelIntoLog(const VkDebugUtilsLabelEXT *utils_label, std::vector<LoggingLabelData> &log_vector) {
987     LoggingLabelData log_label_data = {};
988     log_label_data.name = utils_label->pLabelName;
989     log_label_data.color[0] = utils_label->color[0];
990     log_label_data.color[1] = utils_label->color[1];
991     log_label_data.color[2] = utils_label->color[2];
992     log_label_data.color[3] = utils_label->color[3];
993     log_vector.push_back(log_label_data);
994 }
995 
BeginQueueDebugUtilsLabel(debug_report_data * report_data,VkQueue queue,const VkDebugUtilsLabelEXT * label_info)996 static inline void BeginQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
997                                              const VkDebugUtilsLabelEXT *label_info) {
998     if (nullptr != label_info && nullptr != label_info->pLabelName) {
999         auto label_iter = report_data->debugUtilsQueueLabels->find(queue);
1000         if (label_iter == report_data->debugUtilsQueueLabels->end()) {
1001             std::vector<LoggingLabelData> new_queue_labels;
1002             InsertLabelIntoLog(label_info, new_queue_labels);
1003             report_data->debugUtilsQueueLabels->insert({queue, new_queue_labels});
1004         } else {
1005             // If the last thing was a label insert, we need to pop it off of the label vector before any
1006             // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1007             // temporary location that exists until the next operation occurs.  In this case, a new
1008             // "vkQueueBeginDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1009             if (report_data->queueLabelHasInsert) {
1010                 report_data->queueLabelHasInsert = false;
1011                 label_iter->second.pop_back();
1012             }
1013             InsertLabelIntoLog(label_info, label_iter->second);
1014         }
1015     }
1016 }
1017 
EndQueueDebugUtilsLabel(debug_report_data * report_data,VkQueue queue)1018 static inline void EndQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue) {
1019     auto label_iter = report_data->debugUtilsQueueLabels->find(queue);
1020     if (label_iter != report_data->debugUtilsQueueLabels->end()) {
1021         // If the last thing was a label insert, we need to pop it off of the label vector before any
1022         // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1023         // temporary location that exists until the next operation occurs.  In this case, a
1024         // "vkQueueEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
1025         if (report_data->queueLabelHasInsert) {
1026             report_data->queueLabelHasInsert = false;
1027             label_iter->second.pop_back();
1028         }
1029         // Now pop the normal item
1030         label_iter->second.pop_back();
1031     }
1032 }
1033 
InsertQueueDebugUtilsLabel(debug_report_data * report_data,VkQueue queue,const VkDebugUtilsLabelEXT * label_info)1034 static inline void InsertQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue,
1035                                               const VkDebugUtilsLabelEXT *label_info) {
1036     if (nullptr != label_info && nullptr != label_info->pLabelName) {
1037         auto label_iter = report_data->debugUtilsQueueLabels->find(queue);
1038         if (label_iter == report_data->debugUtilsQueueLabels->end()) {
1039             std::vector<LoggingLabelData> new_queue_labels;
1040             InsertLabelIntoLog(label_info, new_queue_labels);
1041             report_data->debugUtilsQueueLabels->insert({queue, new_queue_labels});
1042         } else {
1043             // If the last thing was a label insert, we need to pop it off of the label vector before any
1044             // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
1045             // temporary location that exists until the next operation occurs.  In this case, a new
1046             // "vkQueueInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1047             if (report_data->queueLabelHasInsert) {
1048                 label_iter->second.pop_back();
1049             }
1050             // Insert this new label and mark it as one that has been "inserted" so we can remove it on
1051             // the next queue label operation.
1052             InsertLabelIntoLog(label_info, label_iter->second);
1053             report_data->queueLabelHasInsert = true;
1054         }
1055     }
1056 }
1057 
BeginCmdDebugUtilsLabel(debug_report_data * report_data,VkCommandBuffer command_buffer,const VkDebugUtilsLabelEXT * label_info)1058 static inline void BeginCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1059                                            const VkDebugUtilsLabelEXT *label_info) {
1060     if (nullptr != label_info && nullptr != label_info->pLabelName) {
1061         auto label_iter = report_data->debugUtilsCmdBufLabels->find(command_buffer);
1062         if (label_iter == report_data->debugUtilsCmdBufLabels->end()) {
1063             std::vector<LoggingLabelData> new_cmdbuf_labels;
1064             InsertLabelIntoLog(label_info, new_cmdbuf_labels);
1065             report_data->debugUtilsCmdBufLabels->insert({command_buffer, new_cmdbuf_labels});
1066         } else {
1067             // If the last thing was a label insert, we need to pop it off of the label vector before any
1068             // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1069             // temporary location that exists until the next operation occurs.  In this case, a
1070             // "vkCmdBeginDebugUtilsLabelEXT" has occurred erasing the inserted label.
1071             if (report_data->cmdBufLabelHasInsert) {
1072                 report_data->cmdBufLabelHasInsert = false;
1073                 label_iter->second.pop_back();
1074             }
1075             InsertLabelIntoLog(label_info, label_iter->second);
1076         }
1077     }
1078 }
1079 
EndCmdDebugUtilsLabel(debug_report_data * report_data,VkCommandBuffer command_buffer)1080 static inline void EndCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
1081     auto label_iter = report_data->debugUtilsCmdBufLabels->find(command_buffer);
1082     if (label_iter != report_data->debugUtilsCmdBufLabels->end()) {
1083         // If the last thing was a label insert, we need to pop it off of the label vector before any
1084         // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1085         // temporary location that exists until the next operation occurs.  In this case, a
1086         // "vkCmdEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
1087         if (report_data->cmdBufLabelHasInsert) {
1088             report_data->cmdBufLabelHasInsert = false;
1089             label_iter->second.pop_back();
1090         }
1091         // Now pop the normal item
1092         label_iter->second.pop_back();
1093     }
1094 }
1095 
InsertCmdDebugUtilsLabel(debug_report_data * report_data,VkCommandBuffer command_buffer,const VkDebugUtilsLabelEXT * label_info)1096 static inline void InsertCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
1097                                             const VkDebugUtilsLabelEXT *label_info) {
1098     if (nullptr != label_info && nullptr != label_info->pLabelName) {
1099         auto label_iter = report_data->debugUtilsCmdBufLabels->find(command_buffer);
1100         if (label_iter == report_data->debugUtilsCmdBufLabels->end()) {
1101             std::vector<LoggingLabelData> new_cmdbuf_labels;
1102             InsertLabelIntoLog(label_info, new_cmdbuf_labels);
1103             report_data->debugUtilsCmdBufLabels->insert({command_buffer, new_cmdbuf_labels});
1104         } else {
1105             // If the last thing was a label insert, we need to pop it off of the label vector before any
1106             // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
1107             // temporary location that exists until the next operation occurs.  In this case, a new
1108             // "vkCmdInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
1109             if (report_data->cmdBufLabelHasInsert) {
1110                 label_iter->second.pop_back();
1111             }
1112             // Insert this new label and mark it as one that has been "inserted" so we can remove it on
1113             // the next command buffer label operation.
1114             InsertLabelIntoLog(label_info, label_iter->second);
1115             report_data->cmdBufLabelHasInsert = true;
1116         }
1117     }
1118 }
1119 
1120 #endif  // LAYER_LOGGING_H
1121