| // Copyright 2013 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "vulkan_debug_report.h" | |
| #include <algorithm> | |
| #include <iomanip> | |
| #include <vector> | |
| #include "flutter/fml/compiler_specific.h" | |
| #include "vulkan_utilities.h" | |
| namespace vulkan { | |
| static const VkDebugReportFlagsEXT kVulkanErrorFlags FML_ALLOW_UNUSED_TYPE = | |
| VK_DEBUG_REPORT_WARNING_BIT_EXT | | |
| VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_ERROR_BIT_EXT; | |
| static const VkDebugReportFlagsEXT kVulkanInfoFlags FML_ALLOW_UNUSED_TYPE = | |
| VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT; | |
| std::string VulkanDebugReport::DebugExtensionName() { | |
| return VK_EXT_DEBUG_REPORT_EXTENSION_NAME; | |
| } | |
| static const char* VkDebugReportFlagsEXTToString(VkDebugReportFlagsEXT flags) { | |
| if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { | |
| return "Information"; | |
| } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { | |
| return "Warning"; | |
| } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { | |
| return "Performance Warning"; | |
| } else if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { | |
| return "Error"; | |
| } else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { | |
| return "Debug"; | |
| } | |
| return "UNKNOWN"; | |
| } | |
| static const char* VkDebugReportObjectTypeEXTToString( | |
| VkDebugReportObjectTypeEXT type) { | |
| switch (type) { | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT: | |
| return "Unknown"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT: | |
| return "Instance"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT: | |
| return "Physical Device"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT: | |
| return "Device"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT: | |
| return "Queue"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT: | |
| return "Semaphore"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT: | |
| return "Command Buffer"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT: | |
| return "Fence"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT: | |
| return "Device Memory"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: | |
| return "Buffer"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: | |
| return "Image"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT: | |
| return "Event"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT: | |
| return "Query Pool"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT: | |
| return "Buffer View"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT: | |
| return "Image_view"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT: | |
| return "Shader Module"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT: | |
| return "Pipeline Cache"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT: | |
| return "Pipeline Layout"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT: | |
| return "Render Pass"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT: | |
| return "Pipeline"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT: | |
| return "Descriptor Set Layout"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: | |
| return "Sampler"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT: | |
| return "Descriptor Pool"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT: | |
| return "Descriptor Set"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT: | |
| return "Framebuffer"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: | |
| return "Command Pool"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT: | |
| return "Surface"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: | |
| return "Swapchain"; | |
| case VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT: | |
| return "Debug"; | |
| default: | |
| break; | |
| } | |
| return "Unknown"; | |
| } | |
| static VKAPI_ATTR VkBool32 | |
| #ifdef WIN32 | |
| __stdcall | |
| #endif | |
| OnVulkanDebugReportCallback(VkDebugReportFlagsEXT flags, | |
| VkDebugReportObjectTypeEXT object_type, | |
| uint64_t object, | |
| size_t location, | |
| int32_t message_code, | |
| const char* layer_prefix, | |
| const char* message, | |
| void* user_data) { | |
| std::vector<std::pair<std::string, std::string>> items; | |
| items.emplace_back("Severity", VkDebugReportFlagsEXTToString(flags)); | |
| items.emplace_back("Object Type", | |
| VkDebugReportObjectTypeEXTToString(object_type)); | |
| items.emplace_back("Object Handle", std::to_string(object)); | |
| if (location != 0) { | |
| items.emplace_back("Location", std::to_string(location)); | |
| } | |
| if (message_code != 0) { | |
| items.emplace_back("Message Code", std::to_string(message_code)); | |
| } | |
| if (layer_prefix != nullptr) { | |
| items.emplace_back("Layer", layer_prefix); | |
| } | |
| if (message != nullptr) { | |
| items.emplace_back("Message", message); | |
| } | |
| size_t padding = 0; | |
| for (const auto& item : items) { | |
| padding = std::max(padding, item.first.size()); | |
| } | |
| padding += 1; | |
| std::stringstream stream; | |
| stream << std::endl; | |
| stream << "--- Vulkan Debug Report ----------------------------------------"; | |
| stream << std::endl; | |
| for (const auto& item : items) { | |
| stream << "| " << std::setw(static_cast<int>(padding)) << item.first | |
| << std::setw(0) << ": " << item.second << std::endl; | |
| } | |
| stream << "-----------------------------------------------------------------"; | |
| if (flags & kVulkanErrorFlags) { | |
| if (ValidationErrorsFatal()) { | |
| FML_DCHECK(false) << stream.str(); | |
| } else { | |
| FML_LOG(ERROR) << stream.str(); | |
| } | |
| } else { | |
| FML_LOG(INFO) << stream.str(); | |
| } | |
| // Returning false tells the layer not to stop when the event occurs, so | |
| // they see the same behavior with and without validation layers enabled. | |
| return VK_FALSE; | |
| } | |
| VulkanDebugReport::VulkanDebugReport( | |
| const VulkanProcTable& p_vk, | |
| const VulkanHandle<VkInstance>& application) | |
| : vk(p_vk), application_(application), valid_(false) { | |
| if (!vk.CreateDebugReportCallbackEXT || !vk.DestroyDebugReportCallbackEXT) { | |
| return; | |
| } | |
| if (!application_) { | |
| return; | |
| } | |
| VkDebugReportFlagsEXT flags = kVulkanErrorFlags; | |
| if (ValidationLayerInfoMessagesEnabled()) { | |
| flags |= kVulkanInfoFlags; | |
| } | |
| const VkDebugReportCallbackCreateInfoEXT create_info = { | |
| .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT, | |
| .pNext = nullptr, | |
| .flags = flags, | |
| .pfnCallback = &vulkan::OnVulkanDebugReportCallback, | |
| .pUserData = nullptr, | |
| }; | |
| VkDebugReportCallbackEXT handle = VK_NULL_HANDLE; | |
| if (VK_CALL_LOG_ERROR(vk.CreateDebugReportCallbackEXT( | |
| application_, &create_info, nullptr, &handle)) != VK_SUCCESS) { | |
| return; | |
| } | |
| handle_ = VulkanHandle<VkDebugReportCallbackEXT>{ | |
| handle, [this](VkDebugReportCallbackEXT handle) { | |
| vk.DestroyDebugReportCallbackEXT(application_, handle, nullptr); | |
| }}; | |
| valid_ = true; | |
| } | |
| VulkanDebugReport::~VulkanDebugReport() = default; | |
| bool VulkanDebugReport::IsValid() const { | |
| return valid_; | |
| } | |
| } // namespace vulkan |