debug_report.c revision b40f2568bff91895d66848767fdaa540793b5162
1/*
2 * Vulkan
3 *
4 * Copyright (C) 2015 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 *   Jon Ashburn <jon@lunarg.com>
26 *   Courtney Goeltzenleuchter <courtney@lunarg.com>
27 */
28
29#include <string.h>
30#include <stdlib.h>
31#include "debug_report.h"
32#include "vkLayer.h"
33
34static const struct loader_extension_property debug_report_extension_info = {
35    .info =  {
36        .sType = VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES,
37        .name = DEBUG_REPORT_EXTENSION_NAME,
38        .version = VK_DEBUG_REPORT_EXTENSION_VERSION,
39        .description = "loader: debug report extension",
40        },
41    .origin = VK_EXTENSION_ORIGIN_LOADER,
42    .hosted = true,
43};
44
45void debug_report_add_instance_extensions(
46        struct loader_extension_list *ext_list)
47{
48    loader_add_to_ext_list(ext_list, 1, &debug_report_extension_info);
49}
50
51void debug_report_create_instance(
52        struct loader_instance *ptr_instance)
53{
54    ptr_instance->debug_report_enabled = has_vk_extension_property(
55                                             &debug_report_extension_info.info,
56                                             &ptr_instance->enabled_instance_extensions);
57}
58
59static VkResult debug_report_DbgCreateMsgCallback(
60        VkInstance instance,
61        VkFlags msgFlags,
62        const PFN_vkDbgMsgCallback pfnMsgCallback,
63        void* pUserData,
64        VkDbgMsgCallback* pMsgCallback)
65{
66    VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *) malloc(sizeof(VkLayerDbgFunctionNode));
67    if (!pNewDbgFuncNode)
68        return VK_ERROR_OUT_OF_HOST_MEMORY;
69
70    struct loader_instance *inst = loader_instance(instance);
71    loader_platform_thread_lock_mutex(&loader_lock);
72    VkResult result = inst->disp->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
73    if (result == VK_SUCCESS) {
74        pNewDbgFuncNode->msgCallback = *pMsgCallback;
75        pNewDbgFuncNode->pfnMsgCallback = pfnMsgCallback;
76        pNewDbgFuncNode->msgFlags = msgFlags;
77        pNewDbgFuncNode->pUserData = pUserData;
78        pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
79        inst->DbgFunctionHead = pNewDbgFuncNode;
80    } else {
81        free(pNewDbgFuncNode);
82    }
83    loader_platform_thread_unlock_mutex(&loader_lock);
84    return result;
85}
86
87static VkResult debug_report_DbgDestroyMsgCallback(
88        VkInstance instance,
89        VkDbgMsgCallback msg_callback)
90{
91    struct loader_instance *inst = loader_instance(instance);
92    loader_platform_thread_lock_mutex(&loader_lock);
93    VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
94    VkLayerDbgFunctionNode *pPrev = pTrav;
95
96    VkResult result = inst->disp->DbgDestroyMsgCallback(instance, msg_callback);
97
98    while (pTrav) {
99        if (pTrav->msgCallback == msg_callback) {
100            pPrev->pNext = pTrav->pNext;
101            if (inst->DbgFunctionHead == pTrav)
102                inst->DbgFunctionHead = pTrav->pNext;
103            free(pTrav);
104            break;
105        }
106        pPrev = pTrav;
107        pTrav = pTrav->pNext;
108    }
109
110    loader_platform_thread_unlock_mutex(&loader_lock);
111    return result;
112}
113
114
115/*
116 * This is the instance chain terminator function
117 * for DbgCreateMsgCallback
118 */
119VkResult loader_DbgCreateMsgCallback(
120        VkInstance                          instance,
121        VkFlags                             msgFlags,
122        const PFN_vkDbgMsgCallback          pfnMsgCallback,
123        const void*                         pUserData,
124        VkDbgMsgCallback*                   pMsgCallback)
125{
126    VkDbgMsgCallback *icd_info;
127    const struct loader_icd *icd;
128    struct loader_instance *inst;
129    VkResult res;
130    uint32_t storage_idx;
131
132    if (instance == VK_NULL_HANDLE)
133        return VK_ERROR_INVALID_HANDLE;
134
135    assert(loader.icds_scanned);
136
137    for (inst = loader.instances; inst; inst = inst->next) {
138        if ((VkInstance) inst == instance)
139            break;
140    }
141
142    if (inst == VK_NULL_HANDLE)
143        return VK_ERROR_INVALID_HANDLE;
144
145    icd_info = calloc(sizeof(VkDbgMsgCallback), inst->total_icd_count);
146    if (!icd_info) {
147        return VK_ERROR_OUT_OF_HOST_MEMORY;
148    }
149
150    storage_idx = 0;
151    for (icd = inst->icds; icd; icd = icd->next) {
152        if (!icd->DbgCreateMsgCallback) {
153            continue;
154        }
155
156        res = icd->DbgCreateMsgCallback(
157                  icd->instance,
158                  msgFlags,
159                  pfnMsgCallback,
160                  pUserData,
161                  &icd_info[storage_idx]);
162
163        if (res != VK_SUCCESS) {
164            break;
165        }
166        storage_idx++;
167    }
168
169    /* roll back on errors */
170    if (icd) {
171        storage_idx = 0;
172        for (icd = inst->icds; icd; icd = icd->next) {
173            if (icd_info[storage_idx]) {
174                icd->DbgDestroyMsgCallback(
175                      icd->instance,
176                      icd_info[storage_idx]);
177            }
178            storage_idx++;
179        }
180
181        return res;
182    }
183
184    *pMsgCallback = (VkDbgMsgCallback) icd_info;
185
186    return VK_SUCCESS;
187}
188
189/*
190 * This is the instance chain terminator function
191 * for DbgDestroyMsgCallback
192 */
193VkResult loader_DbgDestroyMsgCallback(
194        VkInstance instance,
195        VkDbgMsgCallback msgCallback)
196{
197    uint32_t storage_idx;
198    VkDbgMsgCallback *icd_info;
199    const struct loader_icd *icd;
200    VkResult res = VK_SUCCESS;
201    struct loader_instance *inst;
202
203    if (instance == VK_NULL_HANDLE)
204        return VK_ERROR_INVALID_HANDLE;
205
206    assert(loader.icds_scanned);
207
208    for (inst = loader.instances; inst; inst = inst->next) {
209        if ((VkInstance) inst == instance)
210            break;
211    }
212
213    if (inst == VK_NULL_HANDLE)
214        return VK_ERROR_INVALID_HANDLE;
215
216    icd_info = (VkDbgMsgCallback *) msgCallback;
217    storage_idx = 0;
218    for (icd = inst->icds; icd; icd = icd->next) {
219        if (icd_info[storage_idx]) {
220            icd->DbgDestroyMsgCallback(
221                  icd->instance,
222                  icd_info[storage_idx]);
223        }
224        storage_idx++;
225    }
226    return res;
227}
228
229// DebugReport utility callback functions
230static void VKAPI StringCallback(
231    VkFlags                             msgFlags,
232    VkObjectType                        objType,
233    VkObject                            srcObject,
234    size_t                              location,
235    int32_t                             msgCode,
236    const char*                         pLayerPrefix,
237    const char*                         pMsg,
238    void*                               pUserData)
239{
240
241}
242
243static void VKAPI StdioCallback(
244    VkFlags                             msgFlags,
245    VkObjectType                        objType,
246    VkObject                            srcObject,
247    size_t                              location,
248    int32_t                             msgCode,
249    const char*                         pLayerPrefix,
250    const char*                         pMsg,
251    void*                               pUserData)
252{
253
254}
255
256static void VKAPI BreakCallback(
257    VkFlags                             msgFlags,
258    VkObjectType                        objType,
259    VkObject                            srcObject,
260    size_t                              location,
261    int32_t                             msgCode,
262    const char*                         pLayerPrefix,
263    const char*                         pMsg,
264    void*                               pUserData)
265{
266
267}
268
269void *debug_report_instance_gpa(
270        struct loader_instance *ptr_instance,
271        const char* name)
272{
273    if (ptr_instance == VK_NULL_HANDLE || !ptr_instance->debug_report_enabled)
274        return NULL;
275
276    if (!strcmp("vkDbgCreateMsgCallback", name))
277        return (void *) debug_report_DbgCreateMsgCallback;
278    else if (!strcmp("vkDbgDestroyMsgCallback", name))
279        return (void *) debug_report_DbgDestroyMsgCallback;
280    else if (!strcmp("vkDbgStringCallback", name))
281        return (void *) StringCallback;
282    else if (!strcmp("vkDbgStdioCallback", name))
283        return (void *) StdioCallback;
284    else if (!strcmp("vkDbgBreakCallback", name))
285        return (void *) BreakCallback;
286
287    return NULL;
288}
289