Home | History | Annotate | Download | only in libvulkan
      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     explicit DebugReportLogger(const VkInstanceCreateInfo& info)
     89         : instance_pnext_(info.pNext), callbacks_(nullptr) {}
     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>
    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