| // 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 "impeller/renderer/backend/vulkan/debug_report_vk.h" |
| |
| #include "impeller/base/validation.h" |
| #include "impeller/renderer/backend/vulkan/capabilities_vk.h" |
| |
| namespace impeller { |
| |
| DebugReportVK::DebugReportVK(const CapabilitiesVK& caps, |
| const vk::Instance& instance) { |
| if (!caps.AreValidationsEnabled()) { |
| is_valid_ = true; |
| return; |
| } |
| |
| vk::DebugUtilsMessengerCreateInfoEXT messenger_info; |
| messenger_info.messageSeverity = |
| vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | |
| vk::DebugUtilsMessageSeverityFlagBitsEXT::eError; |
| messenger_info.messageType = |
| vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | |
| vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance | |
| vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation; |
| messenger_info.pUserData = this; |
| messenger_info.pfnUserCallback = DebugUtilsMessengerCallback; |
| |
| auto messenger = instance.createDebugUtilsMessengerEXTUnique(messenger_info); |
| |
| if (messenger.result != vk::Result::eSuccess) { |
| FML_LOG(ERROR) << "Could not create debug messenger: " |
| << vk::to_string(messenger.result); |
| return; |
| } |
| |
| messenger_ = std::move(messenger.value); |
| is_valid_ = true; |
| } |
| |
| DebugReportVK::~DebugReportVK() = default; |
| |
| bool DebugReportVK::IsValid() const { |
| return is_valid_; |
| } |
| |
| static std::string JoinLabels(const VkDebugUtilsLabelEXT* labels, |
| size_t count) { |
| std::stringstream stream; |
| for (size_t i = 0u; i < count; i++) { |
| stream << labels[i].pLabelName; |
| if (i != count - 1u) { |
| stream << ", "; |
| } |
| } |
| return stream.str(); |
| } |
| |
| static std::string JoinVKDebugUtilsObjectNameInfoEXT( |
| const VkDebugUtilsObjectNameInfoEXT* names, |
| size_t count) { |
| std::stringstream stream; |
| for (size_t i = 0u; i < count; i++) { |
| stream << vk::to_string(vk::ObjectType(names[i].objectType)) << " [" |
| << names[i].objectHandle << "] ["; |
| if (names[i].pObjectName != nullptr) { |
| stream << names[i].pObjectName; |
| } else { |
| stream << "UNNAMED"; |
| } |
| stream << "]"; |
| if (i != count - 1u) { |
| stream << ", "; |
| } |
| } |
| return stream.str(); |
| } |
| |
| VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportVK::DebugUtilsMessengerCallback( |
| VkDebugUtilsMessageSeverityFlagBitsEXT severity, |
| VkDebugUtilsMessageTypeFlagsEXT type, |
| const VkDebugUtilsMessengerCallbackDataEXT* callback_data, |
| void* debug_report) { |
| auto result = |
| reinterpret_cast<DebugReportVK*>(debug_report) |
| ->OnDebugCallback( |
| static_cast<vk::DebugUtilsMessageSeverityFlagBitsEXT>( |
| severity), // |
| static_cast<vk::DebugUtilsMessageTypeFlagsEXT>(type), // |
| callback_data // |
| ); |
| switch (result) { |
| case Result::kContinue: |
| return VK_FALSE; |
| case Result::kAbort: |
| return VK_TRUE; |
| } |
| return VK_FALSE; |
| } |
| |
| DebugReportVK::Result DebugReportVK::OnDebugCallback( |
| vk::DebugUtilsMessageSeverityFlagBitsEXT severity, |
| vk::DebugUtilsMessageTypeFlagsEXT type, |
| const VkDebugUtilsMessengerCallbackDataEXT* data) { |
| // Issue in older versions of the SDK. |
| // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/3554 |
| if (strstr(data->pMessageIdName, "CoreValidation-Shader-OutputNotConsumed") != |
| nullptr) { |
| return Result::kContinue; |
| } |
| |
| // This is a real error but we can't fix it due to our headers being too |
| // old. More more details see: |
| // https://vulkan.lunarg.com/doc/view/1.3.224.1/mac/1.3-extensions/vkspec.html#VUID-VkImageViewCreateInfo-imageViewFormatSwizzle-04465 |
| // This validation error currently only trips on macOS due to the use of |
| // texture swizzles. |
| if (data->messageIdNumber == static_cast<int32_t>(0x82ae5050)) { |
| return Result::kContinue; |
| } |
| |
| std::vector<std::pair<std::string, std::string>> items; |
| |
| items.emplace_back("Severity", vk::to_string(severity)); |
| |
| items.emplace_back("Type", vk::to_string(type)); |
| |
| if (data->pMessageIdName) { |
| items.emplace_back("ID Name", data->pMessageIdName); |
| } |
| |
| items.emplace_back("ID Number", std::to_string(data->messageIdNumber)); |
| |
| if (auto queues = JoinLabels(data->pQueueLabels, data->queueLabelCount); |
| !queues.empty()) { |
| items.emplace_back("Queue Breadcrumbs", std::move(queues)); |
| } else { |
| items.emplace_back("Queue Breadcrumbs", "[NONE]"); |
| } |
| |
| if (auto cmd_bufs = JoinLabels(data->pCmdBufLabels, data->cmdBufLabelCount); |
| !cmd_bufs.empty()) { |
| items.emplace_back("CMD Buffer Breadcrumbs", std::move(cmd_bufs)); |
| } else { |
| items.emplace_back("CMD Buffer Breadcrumbs", "[NONE]"); |
| } |
| |
| if (auto related = |
| JoinVKDebugUtilsObjectNameInfoEXT(data->pObjects, data->objectCount); |
| !related.empty()) { |
| items.emplace_back("Related Objects", std::move(related)); |
| } |
| |
| if (data->pMessage) { |
| items.emplace_back("Trigger", data->pMessage); |
| } |
| |
| 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 (type == vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance) { |
| FML_LOG(INFO) << stream.str(); |
| } else { |
| VALIDATION_LOG << stream.str(); |
| } |
| |
| return Result::kContinue; |
| } |
| |
| } // namespace impeller |