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: 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 58 static Node* FromHandle(VkDebugReportCallbackEXT handle) { 59 return reinterpret_cast<Node*>(uintptr_t(handle)); 60 } 61 62 static VkDebugReportCallbackEXT GetHandle(const Node* node) { 63 return VkDebugReportCallbackEXT(reinterpret_cast<uintptr_t>(node)); 64 } 65 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: 88 DebugReportLogger(const VkInstanceCreateInfo& info) 89 : instance_pnext_(info.pNext), callbacks_(nullptr) {} 90 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> 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> 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> 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> 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> 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