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