1715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall/*
2715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall * Copyright 2016 The Android Open Source Project
3715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall *
4715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall * Licensed under the Apache License, Version 2.0 (the "License");
5715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall * you may not use this file except in compliance with the License.
6715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall * You may obtain a copy of the License at
7715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall *
8715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall *      http://www.apache.org/licenses/LICENSE-2.0
9715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall *
10715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall * Unless required by applicable law or agreed to in writing, software
11715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall * distributed under the License is distributed on an "AS IS" BASIS,
12715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall * See the License for the specific language governing permissions and
14715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall * limitations under the License.
15715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall */
16715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall
17715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall#ifndef LIBVULKAN_DEBUG_REPORT_H
18715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall#define LIBVULKAN_DEBUG_REPORT_H 1
19715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall
20bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu#include <stdarg.h>
21715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall#include <shared_mutex>
22bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu#include <vulkan/vulkan.h>
23715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall
24715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hallnamespace vulkan {
25622622377a1ac71a81a88e335f170c4a08835f06Chia-I Wunamespace driver {
26715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall
27715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall// clang-format off
28622622377a1ac71a81a88e335f170c4a08835f06Chia-I WuVKAPI_ATTR VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
29622622377a1ac71a81a88e335f170c4a08835f06Chia-I WuVKAPI_ATTR void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
30622622377a1ac71a81a88e335f170c4a08835f06Chia-I WuVKAPI_ATTR void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
31715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall// clang-format on
32715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall
33715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hallclass DebugReportCallbackList {
34a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu   private:
35a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu    // forward declaration
36a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu    struct Node;
37a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu
38715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall   public:
39715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall    DebugReportCallbackList()
40715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall        : head_{nullptr, 0, nullptr, nullptr, VK_NULL_HANDLE} {}
41715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall    DebugReportCallbackList(const DebugReportCallbackList&) = delete;
42715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall    DebugReportCallbackList& operator=(const DebugReportCallbackList&) = delete;
43715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall    ~DebugReportCallbackList() = default;
44715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall
45a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu    Node* AddCallback(const VkDebugReportCallbackCreateInfoEXT& info,
46a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu                      VkDebugReportCallbackEXT driver_handle,
47a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu                      const VkAllocationCallbacks& allocator);
48a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu    void RemoveCallback(Node* node, const VkAllocationCallbacks& allocator);
49a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu
50715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall    void Message(VkDebugReportFlagsEXT flags,
51715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall                 VkDebugReportObjectTypeEXT object_type,
52715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall                 uint64_t object,
53715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall                 size_t location,
54715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall                 int32_t message_code,
55715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall                 const char* layer_prefix,
56b3055f34650cd066a349e1e8cba294b05513ef2eChia-I Wu                 const char* message) const;
57715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall
58a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu    static Node* FromHandle(VkDebugReportCallbackEXT handle) {
59a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu        return reinterpret_cast<Node*>(uintptr_t(handle));
60a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu    }
61a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu
62a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu    static VkDebugReportCallbackEXT GetHandle(const Node* node) {
63a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu        return VkDebugReportCallbackEXT(reinterpret_cast<uintptr_t>(node));
64a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu    }
65a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu
66a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu    static VkDebugReportCallbackEXT GetDriverHandle(const Node* node) {
67a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu        return node->driver_handle;
68a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu    }
69a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu
70715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall   private:
71715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall    struct Node {
72715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall        Node* next;
73a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu
74715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall        VkDebugReportFlagsEXT flags;
75715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall        PFN_vkDebugReportCallbackEXT callback;
76a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu        void* user_data;
77a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu
78a0d40aaf12435fe82bc9c1612dbe97ea2a60da31Chia-I Wu        VkDebugReportCallbackEXT driver_handle;
79715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall    };
80715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall
81715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall    // TODO(jessehall): replace with std::shared_mutex when available in libc++
82b3055f34650cd066a349e1e8cba294b05513ef2eChia-I Wu    mutable std::shared_timed_mutex rwmutex_;
83715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall    Node head_;
84715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall};
85715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall
86bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wuclass DebugReportLogger {
87bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu   public:
88d56988d1fc3a42f5728f2ae707cc8faf73860745Chih-Hung Hsieh    explicit DebugReportLogger(const VkInstanceCreateInfo& info)
89bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        : instance_pnext_(info.pNext), callbacks_(nullptr) {}
90d56988d1fc3a42f5728f2ae707cc8faf73860745Chih-Hung Hsieh    explicit DebugReportLogger(const DebugReportCallbackList& callbacks)
91bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        : instance_pnext_(nullptr), callbacks_(&callbacks) {}
92bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu
93bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    void Message(VkDebugReportFlagsEXT flags,
94bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu                 VkDebugReportObjectTypeEXT object_type,
95bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu                 uint64_t object,
96bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu                 size_t location,
97bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu                 int32_t message_code,
98bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu                 const char* layer_prefix,
99bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu                 const char* message) const;
100bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu
101bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu#define DEBUG_REPORT_LOGGER_PRINTF(fmt, args) \
102bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    __attribute__((format(printf, (fmt) + 1, (args) + 1)))
103bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    template <typename ObjectType>
104bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    void Info(ObjectType object, const char* format, ...) const
105bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        DEBUG_REPORT_LOGGER_PRINTF(2, 3) {
106bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        va_list ap;
107bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        va_start(ap, format);
108bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        PrintV(VK_DEBUG_REPORT_INFORMATION_BIT_EXT, GetObjectType(object),
109bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu               GetObjectUInt64(object), format, ap);
110bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        va_end(ap);
111bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    }
112bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu
113bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    template <typename ObjectType>
114bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    void Warn(ObjectType object, const char* format, ...) const
115bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        DEBUG_REPORT_LOGGER_PRINTF(2, 3) {
116bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        va_list ap;
117bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        va_start(ap, format);
118bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        PrintV(VK_DEBUG_REPORT_WARNING_BIT_EXT, GetObjectType(object),
119bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu               GetObjectUInt64(object), format, ap);
120bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        va_end(ap);
121bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    }
122bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu
123bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    template <typename ObjectType>
124bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    void Err(ObjectType object, const char* format, ...) const
125bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        DEBUG_REPORT_LOGGER_PRINTF(2, 3) {
126bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        va_list ap;
127bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        va_start(ap, format);
128bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        PrintV(VK_DEBUG_REPORT_ERROR_BIT_EXT, GetObjectType(object),
129bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu               GetObjectUInt64(object), format, ap);
130bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        va_end(ap);
131bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    }
132bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu
133bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu   private:
134bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    template <typename ObjectType>
135bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    static VkDebugReportObjectTypeEXT GetObjectType(ObjectType) {
136bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        if (std::is_same<ObjectType, VkInstance>::value)
137bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu            return VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT;
138bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        else if (std::is_same<ObjectType, VkPhysicalDevice>::value)
139bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu            return VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT;
140bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        else if (std::is_same<ObjectType, VkDevice>::value)
141bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu            return VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT;
142bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        else
143bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu            return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;
144bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    }
145bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu
146bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    template <typename ObjectType>
147bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    static uint64_t GetObjectUInt64(ObjectType object) {
148bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu        return uint64_t(object);
149bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    }
150bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu
151bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu#define DEBUG_REPORT_LOGGER_VPRINTF(fmt) \
152bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    __attribute__((format(printf, (fmt) + 1, 0)))
153bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    void PrintV(VkDebugReportFlagsEXT flags,
154bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu                VkDebugReportObjectTypeEXT object_type,
155bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu                uint64_t object,
156bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu                const char* format,
157bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu                va_list ap) const DEBUG_REPORT_LOGGER_VPRINTF(4);
158bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu
159bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    const void* const instance_pnext_;
160bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu    const DebugReportCallbackList* const callbacks_;
161bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu};
162bc011fc4d78442d1f0167b04aea3484c62e0a92bChia-I Wu
163622622377a1ac71a81a88e335f170c4a08835f06Chia-I Wu}  // namespace driver
164715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall}  // namespace vulkan
165715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall
166715b86ac7d0853131b375ff786c87d8d87a762a1Jesse Hall#endif  // LIBVULKAN_DEBUG_REPORT_H
167