| /* | |
| * Copyright 2016 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "driver.h" | |
| namespace vulkan { | |
| namespace driver { | |
| DebugReportCallbackList::Node* DebugReportCallbackList::AddCallback( | |
| const VkDebugReportCallbackCreateInfoEXT& info, | |
| VkDebugReportCallbackEXT driver_handle, | |
| const VkAllocationCallbacks& allocator) { | |
| void* mem = allocator.pfnAllocation(allocator.pUserData, sizeof(Node), | |
| alignof(Node), | |
| VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); | |
| if (!mem) | |
| return nullptr; | |
| // initialize and prepend node to the list | |
| std::lock_guard<decltype(rwmutex_)> lock(rwmutex_); | |
| head_.next = new (mem) Node{head_.next, info.flags, info.pfnCallback, | |
| info.pUserData, driver_handle}; | |
| return head_.next; | |
| } | |
| void DebugReportCallbackList::RemoveCallback( | |
| Node* node, | |
| const VkAllocationCallbacks& allocator) { | |
| // remove node from the list | |
| { | |
| std::lock_guard<decltype(rwmutex_)> lock(rwmutex_); | |
| Node* prev = &head_; | |
| while (prev && prev->next != node) | |
| prev = prev->next; | |
| if (prev) | |
| prev->next = node->next; | |
| } | |
| allocator.pfnFree(allocator.pUserData, node); | |
| } | |
| void DebugReportCallbackList::Message(VkDebugReportFlagsEXT flags, | |
| VkDebugReportObjectTypeEXT object_type, | |
| uint64_t object, | |
| size_t location, | |
| int32_t message_code, | |
| const char* layer_prefix, | |
| const char* message) const { | |
| std::shared_lock<decltype(rwmutex_)> lock(rwmutex_); | |
| const Node* node = &head_; | |
| while ((node = node->next)) { | |
| if ((node->flags & flags) != 0) { | |
| node->callback(flags, object_type, object, location, message_code, | |
| layer_prefix, message, node->user_data); | |
| } | |
| } | |
| } | |
| void DebugReportLogger::Message(VkDebugReportFlagsEXT flags, | |
| VkDebugReportObjectTypeEXT object_type, | |
| uint64_t object, | |
| size_t location, | |
| int32_t message_code, | |
| const char* layer_prefix, | |
| const char* message) const { | |
| const VkDebugReportCallbackCreateInfoEXT* info = | |
| reinterpret_cast<const VkDebugReportCallbackCreateInfoEXT*>( | |
| instance_pnext_); | |
| while (info) { | |
| if (info->sType == | |
| VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT && | |
| (info->flags & flags) != 0) { | |
| info->pfnCallback(flags, object_type, object, location, | |
| message_code, layer_prefix, message, | |
| info->pUserData); | |
| } | |
| info = reinterpret_cast<const VkDebugReportCallbackCreateInfoEXT*>( | |
| info->pNext); | |
| } | |
| if (callbacks_) { | |
| callbacks_->Message(flags, object_type, object, location, message_code, | |
| layer_prefix, message); | |
| } | |
| } | |
| void DebugReportLogger::PrintV(VkDebugReportFlagsEXT flags, | |
| VkDebugReportObjectTypeEXT object_type, | |
| uint64_t object, | |
| const char* format, | |
| va_list ap) const { | |
| char buf[1024]; | |
| int len = vsnprintf(buf, sizeof(buf), format, ap); | |
| // message truncated | |
| if (len >= static_cast<int>(sizeof(buf))) | |
| memcpy(buf + sizeof(buf) - 4, "...", 4); | |
| Message(flags, object_type, object, 0, 0, LOG_TAG, buf); | |
| } | |
| VkResult CreateDebugReportCallbackEXT( | |
| VkInstance instance, | |
| const VkDebugReportCallbackCreateInfoEXT* create_info, | |
| const VkAllocationCallbacks* allocator, | |
| VkDebugReportCallbackEXT* callback) { | |
| const auto& driver = GetData(instance).driver; | |
| VkDebugReportCallbackEXT driver_handle = VK_NULL_HANDLE; | |
| if (driver.CreateDebugReportCallbackEXT) { | |
| VkResult result = driver.CreateDebugReportCallbackEXT( | |
| instance, create_info, allocator, &driver_handle); | |
| if (result != VK_SUCCESS) | |
| return result; | |
| } | |
| auto& callbacks = GetData(instance).debug_report_callbacks; | |
| auto node = callbacks.AddCallback( | |
| *create_info, driver_handle, | |
| (allocator) ? *allocator : GetData(instance).allocator); | |
| if (!node) { | |
| if (driver_handle != VK_NULL_HANDLE) { | |
| driver.DestroyDebugReportCallbackEXT(instance, driver_handle, | |
| allocator); | |
| } | |
| return VK_ERROR_OUT_OF_HOST_MEMORY; | |
| } | |
| *callback = callbacks.GetHandle(node); | |
| return VK_SUCCESS; | |
| } | |
| void DestroyDebugReportCallbackEXT(VkInstance instance, | |
| VkDebugReportCallbackEXT callback, | |
| const VkAllocationCallbacks* allocator) { | |
| if (callback == VK_NULL_HANDLE) | |
| return; | |
| auto& callbacks = GetData(instance).debug_report_callbacks; | |
| auto node = callbacks.FromHandle(callback); | |
| auto driver_handle = callbacks.GetDriverHandle(node); | |
| callbacks.RemoveCallback( | |
| node, (allocator) ? *allocator : GetData(instance).allocator); | |
| if (driver_handle != VK_NULL_HANDLE) { | |
| GetData(instance).driver.DestroyDebugReportCallbackEXT( | |
| instance, driver_handle, allocator); | |
| } | |
| } | |
| void 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) { | |
| if (GetData(instance).driver.DebugReportMessageEXT) { | |
| GetData(instance).driver.DebugReportMessageEXT( | |
| instance, flags, object_type, object, location, message_code, | |
| layer_prefix, message); | |
| } else { | |
| GetData(instance).debug_report_callbacks.Message( | |
| flags, object_type, object, location, message_code, layer_prefix, | |
| message); | |
| } | |
| } | |
| } // namespace driver | |
| } // namespace vulkan |