debug_report.cpp revision 2676338dd692b7d1e1c276d82e6b0492db53ab2e
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#include "driver.h"
18
19namespace vulkan {
20namespace driver {
21
22DebugReportCallbackList::Node* DebugReportCallbackList::AddCallback(
23    const VkDebugReportCallbackCreateInfoEXT& info,
24    VkDebugReportCallbackEXT driver_handle,
25    const VkAllocationCallbacks& allocator) {
26    void* mem = allocator.pfnAllocation(allocator.pUserData, sizeof(Node),
27                                        alignof(Node),
28                                        VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
29    if (!mem)
30        return nullptr;
31
32    // initialize and prepend node to the list
33    std::lock_guard<decltype(rwmutex_)> lock(rwmutex_);
34    head_.next = new (mem) Node{head_.next, info.flags, info.pfnCallback,
35                                info.pUserData, driver_handle};
36
37    return head_.next;
38}
39
40void DebugReportCallbackList::RemoveCallback(
41    Node* node,
42    const VkAllocationCallbacks& allocator) {
43    // remove node from the list
44    {
45        std::lock_guard<decltype(rwmutex_)> lock(rwmutex_);
46        Node* prev = &head_;
47        while (prev && prev->next != node)
48            prev = prev->next;
49        prev->next = node->next;
50    }
51
52    allocator.pfnFree(allocator.pUserData, node);
53}
54
55void DebugReportCallbackList::Message(VkDebugReportFlagsEXT flags,
56                                      VkDebugReportObjectTypeEXT object_type,
57                                      uint64_t object,
58                                      size_t location,
59                                      int32_t message_code,
60                                      const char* layer_prefix,
61                                      const char* message) const {
62    std::shared_lock<decltype(rwmutex_)> lock(rwmutex_);
63    const Node* node = &head_;
64    while ((node = node->next)) {
65        if ((node->flags & flags) != 0) {
66            node->callback(flags, object_type, object, location, message_code,
67                           layer_prefix, message, node->user_data);
68        }
69    }
70}
71
72void DebugReportLogger::Message(VkDebugReportFlagsEXT flags,
73                                VkDebugReportObjectTypeEXT object_type,
74                                uint64_t object,
75                                size_t location,
76                                int32_t message_code,
77                                const char* layer_prefix,
78                                const char* message) const {
79    const VkDebugReportCallbackCreateInfoEXT* info =
80        reinterpret_cast<const VkDebugReportCallbackCreateInfoEXT*>(
81            instance_pnext_);
82    while (info) {
83        if (info->sType ==
84                VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT &&
85            (info->flags & flags) != 0) {
86            info->pfnCallback(flags, object_type, object, location,
87                              message_code, layer_prefix, message,
88                              info->pUserData);
89        }
90
91        info = reinterpret_cast<const VkDebugReportCallbackCreateInfoEXT*>(
92            info->pNext);
93    }
94
95    if (callbacks_) {
96        callbacks_->Message(flags, object_type, object, location, message_code,
97                            layer_prefix, message);
98    }
99}
100
101void DebugReportLogger::PrintV(VkDebugReportFlagsEXT flags,
102                               VkDebugReportObjectTypeEXT object_type,
103                               uint64_t object,
104                               const char* format,
105                               va_list ap) const {
106    char buf[1024];
107    int len = vsnprintf(buf, sizeof(buf), format, ap);
108
109    // message truncated
110    if (len >= static_cast<int>(sizeof(buf)))
111        memcpy(buf + sizeof(buf) - 4, "...", 4);
112
113    Message(flags, object_type, object, 0, 0, LOG_TAG, buf);
114}
115
116VkResult CreateDebugReportCallbackEXT(
117    VkInstance instance,
118    const VkDebugReportCallbackCreateInfoEXT* create_info,
119    const VkAllocationCallbacks* allocator,
120    VkDebugReportCallbackEXT* callback) {
121    const auto& driver = GetData(instance).driver;
122    VkDebugReportCallbackEXT driver_handle = VK_NULL_HANDLE;
123    if (driver.CreateDebugReportCallbackEXT) {
124        VkResult result = driver.CreateDebugReportCallbackEXT(
125            instance, create_info, allocator, &driver_handle);
126        if (result != VK_SUCCESS)
127            return result;
128    }
129
130    auto& callbacks = GetData(instance).debug_report_callbacks;
131    auto node = callbacks.AddCallback(
132        *create_info, driver_handle,
133        (allocator) ? *allocator : GetData(instance).allocator);
134    if (!node) {
135        if (driver_handle != VK_NULL_HANDLE) {
136            driver.DestroyDebugReportCallbackEXT(instance, driver_handle,
137                                                 allocator);
138        }
139
140        return VK_ERROR_OUT_OF_HOST_MEMORY;
141    }
142
143    *callback = callbacks.GetHandle(node);
144
145    return VK_SUCCESS;
146}
147
148void DestroyDebugReportCallbackEXT(VkInstance instance,
149                                   VkDebugReportCallbackEXT callback,
150                                   const VkAllocationCallbacks* allocator) {
151    if (callback == VK_NULL_HANDLE)
152        return;
153
154    auto& callbacks = GetData(instance).debug_report_callbacks;
155    auto node = callbacks.FromHandle(callback);
156    auto driver_handle = callbacks.GetDriverHandle(node);
157
158    callbacks.RemoveCallback(
159        node, (allocator) ? *allocator : GetData(instance).allocator);
160
161    if (driver_handle != VK_NULL_HANDLE) {
162        GetData(instance).driver.DestroyDebugReportCallbackEXT(
163            instance, driver_handle, allocator);
164    }
165}
166
167void DebugReportMessageEXT(VkInstance instance,
168                           VkDebugReportFlagsEXT flags,
169                           VkDebugReportObjectTypeEXT object_type,
170                           uint64_t object,
171                           size_t location,
172                           int32_t message_code,
173                           const char* layer_prefix,
174                           const char* message) {
175    if (GetData(instance).driver.DebugReportMessageEXT) {
176        GetData(instance).driver.DebugReportMessageEXT(
177            instance, flags, object_type, object, location, message_code,
178            layer_prefix, message);
179    } else {
180        GetData(instance).debug_report_callbacks.Message(
181            flags, object_type, object, location, message_code, layer_prefix,
182            message);
183    }
184}
185
186}  // namespace driver
187}  // namespace vulkan
188