OSDN Git Service

vulkan: add DebugReportLogger
[android-x86/frameworks-native.git] / vulkan / libvulkan / debug_report.cpp
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
19 namespace vulkan {
20 namespace driver {
21
22 DebugReportCallbackList::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
40 void 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
55 void 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
72 void 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 == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
84             info->pfnCallback(flags, object_type, object, location,
85                               message_code, layer_prefix, message,
86                               info->pUserData);
87         }
88
89         info = reinterpret_cast<const VkDebugReportCallbackCreateInfoEXT*>(
90             info->pNext);
91     }
92
93     if (callbacks_) {
94         callbacks_->Message(flags, object_type, object, location, message_code,
95                             layer_prefix, message);
96     }
97 }
98
99 void DebugReportLogger::PrintV(VkDebugReportFlagsEXT flags,
100                                VkDebugReportObjectTypeEXT object_type,
101                                uint64_t object,
102                                const char* format,
103                                va_list ap) const {
104     char buf[1024];
105     int len = vsnprintf(buf, sizeof(buf), format, ap);
106
107     // message truncated
108     if (len >= static_cast<int>(sizeof(buf)))
109         memcpy(buf + sizeof(buf) - 4, "...", 4);
110
111     Message(flags, object_type, object, 0, 0, LOG_TAG, buf);
112 }
113
114 VkResult CreateDebugReportCallbackEXT(
115     VkInstance instance,
116     const VkDebugReportCallbackCreateInfoEXT* create_info,
117     const VkAllocationCallbacks* allocator,
118     VkDebugReportCallbackEXT* callback) {
119     const auto& driver = GetData(instance).driver;
120     VkDebugReportCallbackEXT driver_handle = VK_NULL_HANDLE;
121     if (driver.CreateDebugReportCallbackEXT) {
122         VkResult result = driver.CreateDebugReportCallbackEXT(
123             instance, create_info, allocator, &driver_handle);
124         if (result != VK_SUCCESS)
125             return result;
126     }
127
128     auto& callbacks = GetData(instance).debug_report_callbacks;
129     auto node = callbacks.AddCallback(
130         *create_info, driver_handle,
131         (allocator) ? *allocator : GetData(instance).allocator);
132     if (!node) {
133         if (driver_handle != VK_NULL_HANDLE) {
134             driver.DestroyDebugReportCallbackEXT(instance, driver_handle,
135                                                  allocator);
136         }
137
138         return VK_ERROR_OUT_OF_HOST_MEMORY;
139     }
140
141     *callback = callbacks.GetHandle(node);
142
143     return VK_SUCCESS;
144 }
145
146 void DestroyDebugReportCallbackEXT(VkInstance instance,
147                                    VkDebugReportCallbackEXT callback,
148                                    const VkAllocationCallbacks* allocator) {
149     if (callback == VK_NULL_HANDLE)
150         return;
151
152     auto& callbacks = GetData(instance).debug_report_callbacks;
153     auto node = callbacks.FromHandle(callback);
154     auto driver_handle = callbacks.GetDriverHandle(node);
155
156     callbacks.RemoveCallback(
157         node, (allocator) ? *allocator : GetData(instance).allocator);
158
159     if (driver_handle != VK_NULL_HANDLE) {
160         GetData(instance).driver.DestroyDebugReportCallbackEXT(
161             instance, driver_handle, allocator);
162     }
163 }
164
165 void DebugReportMessageEXT(VkInstance instance,
166                            VkDebugReportFlagsEXT flags,
167                            VkDebugReportObjectTypeEXT object_type,
168                            uint64_t object,
169                            size_t location,
170                            int32_t message_code,
171                            const char* layer_prefix,
172                            const char* message) {
173     if (GetData(instance).driver.DebugReportMessageEXT) {
174         GetData(instance).driver.DebugReportMessageEXT(
175             instance, flags, object_type, object, location, message_code,
176             layer_prefix, message);
177     } else {
178         GetData(instance).debug_report_callbacks.Message(
179             flags, object_type, object, location, message_code, layer_prefix,
180             message);
181     }
182 }
183
184 }  // namespace driver
185 }  // namespace vulkan