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