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