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
31struct 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
41VK_DEFINE_NONDISP_HANDLE_CASTS(vk_debug_report_callback, base,
42                               VkDebugReportCallbackEXT,
43                               VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT)
44
45VKAPI_ATTR VkResult VKAPI_CALL
46vk_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
77VKAPI_ATTR void VKAPI_CALL
78vk_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
96static void
97debug_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
129VKAPI_ATTR void VKAPI_CALL
130vk_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
144void
145vk_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