vk_layer_logging.h revision b94f051b39bc65e1110f1250b2ef0404f7104ab0
1/*
2 * Vulkan
3 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *   Courtney Goeltzenleuchter <courtney@lunarg.com>
26 */
27
28#ifndef LAYER_LOGGING_H
29#define LAYER_LOGGING_H
30
31#include <stdio.h>
32#include <stdarg.h>
33#include <stdbool.h>
34#include <unordered_map>
35#include <inttypes.h>
36#include "vk_layer.h"
37#include "vk_layer_data.h"
38#include "vk_layer_table.h"
39
40typedef struct _debug_report_data {
41    VkLayerDbgFunctionNode *g_pDbgFunctionHead;
42    VkFlags active_flags;
43    bool g_DEBUG_REPORT;
44} debug_report_data;
45
46template debug_report_data *get_my_data_ptr<debug_report_data>(
47        void *data_key,
48        std::unordered_map<void *, debug_report_data *> &data_map);
49
50// Utility function to handle reporting
51static inline VkBool32 debug_report_log_msg(
52    debug_report_data          *debug_data,
53    VkFlags                     msgFlags,
54    VkDbgObjectType             objectType,
55    uint64_t                    srcObject,
56    size_t                      location,
57    int32_t                     msgCode,
58    const char*                 pLayerPrefix,
59    const char*                 pMsg)
60{
61    VkBool32 bail = false;
62    VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
63    while (pTrav) {
64        if (pTrav->msgFlags & msgFlags) {
65            if (pTrav->pfnMsgCallback(msgFlags,
66                                  objectType, srcObject,
67                                  location,
68                                  msgCode,
69                                  pLayerPrefix,
70                                  pMsg,
71                                  (void *) pTrav->pUserData)) {
72                bail = true;
73            }
74        }
75        pTrav = pTrav->pNext;
76    }
77
78    return bail;
79}
80
81static inline debug_report_data *debug_report_create_instance(
82        VkLayerInstanceDispatchTable   *table,
83        VkInstance                      inst,
84        uint32_t                        extension_count,
85        const char*const*               ppEnabledExtensions)    // layer or extension name to be enabled
86{
87    debug_report_data              *debug_data;
88    PFN_vkGetInstanceProcAddr gpa = table->GetInstanceProcAddr;
89
90    table->DbgCreateMsgCallback = (PFN_vkDbgCreateMsgCallback) gpa(inst, "vkDbgCreateMsgCallback");
91    table->DbgDestroyMsgCallback = (PFN_vkDbgDestroyMsgCallback) gpa(inst, "vkDbgDestroyMsgCallback");
92
93    debug_data = (debug_report_data *) malloc(sizeof(debug_report_data));
94    if (!debug_data) return NULL;
95
96    memset(debug_data, 0, sizeof(debug_report_data));
97    for (uint32_t i = 0; i < extension_count; i++) {
98        /* TODO: Check other property fields */
99        if (strcmp(ppEnabledExtensions[i], VK_DEBUG_REPORT_EXTENSION_NAME) == 0) {
100            debug_data->g_DEBUG_REPORT = true;
101        }
102    }
103    return debug_data;
104}
105
106static inline void layer_debug_report_destroy_instance(debug_report_data *debug_data)
107{
108    VkLayerDbgFunctionNode *pTrav;
109    VkLayerDbgFunctionNode *pTravNext;
110
111    if (!debug_data) {
112        return;
113    }
114
115    pTrav = debug_data->g_pDbgFunctionHead;
116    /* Clear out any leftover callbacks */
117    while (pTrav) {
118        pTravNext = pTrav->pNext;
119
120        debug_report_log_msg(
121                    debug_data, VK_DBG_REPORT_WARN_BIT,
122                    VK_OBJECT_TYPE_MSG_CALLBACK, pTrav->msgCallback.handle,
123                    0, DEBUG_REPORT_CALLBACK_REF,
124                    "DebugReport",
125                    "Debug Report callbacks not removed before DestroyInstance");
126
127        free(pTrav);
128        pTrav = pTravNext;
129    }
130    debug_data->g_pDbgFunctionHead = NULL;
131
132    free(debug_data);
133}
134
135static inline debug_report_data *layer_debug_report_create_device(
136        debug_report_data              *instance_debug_data,
137        VkDevice                        device)
138{
139    /* DEBUG_REPORT shares data between Instance and Device,
140     * so just return instance's data pointer */
141    return instance_debug_data;
142}
143
144static inline void layer_debug_report_destroy_device(VkDevice device)
145{
146    /* Nothing to do since we're using instance data record */
147}
148
149static inline VkResult layer_create_msg_callback(
150        debug_report_data              *debug_data,
151        VkFlags                         msgFlags,
152        const PFN_vkDbgMsgCallback      pfnMsgCallback,
153        void                           *pUserData,
154        VkDbgMsgCallback               *pMsgCallback)
155{
156    VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode*)malloc(sizeof(VkLayerDbgFunctionNode));
157    if (!pNewDbgFuncNode)
158        return VK_ERROR_OUT_OF_HOST_MEMORY;
159
160    // Handle of 0 is logging_callback so use allocated Node address as unique handle
161    if (!(*pMsgCallback))
162        *pMsgCallback = (uint64_t) pNewDbgFuncNode;
163    pNewDbgFuncNode->msgCallback = *pMsgCallback;
164    pNewDbgFuncNode->pfnMsgCallback = pfnMsgCallback;
165    pNewDbgFuncNode->msgFlags = msgFlags;
166    pNewDbgFuncNode->pUserData = pUserData;
167    pNewDbgFuncNode->pNext = debug_data->g_pDbgFunctionHead;
168
169    debug_data->g_pDbgFunctionHead = pNewDbgFuncNode;
170    debug_data->active_flags |= msgFlags;
171
172    debug_report_log_msg(
173                debug_data, VK_DBG_REPORT_DEBUG_BIT,
174                VK_OBJECT_TYPE_MSG_CALLBACK, (*pMsgCallback).handle,
175                0, DEBUG_REPORT_CALLBACK_REF,
176                "DebugReport",
177                "Added callback");
178    return VK_SUCCESS;
179}
180
181static inline void layer_destroy_msg_callback(
182        debug_report_data              *debug_data,
183        VkDbgMsgCallback                msg_callback)
184{
185    VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
186    VkLayerDbgFunctionNode *pPrev = pTrav;
187    bool matched;
188
189    debug_data->active_flags = 0;
190    while (pTrav) {
191        if (pTrav->msgCallback == msg_callback) {
192            matched = true;
193            pPrev->pNext = pTrav->pNext;
194            if (debug_data->g_pDbgFunctionHead == pTrav) {
195                debug_data->g_pDbgFunctionHead = pTrav->pNext;
196            }
197            debug_report_log_msg(
198                        debug_data, VK_DBG_REPORT_DEBUG_BIT,
199                        VK_OBJECT_TYPE_MSG_CALLBACK, pTrav->msgCallback.handle,
200                        0, DEBUG_REPORT_NONE,
201                        "DebugReport",
202                        "Destroyed callback");
203        } else {
204            matched = false;
205            debug_data->active_flags |= pTrav->msgFlags;
206        }
207        pPrev = pTrav;
208        pTrav = pTrav->pNext;
209        if (matched) {
210            free(pPrev);
211        }
212    }
213}
214
215static inline PFN_vkVoidFunction debug_report_get_instance_proc_addr(
216        debug_report_data              *debug_data,
217        const char                     *funcName)
218{
219    if (!debug_data || !debug_data->g_DEBUG_REPORT) {
220        return NULL;
221    }
222
223    if (!strcmp(funcName, "vkDbgCreateMsgCallback")) {
224        return (PFN_vkVoidFunction) vkDbgCreateMsgCallback;
225    }
226    if (!strcmp(funcName, "vkDbgDestroyMsgCallback")) {
227        return (PFN_vkVoidFunction) vkDbgDestroyMsgCallback;
228    }
229
230    return NULL;
231}
232
233/*
234 * Checks if the message will get logged.
235 * Allows layer to defer collecting & formating data if the
236 * message will be discarded.
237 */
238static inline VkBool32 will_log_msg(
239    debug_report_data          *debug_data,
240    VkFlags                     msgFlags)
241{
242    if (!debug_data || !(debug_data->active_flags & msgFlags)) {
243        /* message is not wanted */
244        return false;
245    }
246
247    return true;
248}
249
250/*
251 * Output log message via DEBUG_REPORT
252 * Takes format and variable arg list so that output string
253 * is only computed if a message needs to be logged
254 */
255static inline VkBool32 log_msg(
256    debug_report_data          *debug_data,
257    VkFlags                     msgFlags,
258    VkDbgObjectType             objectType,
259    uint64_t                    srcObject,
260    size_t                      location,
261    int32_t                     msgCode,
262    const char*                 pLayerPrefix,
263    const char*                 format,
264    ...)
265{
266    if (!debug_data || !(debug_data->active_flags & msgFlags)) {
267        /* message is not wanted */
268        return false;
269    }
270
271    char str[1024];
272    va_list argptr;
273    va_start(argptr, format);
274    vsnprintf(str, 1024, format, argptr);
275    va_end(argptr);
276    return debug_report_log_msg(
277                debug_data, msgFlags, objectType,
278                srcObject, location, msgCode,
279                pLayerPrefix, str);
280}
281
282static inline VkBool32 VKAPI log_callback(
283    VkFlags                             msgFlags,
284    VkDbgObjectType                     objType,
285    uint64_t                            srcObject,
286    size_t                              location,
287    int32_t                             msgCode,
288    const char*                         pLayerPrefix,
289    const char*                         pMsg,
290    void*                               pUserData)
291{
292    char msg_flags[30];
293
294    print_msg_flags(msgFlags, msg_flags);
295
296    fprintf((FILE *) pUserData, "%s(%s): object: %#" PRIx64 " type: %d location: %lu msgCode: %d: %s\n",
297             pLayerPrefix, msg_flags, srcObject, objType, (unsigned long)location, msgCode, pMsg);
298    fflush((FILE *) pUserData);
299
300    return false;
301}
302
303static inline VkBool32 VKAPI win32_debug_output_msg(
304    VkFlags                             msgFlags,
305    VkDbgObjectType                     objType,
306    uint64_t                            srcObject,
307    size_t                              location,
308    int32_t                             msgCode,
309    const char*                         pLayerPrefix,
310    const char*                         pMsg,
311    void*                               pUserData)
312{
313#ifdef WIN32
314    char msg_flags[30];
315    char buf[2048];
316
317    print_msg_flags(msgFlags, msg_flags);
318    _snprintf(buf, sizeof(buf)-1, "%s (%s): object: 0x%" PRIxLEAST64 " type: %d location: %zu msgCode: %d: %s\n",
319             pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
320
321    OutputDebugString(buf);
322#endif
323
324    return false;
325}
326
327#endif // LAYER_LOGGING_H
328