1 /*
2  * Copyright © 2017 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * 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 DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "vk_debug_report.h"
25 
26 #include "vk_alloc.h"
27 #include "vk_common_entrypoints.h"
28 #include "vk_instance.h"
29 #include "vk_util.h"
30 
31 struct vk_debug_report_callback {
32    struct vk_object_base                        base;
33 
34    /* Link in the 'callbacks' list in anv_instance struct. */
35    struct list_head                             link;
36    VkDebugReportFlagsEXT                        flags;
37    PFN_vkDebugReportCallbackEXT                 callback;
38    void *                                       data;
39 };
40 
VK_DEFINE_NONDISP_HANDLE_CASTS(vk_debug_report_callback,base,VkDebugReportCallbackEXT,VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT)41 VK_DEFINE_NONDISP_HANDLE_CASTS(vk_debug_report_callback, base,
42                                VkDebugReportCallbackEXT,
43                                VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT)
44 
45 VKAPI_ATTR VkResult VKAPI_CALL
46 vk_common_CreateDebugReportCallbackEXT(VkInstance _instance,
47                                        const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
48                                        const VkAllocationCallbacks *pAllocator,
49                                        VkDebugReportCallbackEXT *pCallback)
50 {
51    VK_FROM_HANDLE(vk_instance, instance, _instance);
52 
53    struct vk_debug_report_callback *cb =
54       vk_alloc2(&instance->alloc, pAllocator,
55                 sizeof(struct vk_debug_report_callback), 8,
56                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
57 
58    if (!cb)
59       return VK_ERROR_OUT_OF_HOST_MEMORY;
60 
61    vk_object_base_init(NULL, &cb->base,
62                        VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT);
63 
64    cb->flags = pCreateInfo->flags;
65    cb->callback = pCreateInfo->pfnCallback;
66    cb->data = pCreateInfo->pUserData;
67 
68    mtx_lock(&instance->debug_report.callbacks_mutex);
69    list_addtail(&cb->link, &instance->debug_report.callbacks);
70    mtx_unlock(&instance->debug_report.callbacks_mutex);
71 
72    *pCallback = vk_debug_report_callback_to_handle(cb);
73 
74    return VK_SUCCESS;
75 }
76 
77 VKAPI_ATTR void VKAPI_CALL
vk_common_DestroyDebugReportCallbackEXT(VkInstance _instance,VkDebugReportCallbackEXT _callback,const VkAllocationCallbacks * pAllocator)78 vk_common_DestroyDebugReportCallbackEXT(VkInstance _instance,
79                                         VkDebugReportCallbackEXT _callback,
80                                         const VkAllocationCallbacks *pAllocator)
81 {
82    VK_FROM_HANDLE(vk_instance, instance, _instance);
83    VK_FROM_HANDLE(vk_debug_report_callback, callback, _callback);
84 
85    if (callback == NULL)
86       return;
87 
88    /* Remove from list and destroy given callback. */
89    mtx_lock(&instance->debug_report.callbacks_mutex);
90    list_del(&callback->link);
91    vk_object_base_finish(&callback->base);
92    vk_free2(&instance->alloc, pAllocator, callback);
93    mtx_unlock(&instance->debug_report.callbacks_mutex);
94 }
95 
96 static void
debug_report(struct vk_instance * instance,VkDebugReportFlagsEXT flags,VkDebugReportObjectTypeEXT object_type,uint64_t handle,size_t location,int32_t messageCode,const char * pLayerPrefix,const char * pMessage)97 debug_report(struct vk_instance *instance,
98              VkDebugReportFlagsEXT flags,
99              VkDebugReportObjectTypeEXT object_type,
100              uint64_t handle,
101              size_t location,
102              int32_t messageCode,
103              const char* pLayerPrefix,
104              const char *pMessage)
105 {
106    /* Allow NULL for convinience, return if no callbacks registered. */
107    if (!instance || list_is_empty(&instance->debug_report.callbacks))
108       return;
109 
110    mtx_lock(&instance->debug_report.callbacks_mutex);
111 
112    /* Section 33.2 of the Vulkan 1.0.59 spec says:
113     *
114     *    "callback is an externally synchronized object and must not be
115     *    used on more than one thread at a time. This means that
116     *    vkDestroyDebugReportCallbackEXT must not be called when a callback
117     *    is active."
118     */
119    list_for_each_entry(struct vk_debug_report_callback, cb,
120                        &instance->debug_report.callbacks, link) {
121       if (cb->flags & flags)
122          cb->callback(flags, object_type, handle, location, messageCode,
123                       pLayerPrefix, pMessage, cb->data);
124    }
125 
126    mtx_unlock(&instance->debug_report.callbacks_mutex);
127 }
128 
129 VKAPI_ATTR void VKAPI_CALL
vk_common_DebugReportMessageEXT(VkInstance _instance,VkDebugReportFlagsEXT flags,VkDebugReportObjectTypeEXT objectType,uint64_t object,size_t location,int32_t messageCode,const char * pLayerPrefix,const char * pMessage)130 vk_common_DebugReportMessageEXT(VkInstance _instance,
131                                 VkDebugReportFlagsEXT flags,
132                                 VkDebugReportObjectTypeEXT objectType,
133                                 uint64_t object,
134                                 size_t location,
135                                 int32_t messageCode,
136                                 const char* pLayerPrefix,
137                                 const char* pMessage)
138 {
139    VK_FROM_HANDLE(vk_instance, instance, _instance);
140    debug_report(instance, flags, objectType,
141                 object, location, messageCode, pLayerPrefix, pMessage);
142 }
143 
144 void
vk_debug_report(struct vk_instance * instance,VkDebugReportFlagsEXT flags,const struct vk_object_base * object,size_t location,int32_t messageCode,const char * pLayerPrefix,const char * pMessage)145 vk_debug_report(struct vk_instance *instance,
146                 VkDebugReportFlagsEXT flags,
147                 const struct vk_object_base *object,
148                 size_t location,
149                 int32_t messageCode,
150                 const char* pLayerPrefix,
151                 const char *pMessage)
152 {
153    VkDebugReportObjectTypeEXT object_type =
154       object ? object->type : VK_OBJECT_TYPE_UNKNOWN;
155    debug_report(instance, flags, object_type, (uint64_t)(uintptr_t)object,
156                 location, messageCode, pLayerPrefix, pMessage);
157 }
158