vk_layer_logging.h revision f8155e48c6ce161cb0e9a2c4e2b8eb0b19cc99b4
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 void 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    VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
62    while (pTrav) {
63        if (pTrav->msgFlags & msgFlags) {
64            pTrav->pfnMsgCallback(msgFlags,
65                                  objectType, srcObject,
66                                  location,
67                                  msgCode,
68                                  pLayerPrefix,
69                                  pMsg,
70                                  (void *) pTrav->pUserData);
71        }
72        pTrav = pTrav->pNext;
73    }
74}
75
76static inline debug_report_data *debug_report_create_instance(
77        VkLayerInstanceDispatchTable   *table,
78        VkInstance                      inst,
79        uint32_t                        extension_count,
80        const char*const*               ppEnabledExtensions)    // layer or extension name to be enabled
81{
82    debug_report_data              *debug_data;
83    PFN_vkGetInstanceProcAddr gpa = table->GetInstanceProcAddr;
84
85    table->DbgCreateMsgCallback = (PFN_vkDbgCreateMsgCallback) gpa(inst, "vkDbgCreateMsgCallback");
86    table->DbgDestroyMsgCallback = (PFN_vkDbgDestroyMsgCallback) gpa(inst, "vkDbgDestroyMsgCallback");
87
88    debug_data = (debug_report_data *) malloc(sizeof(debug_report_data));
89    if (!debug_data) return NULL;
90
91    memset(debug_data, 0, sizeof(debug_report_data));
92    for (uint32_t i = 0; i < extension_count; i++) {
93        /* TODO: Check other property fields */
94        if (strcmp(ppEnabledExtensions[i], VK_DEBUG_REPORT_EXTENSION_NAME) == 0) {
95            debug_data->g_DEBUG_REPORT = true;
96        }
97    }
98    return debug_data;
99}
100
101static inline void layer_debug_report_destroy_instance(debug_report_data *debug_data)
102{
103    VkLayerDbgFunctionNode *pTrav;
104    VkLayerDbgFunctionNode *pTravNext;
105
106    if (!debug_data) {
107        return;
108    }
109
110    pTrav = debug_data->g_pDbgFunctionHead;
111    /* Clear out any leftover callbacks */
112    while (pTrav) {
113        pTravNext = pTrav->pNext;
114
115        debug_report_log_msg(
116                    debug_data, VK_DBG_REPORT_WARN_BIT,
117                    VK_OBJECT_TYPE_MSG_CALLBACK, pTrav->msgCallback.handle,
118                    0, DEBUG_REPORT_CALLBACK_REF,
119                    "DebugReport",
120                    "Debug Report callbacks not removed before DestroyInstance");
121
122        free(pTrav);
123        pTrav = pTravNext;
124    }
125    debug_data->g_pDbgFunctionHead = NULL;
126
127    free(debug_data);
128}
129
130static inline debug_report_data *layer_debug_report_create_device(
131        debug_report_data              *instance_debug_data,
132        VkDevice                        device)
133{
134    /* DEBUG_REPORT shares data between Instance and Device,
135     * so just return instance's data pointer */
136    return instance_debug_data;
137}
138
139static inline void layer_debug_report_destroy_device(VkDevice device)
140{
141    /* Nothing to do since we're using instance data record */
142}
143
144static inline VkResult layer_create_msg_callback(
145        debug_report_data              *debug_data,
146        VkFlags                         msgFlags,
147        const PFN_vkDbgMsgCallback      pfnMsgCallback,
148        void                           *pUserData,
149        VkDbgMsgCallback               *pMsgCallback)
150{
151    VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode*)malloc(sizeof(VkLayerDbgFunctionNode));
152    if (!pNewDbgFuncNode)
153        return VK_ERROR_OUT_OF_HOST_MEMORY;
154
155    pNewDbgFuncNode->msgCallback = *pMsgCallback;
156    pNewDbgFuncNode->pfnMsgCallback = pfnMsgCallback;
157    pNewDbgFuncNode->msgFlags = msgFlags;
158    pNewDbgFuncNode->pUserData = pUserData;
159    pNewDbgFuncNode->pNext = debug_data->g_pDbgFunctionHead;
160
161    debug_data->g_pDbgFunctionHead = pNewDbgFuncNode;
162    debug_data->active_flags |= msgFlags;
163
164    debug_report_log_msg(
165                debug_data, VK_DBG_REPORT_DEBUG_BIT,
166                VK_OBJECT_TYPE_MSG_CALLBACK, (*pMsgCallback).handle,
167                0, DEBUG_REPORT_CALLBACK_REF,
168                "DebugReport",
169                "Added callback");
170    return VK_SUCCESS;
171}
172
173static inline void layer_destroy_msg_callback(
174        debug_report_data              *debug_data,
175        VkDbgMsgCallback                msg_callback)
176{
177    VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
178    VkLayerDbgFunctionNode *pPrev = pTrav;
179    bool matched;
180
181    debug_data->active_flags = 0;
182    while (pTrav) {
183        if (pTrav->msgCallback == msg_callback) {
184            matched = true;
185            pPrev->pNext = pTrav->pNext;
186            if (debug_data->g_pDbgFunctionHead == pTrav) {
187                debug_data->g_pDbgFunctionHead = pTrav->pNext;
188            }
189            debug_report_log_msg(
190                        debug_data, VK_DBG_REPORT_DEBUG_BIT,
191                        VK_OBJECT_TYPE_MSG_CALLBACK, pTrav->msgCallback.handle,
192                        0, DEBUG_REPORT_NONE,
193                        "DebugReport",
194                        "Destroyed callback");
195        } else {
196            matched = false;
197            debug_data->active_flags |= pTrav->msgFlags;
198        }
199        pPrev = pTrav;
200        pTrav = pTrav->pNext;
201        if (matched) {
202            free(pPrev);
203        }
204    }
205}
206
207static inline PFN_vkVoidFunction debug_report_get_instance_proc_addr(
208        debug_report_data              *debug_data,
209        const char                     *funcName)
210{
211    if (!debug_data || !debug_data->g_DEBUG_REPORT) {
212        return NULL;
213    }
214
215    if (!strcmp(funcName, "vkDbgCreateMsgCallback")) {
216        return (PFN_vkVoidFunction) vkDbgCreateMsgCallback;
217    }
218    if (!strcmp(funcName, "vkDbgDestroyMsgCallback")) {
219        return (PFN_vkVoidFunction) vkDbgDestroyMsgCallback;
220    }
221
222    return NULL;
223}
224
225/*
226 * Output log message via DEBUG_REPORT
227 * Takes format and variable arg list so that output string
228 * is only computed if a message needs to be logged
229 */
230static inline void log_msg(
231    debug_report_data          *debug_data,
232    VkFlags                     msgFlags,
233    VkDbgObjectType             objectType,
234    uint64_t                    srcObject,
235    size_t                      location,
236    int32_t                     msgCode,
237    const char*                 pLayerPrefix,
238    const char*                 format,
239    ...)
240{
241    if (!debug_data || !(debug_data->active_flags & msgFlags)) {
242        /* message is not wanted */
243        return;
244    }
245
246    char str[1024];
247    va_list argptr;
248    va_start(argptr, format);
249    vsnprintf(str, 1024, format, argptr);
250    va_end(argptr);
251    debug_report_log_msg(debug_data, msgFlags, objectType,
252                         srcObject, location, msgCode,
253                         pLayerPrefix, str);
254}
255
256static inline void VKAPI log_callback(
257    VkFlags                             msgFlags,
258    VkDbgObjectType                     objType,
259    uint64_t                            srcObject,
260    size_t                              location,
261    int32_t                             msgCode,
262    const char*                         pLayerPrefix,
263    const char*                         pMsg,
264    void*                               pUserData)
265{
266    char msg_flags[30];
267
268    print_msg_flags(msgFlags, msg_flags);
269
270    fprintf((FILE *) pUserData, "%s(%s): object: %#" PRIx64 " type: %d location: %zu msgCode: %d: %s\n",
271             pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
272}
273#endif // LAYER_LOGGING_H
274