• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2015-2016 The Khronos Group Inc.
2  * Copyright (c) 2015-2016 Valve Corporation
3  * Copyright (c) 2015-2016 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  *
20  */
21 
22 #ifndef LAYER_LOGGING_H
23 #define LAYER_LOGGING_H
24 
25 #include "vk_loader_layer.h"
26 #include "vk_layer_config.h"
27 #include "vk_layer_data.h"
28 #include "vk_layer_table.h"
29 #include "vk_loader_platform.h"
30 #include "vulkan/vk_layer.h"
31 #include <cinttypes>
32 #include <stdarg.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <unordered_map>
36 #include <vector>
37 
38 typedef struct _debug_report_data {
39     VkLayerDbgFunctionNode *debug_callback_list;
40     VkLayerDbgFunctionNode *default_debug_callback_list;
41     VkFlags active_flags;
42     bool g_DEBUG_REPORT;
43 } debug_report_data;
44 
45 template debug_report_data *get_my_data_ptr<debug_report_data>(void *data_key,
46                                                                std::unordered_map<void *, debug_report_data *> &data_map);
47 
48 // Forward Declarations
49 static inline bool debug_report_log_msg(const debug_report_data *debug_data, VkFlags msgFlags,
50                                         VkDebugReportObjectTypeEXT objectType, uint64_t srcObject, size_t location, int32_t msgCode,
51                                         const char *pLayerPrefix, const char *pMsg);
52 
53 // Add a debug message callback node structure to the specified callback linked list
AddDebugMessageCallback(debug_report_data * debug_data,VkLayerDbgFunctionNode ** list_head,VkLayerDbgFunctionNode * new_node)54 static inline void AddDebugMessageCallback(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
55                                            VkLayerDbgFunctionNode *new_node) {
56 
57     new_node->pNext = *list_head;
58     *list_head = new_node;
59 }
60 
61 // Remove specified debug message callback node structure from the specified callback linked list
RemoveDebugMessageCallback(debug_report_data * debug_data,VkLayerDbgFunctionNode ** list_head,VkDebugReportCallbackEXT callback)62 static inline void RemoveDebugMessageCallback(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
63                                               VkDebugReportCallbackEXT callback) {
64     VkLayerDbgFunctionNode *cur_callback = *list_head;
65     VkLayerDbgFunctionNode *prev_callback = cur_callback;
66     bool matched = false;
67 
68     debug_data->active_flags = 0;
69     while (cur_callback) {
70         if (cur_callback->msgCallback == callback) {
71             matched = true;
72             prev_callback->pNext = cur_callback->pNext;
73             if (*list_head == cur_callback) {
74                 *list_head = cur_callback->pNext;
75             }
76             debug_report_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
77                                  reinterpret_cast<uint64_t &>(cur_callback->msgCallback), 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT,
78                                  "DebugReport", "Destroyed callback");
79         } else {
80             matched = false;
81             debug_data->active_flags |= cur_callback->msgFlags;
82         }
83         prev_callback = cur_callback;
84         cur_callback = cur_callback->pNext;
85         if (matched) {
86             free(prev_callback);
87         }
88     }
89 }
90 
91 // 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)92 static inline void RemoveAllMessageCallbacks(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head) {
93     VkLayerDbgFunctionNode *current_callback = *list_head;
94     VkLayerDbgFunctionNode *prev_callback = current_callback;
95 
96     while (current_callback) {
97         prev_callback = current_callback->pNext;
98         debug_report_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
99                              (uint64_t)current_callback->msgCallback, 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, "DebugReport",
100                              "Debug Report callbacks not removed before DestroyInstance");
101         free(current_callback);
102         current_callback = prev_callback;
103     }
104     *list_head = NULL;
105 }
106 
107 // Utility function to handle reporting
debug_report_log_msg(const debug_report_data * debug_data,VkFlags msgFlags,VkDebugReportObjectTypeEXT objectType,uint64_t srcObject,size_t location,int32_t msgCode,const char * pLayerPrefix,const char * pMsg)108 static inline bool debug_report_log_msg(const debug_report_data *debug_data, VkFlags msgFlags,
109                                         VkDebugReportObjectTypeEXT objectType, uint64_t srcObject, size_t location, int32_t msgCode,
110                                         const char *pLayerPrefix, const char *pMsg) {
111     bool bail = false;
112     VkLayerDbgFunctionNode *pTrav = NULL;
113 
114     if (debug_data->debug_callback_list != NULL) {
115         pTrav = debug_data->debug_callback_list;
116     } else {
117         pTrav = debug_data->default_debug_callback_list;
118     }
119 
120     while (pTrav) {
121         if (pTrav->msgFlags & msgFlags) {
122             if (pTrav->pfnMsgCallback(msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, pMsg, pTrav->pUserData)) {
123                 bail = true;
124             }
125         }
126         pTrav = pTrav->pNext;
127     }
128 
129     return bail;
130 }
131 
132 static inline debug_report_data *
debug_report_create_instance(VkLayerInstanceDispatchTable * table,VkInstance inst,uint32_t extension_count,const char * const * ppEnabledExtensions)133 debug_report_create_instance(VkLayerInstanceDispatchTable *table, VkInstance inst, uint32_t extension_count,
134                              const char *const *ppEnabledExtensions) // layer or extension name to be enabled
135 {
136     debug_report_data *debug_data = (debug_report_data *)malloc(sizeof(debug_report_data));
137     if (!debug_data)
138         return NULL;
139 
140     memset(debug_data, 0, sizeof(debug_report_data));
141     for (uint32_t i = 0; i < extension_count; i++) {
142         // TODO: Check other property fields
143         if (strcmp(ppEnabledExtensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
144             debug_data->g_DEBUG_REPORT = true;
145         }
146     }
147     return debug_data;
148 }
149 
layer_debug_report_destroy_instance(debug_report_data * debug_data)150 static inline void layer_debug_report_destroy_instance(debug_report_data *debug_data) {
151     if (debug_data) {
152         RemoveAllMessageCallbacks(debug_data, &debug_data->default_debug_callback_list);
153         RemoveAllMessageCallbacks(debug_data, &debug_data->debug_callback_list);
154         free(debug_data);
155     }
156 }
157 
layer_debug_report_create_device(debug_report_data * instance_debug_data,VkDevice device)158 static inline debug_report_data *layer_debug_report_create_device(debug_report_data *instance_debug_data, VkDevice device) {
159     // DEBUG_REPORT shares data between Instance and Device,
160     // so just return instance's data pointer
161     return instance_debug_data;
162 }
163 
layer_debug_report_destroy_device(VkDevice device)164 static inline void layer_debug_report_destroy_device(VkDevice device) {
165     // Nothing to do since we're using instance data record
166 }
167 
layer_destroy_msg_callback(debug_report_data * debug_data,VkDebugReportCallbackEXT callback,const VkAllocationCallbacks * pAllocator)168 static inline void layer_destroy_msg_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback,
169                                               const VkAllocationCallbacks *pAllocator) {
170     RemoveDebugMessageCallback(debug_data, &debug_data->debug_callback_list, callback);
171     RemoveDebugMessageCallback(debug_data, &debug_data->default_debug_callback_list, callback);
172 }
173 
layer_create_msg_callback(debug_report_data * debug_data,bool default_callback,const VkDebugReportCallbackCreateInfoEXT * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDebugReportCallbackEXT * pCallback)174 static inline VkResult layer_create_msg_callback(debug_report_data *debug_data, bool default_callback,
175                                                  const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
176                                                  const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback) {
177     VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
178     if (!pNewDbgFuncNode)
179         return VK_ERROR_OUT_OF_HOST_MEMORY;
180 
181     // Handle of 0 is logging_callback so use allocated Node address as unique handle
182     if (!(*pCallback))
183         *pCallback = (VkDebugReportCallbackEXT)pNewDbgFuncNode;
184     pNewDbgFuncNode->msgCallback = *pCallback;
185     pNewDbgFuncNode->pfnMsgCallback = pCreateInfo->pfnCallback;
186     pNewDbgFuncNode->msgFlags = pCreateInfo->flags;
187     pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
188 
189     if (default_callback) {
190         AddDebugMessageCallback(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
191     } else {
192         AddDebugMessageCallback(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
193     }
194     debug_data->active_flags |= pCreateInfo->flags;
195 
196     debug_report_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
197                          (uint64_t)*pCallback, 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, "DebugReport", "Added callback");
198     return VK_SUCCESS;
199 }
200 
debug_report_get_instance_proc_addr(debug_report_data * debug_data,const char * funcName)201 static inline PFN_vkVoidFunction debug_report_get_instance_proc_addr(debug_report_data *debug_data, const char *funcName) {
202     if (!debug_data || !debug_data->g_DEBUG_REPORT) {
203         return NULL;
204     }
205 
206     if (!strcmp(funcName, "vkCreateDebugReportCallbackEXT")) {
207         return (PFN_vkVoidFunction)vkCreateDebugReportCallbackEXT;
208     }
209     if (!strcmp(funcName, "vkDestroyDebugReportCallbackEXT")) {
210         return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT;
211     }
212     if (!strcmp(funcName, "vkDebugReportMessageEXT")) {
213         return (PFN_vkVoidFunction)vkDebugReportMessageEXT;
214     }
215     return NULL;
216 }
217 
218 // This utility (called at vkCreateInstance() time), looks at a pNext chain.
219 // It counts any VkDebugReportCallbackCreateInfoEXT structs that it finds.  It
220 // then allocates an array that can hold that many structs, as well as that
221 // many VkDebugReportCallbackEXT handles.  It then copies each
222 // VkDebugReportCallbackCreateInfoEXT, and initializes each handle.
layer_copy_tmp_callbacks(const void * pChain,uint32_t * num_callbacks,VkDebugReportCallbackCreateInfoEXT ** infos,VkDebugReportCallbackEXT ** callbacks)223 static VkResult layer_copy_tmp_callbacks(const void *pChain, uint32_t *num_callbacks, VkDebugReportCallbackCreateInfoEXT **infos,
224                                          VkDebugReportCallbackEXT **callbacks) {
225     uint32_t n = *num_callbacks = 0;
226 
227     const void *pNext = pChain;
228     while (pNext) {
229         // 1st, count the number VkDebugReportCallbackCreateInfoEXT:
230         if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
231             n++;
232         }
233         pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext;
234     }
235     if (n == 0) {
236         return VK_SUCCESS;
237     }
238 
239     // 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT:
240     VkDebugReportCallbackCreateInfoEXT *pInfos = *infos =
241         ((VkDebugReportCallbackCreateInfoEXT *)malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT)));
242     if (!pInfos) {
243         return VK_ERROR_OUT_OF_HOST_MEMORY;
244     }
245     // 3rd, allocate memory for a unique handle for each callback:
246     VkDebugReportCallbackEXT *pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)malloc(n * sizeof(VkDebugReportCallbackEXT)));
247     if (!pCallbacks) {
248         free(pInfos);
249         return VK_ERROR_OUT_OF_HOST_MEMORY;
250     }
251     // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by
252     // vkDestroyInstance, and assign a unique handle to each callback (just
253     // use the address of the copied VkDebugReportCallbackCreateInfoEXT):
254     pNext = pChain;
255     while (pNext) {
256         if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
257             memcpy(pInfos, pNext, sizeof(VkDebugReportCallbackCreateInfoEXT));
258             *pCallbacks++ = (VkDebugReportCallbackEXT)pInfos++;
259         }
260         pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
261     }
262 
263     *num_callbacks = n;
264     return VK_SUCCESS;
265 }
266 
267 // This utility frees the arrays allocated by layer_copy_tmp_callbacks()
layer_free_tmp_callbacks(VkDebugReportCallbackCreateInfoEXT * infos,VkDebugReportCallbackEXT * callbacks)268 static void layer_free_tmp_callbacks(VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) {
269     free(infos);
270     free(callbacks);
271 }
272 
273 // This utility enables all of the VkDebugReportCallbackCreateInfoEXT structs
274 // that were copied by layer_copy_tmp_callbacks()
layer_enable_tmp_callbacks(debug_report_data * debug_data,uint32_t num_callbacks,VkDebugReportCallbackCreateInfoEXT * infos,VkDebugReportCallbackEXT * callbacks)275 static VkResult layer_enable_tmp_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
276                                            VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) {
277     VkResult rtn = VK_SUCCESS;
278     for (uint32_t i = 0; i < num_callbacks; i++) {
279         rtn = layer_create_msg_callback(debug_data, false, &infos[i], NULL, &callbacks[i]);
280         if (rtn != VK_SUCCESS) {
281             for (uint32_t j = 0; j < i; j++) {
282                 layer_destroy_msg_callback(debug_data, callbacks[j], NULL);
283             }
284             return rtn;
285         }
286     }
287     return rtn;
288 }
289 
290 // This utility disables all of the VkDebugReportCallbackCreateInfoEXT structs
291 // that were copied by layer_copy_tmp_callbacks()
layer_disable_tmp_callbacks(debug_report_data * debug_data,uint32_t num_callbacks,VkDebugReportCallbackEXT * callbacks)292 static void layer_disable_tmp_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
293                                         VkDebugReportCallbackEXT *callbacks) {
294     for (uint32_t i = 0; i < num_callbacks; i++) {
295         layer_destroy_msg_callback(debug_data, callbacks[i], NULL);
296     }
297 }
298 
299 // Checks if the message will get logged.
300 // Allows layer to defer collecting & formating data if the
301 // message will be discarded.
will_log_msg(debug_report_data * debug_data,VkFlags msgFlags)302 static inline bool will_log_msg(debug_report_data *debug_data, VkFlags msgFlags) {
303     if (!debug_data || !(debug_data->active_flags & msgFlags)) {
304         // Message is not wanted
305         return false;
306     }
307 
308     return true;
309 }
310 
311 #ifdef WIN32
vasprintf(char ** strp,char const * fmt,va_list ap)312 static inline int vasprintf(char **strp, char const *fmt, va_list ap) {
313     *strp = nullptr;
314     int size = _vscprintf(fmt, ap);
315     if (size >= 0) {
316         *strp = (char *)malloc(size+1);
317         if (!*strp) {
318             return -1;
319         }
320         _vsnprintf(*strp, size+1, fmt, ap);
321     }
322     return size;
323 }
324 #endif
325 
326 // Output log message via DEBUG_REPORT
327 // Takes format and variable arg list so that output string
328 // is only computed if a message needs to be logged
329 #ifndef WIN32
330 static inline bool log_msg(const debug_report_data *debug_data, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
331                            uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *format, ...)
332     __attribute__((format(printf, 8, 9)));
333 #endif
log_msg(const debug_report_data * debug_data,VkFlags msgFlags,VkDebugReportObjectTypeEXT objectType,uint64_t srcObject,size_t location,int32_t msgCode,const char * pLayerPrefix,const char * format,...)334 static inline bool log_msg(const debug_report_data *debug_data, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
335                            uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *format,
336                            ...) {
337     if (!debug_data || !(debug_data->active_flags & msgFlags)) {
338         // Message is not wanted
339         return false;
340     }
341 
342     va_list argptr;
343     va_start(argptr, format);
344     char *str;
345     if (-1 == vasprintf(&str, format, argptr)) {
346         // On failure, glibc vasprintf leaves str undefined
347         str = nullptr;
348     }
349     va_end(argptr);
350     bool result = debug_report_log_msg(debug_data, msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix,
351                                        str ? str : "Allocation failure");
352     free(str);
353     return result;
354 }
355 
log_callback(VkFlags msgFlags,VkDebugReportObjectTypeEXT objType,uint64_t srcObject,size_t location,int32_t msgCode,const char * pLayerPrefix,const char * pMsg,void * pUserData)356 static inline VKAPI_ATTR VkBool32 VKAPI_CALL log_callback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
357                                                           size_t location, int32_t msgCode, const char *pLayerPrefix,
358                                                           const char *pMsg, void *pUserData) {
359     char msg_flags[30];
360 
361     print_msg_flags(msgFlags, msg_flags);
362 
363     fprintf((FILE *)pUserData, "%s(%s): object: 0x%" PRIx64 " type: %d location: %lu msgCode: %d: %s\n", pLayerPrefix, msg_flags,
364             srcObject, objType, (unsigned long)location, msgCode, pMsg);
365     fflush((FILE *)pUserData);
366 
367     return false;
368 }
369 
win32_debug_output_msg(VkFlags msgFlags,VkDebugReportObjectTypeEXT objType,uint64_t srcObject,size_t location,int32_t msgCode,const char * pLayerPrefix,const char * pMsg,void * pUserData)370 static inline VKAPI_ATTR VkBool32 VKAPI_CALL win32_debug_output_msg(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
371                                                                     uint64_t srcObject, size_t location, int32_t msgCode,
372                                                                     const char *pLayerPrefix, const char *pMsg, void *pUserData) {
373 #ifdef WIN32
374     char msg_flags[30];
375     char buf[2048];
376 
377     print_msg_flags(msgFlags, msg_flags);
378     _snprintf(buf, sizeof(buf) - 1,
379               "%s (%s): object: 0x%" PRIxPTR " type: %d location: " PRINTF_SIZE_T_SPECIFIER " msgCode: %d: %s\n", pLayerPrefix,
380               msg_flags, (size_t)srcObject, objType, location, msgCode, pMsg);
381 
382     OutputDebugString(buf);
383 #endif
384 
385     return false;
386 }
387 
388 #endif // LAYER_LOGGING_H
389