|  | /* | 
|  | * 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 |