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