blob: 3dd88ea4b8ebbf22ac65b77ca95d08366120d9a5 [file] [log] [blame]
// 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 "flutter/vulkan/vulkan_debug_report.h"
#include <iomanip>
#include <vector>
#include "flutter/fml/compiler_specific.h"
#include "flutter/vulkan/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
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_ = {handle, [this](VkDebugReportCallbackEXT handle) {
vk.DestroyDebugReportCallbackEXT(application_, handle, nullptr);
}};
valid_ = true;
}
VulkanDebugReport::~VulkanDebugReport() = default;
bool VulkanDebugReport::IsValid() const {
return valid_;
}
} // namespace vulkan