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