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