1 /*
2  * Copyright 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef LIBVULKAN_DEBUG_REPORT_H
18 #define LIBVULKAN_DEBUG_REPORT_H 1
19 
20 #include <stdarg.h>
21 #include <shared_mutex>
22 #include <vulkan/vulkan.h>
23 
24 namespace vulkan {
25 namespace driver {
26 
27 // clang-format off
28 VKAPI_ATTR VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
29 VKAPI_ATTR void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
30 VKAPI_ATTR void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
31 // clang-format on
32 
33 class DebugReportCallbackList {
34    private:
35     // forward declaration
36     struct Node;
37 
38    public:
DebugReportCallbackList()39     DebugReportCallbackList()
40         : head_{nullptr, 0, nullptr, nullptr, VK_NULL_HANDLE} {}
41     DebugReportCallbackList(const DebugReportCallbackList&) = delete;
42     DebugReportCallbackList& operator=(const DebugReportCallbackList&) = delete;
43     ~DebugReportCallbackList() = default;
44 
45     Node* AddCallback(const VkDebugReportCallbackCreateInfoEXT& info,
46                       VkDebugReportCallbackEXT driver_handle,
47                       const VkAllocationCallbacks& allocator);
48     void RemoveCallback(Node* node, const VkAllocationCallbacks& allocator);
49 
50     void Message(VkDebugReportFlagsEXT flags,
51                  VkDebugReportObjectTypeEXT object_type,
52                  uint64_t object,
53                  size_t location,
54                  int32_t message_code,
55                  const char* layer_prefix,
56                  const char* message) const;
57 
FromHandle(VkDebugReportCallbackEXT handle)58     static Node* FromHandle(VkDebugReportCallbackEXT handle) {
59         return reinterpret_cast<Node*>(uintptr_t(handle));
60     }
61 
GetHandle(const Node * node)62     static VkDebugReportCallbackEXT GetHandle(const Node* node) {
63         return VkDebugReportCallbackEXT(reinterpret_cast<uintptr_t>(node));
64     }
65 
GetDriverHandle(const Node * node)66     static VkDebugReportCallbackEXT GetDriverHandle(const Node* node) {
67         return node->driver_handle;
68     }
69 
70    private:
71     struct Node {
72         Node* next;
73 
74         VkDebugReportFlagsEXT flags;
75         PFN_vkDebugReportCallbackEXT callback;
76         void* user_data;
77 
78         VkDebugReportCallbackEXT driver_handle;
79     };
80 
81     // TODO(jessehall): replace with std::shared_mutex when available in libc++
82     mutable std::shared_timed_mutex rwmutex_;
83     Node head_;
84 };
85 
86 class DebugReportLogger {
87    public:
DebugReportLogger(const VkInstanceCreateInfo & info)88     explicit DebugReportLogger(const VkInstanceCreateInfo& info)
89         : instance_pnext_(info.pNext), callbacks_(nullptr) {}
DebugReportLogger(const DebugReportCallbackList & callbacks)90     explicit DebugReportLogger(const DebugReportCallbackList& callbacks)
91         : instance_pnext_(nullptr), callbacks_(&callbacks) {}
92 
93     void Message(VkDebugReportFlagsEXT flags,
94                  VkDebugReportObjectTypeEXT object_type,
95                  uint64_t object,
96                  size_t location,
97                  int32_t message_code,
98                  const char* layer_prefix,
99                  const char* message) const;
100 
101 #define DEBUG_REPORT_LOGGER_PRINTF(fmt, args) \
102     __attribute__((format(printf, (fmt) + 1, (args) + 1)))
103     template <typename ObjectType>
Info(ObjectType object,const char * format,...)104     void Info(ObjectType object, const char* format, ...) const
105         DEBUG_REPORT_LOGGER_PRINTF(2, 3) {
106         va_list ap;
107         va_start(ap, format);
108         PrintV(VK_DEBUG_REPORT_INFORMATION_BIT_EXT, GetObjectType(object),
109                GetObjectUInt64(object), format, ap);
110         va_end(ap);
111     }
112 
113     template <typename ObjectType>
Warn(ObjectType object,const char * format,...)114     void Warn(ObjectType object, const char* format, ...) const
115         DEBUG_REPORT_LOGGER_PRINTF(2, 3) {
116         va_list ap;
117         va_start(ap, format);
118         PrintV(VK_DEBUG_REPORT_WARNING_BIT_EXT, GetObjectType(object),
119                GetObjectUInt64(object), format, ap);
120         va_end(ap);
121     }
122 
123     template <typename ObjectType>
Err(ObjectType object,const char * format,...)124     void Err(ObjectType object, const char* format, ...) const
125         DEBUG_REPORT_LOGGER_PRINTF(2, 3) {
126         va_list ap;
127         va_start(ap, format);
128         PrintV(VK_DEBUG_REPORT_ERROR_BIT_EXT, GetObjectType(object),
129                GetObjectUInt64(object), format, ap);
130         va_end(ap);
131     }
132 
133    private:
134     template <typename ObjectType>
GetObjectType(ObjectType)135     static VkDebugReportObjectTypeEXT GetObjectType(ObjectType) {
136         if (std::is_same<ObjectType, VkInstance>::value)
137             return VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT;
138         else if (std::is_same<ObjectType, VkPhysicalDevice>::value)
139             return VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT;
140         else if (std::is_same<ObjectType, VkDevice>::value)
141             return VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT;
142         else
143             return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;
144     }
145 
146     template <typename ObjectType>
GetObjectUInt64(ObjectType object)147     static uint64_t GetObjectUInt64(ObjectType object) {
148         return uint64_t(object);
149     }
150 
151 #define DEBUG_REPORT_LOGGER_VPRINTF(fmt) \
152     __attribute__((format(printf, (fmt) + 1, 0)))
153     void PrintV(VkDebugReportFlagsEXT flags,
154                 VkDebugReportObjectTypeEXT object_type,
155                 uint64_t object,
156                 const char* format,
157                 va_list ap) const DEBUG_REPORT_LOGGER_VPRINTF(4);
158 
159     const void* const instance_pnext_;
160     const DebugReportCallbackList* const callbacks_;
161 };
162 
163 }  // namespace driver
164 }  // namespace vulkan
165 
166 #endif  // LIBVULKAN_DEBUG_REPORT_H
167