1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "vulkan_debug_report.h"
6
7#include <iomanip>
8#include <vector>
9
10#include "flutter/fml/compiler_specific.h"
11#include "vulkan_utilities.h"
12
13namespace vulkan {
14
15static const VkDebugReportFlagsEXT kVulkanErrorFlags FML_ALLOW_UNUSED_TYPE =
16 VK_DEBUG_REPORT_WARNING_BIT_EXT |
17 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_ERROR_BIT_EXT;
18
19static const VkDebugReportFlagsEXT kVulkanInfoFlags FML_ALLOW_UNUSED_TYPE =
20 VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT;
21
22std::string VulkanDebugReport::DebugExtensionName() {
23 return VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
24}
25
26static const char* VkDebugReportFlagsEXTToString(VkDebugReportFlagsEXT flags) {
27 if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
28 return "Information";
29 } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
30 return "Warning";
31 } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
32 return "Performance Warning";
33 } else if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
34 return "Error";
35 } else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
36 return "Debug";
37 }
38 return "UNKNOWN";
39}
40
41static const char* VkDebugReportObjectTypeEXTToString(
42 VkDebugReportObjectTypeEXT type) {
43 switch (type) {
44 case VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT:
45 return "Unknown";
46 case VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT:
47 return "Instance";
48 case VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT:
49 return "Physical Device";
50 case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT:
51 return "Device";
52 case VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT:
53 return "Queue";
54 case VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT:
55 return "Semaphore";
56 case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT:
57 return "Command Buffer";
58 case VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT:
59 return "Fence";
60 case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT:
61 return "Device Memory";
62 case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT:
63 return "Buffer";
64 case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT:
65 return "Image";
66 case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT:
67 return "Event";
68 case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT:
69 return "Query Pool";
70 case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT:
71 return "Buffer View";
72 case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT:
73 return "Image_view";
74 case VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT:
75 return "Shader Module";
76 case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT:
77 return "Pipeline Cache";
78 case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT:
79 return "Pipeline Layout";
80 case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT:
81 return "Render Pass";
82 case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT:
83 return "Pipeline";
84 case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT:
85 return "Descriptor Set Layout";
86 case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT:
87 return "Sampler";
88 case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT:
89 return "Descriptor Pool";
90 case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT:
91 return "Descriptor Set";
92 case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT:
93 return "Framebuffer";
94 case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT:
95 return "Command Pool";
96 case VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT:
97 return "Surface";
98 case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT:
99 return "Swapchain";
100 case VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT:
101 return "Debug";
102 default:
103 break;
104 }
105
106 return "Unknown";
107}
108
109static VKAPI_ATTR VkBool32
110OnVulkanDebugReportCallback(VkDebugReportFlagsEXT flags,
111 VkDebugReportObjectTypeEXT object_type,
112 uint64_t object,
113 size_t location,
114 int32_t message_code,
115 const char* layer_prefix,
116 const char* message,
117 void* user_data) {
118 std::vector<std::pair<std::string, std::string>> items;
119
120 items.emplace_back("Severity", VkDebugReportFlagsEXTToString(flags));
121
122 items.emplace_back("Object Type",
123 VkDebugReportObjectTypeEXTToString(object_type));
124
125 items.emplace_back("Object Handle", std::to_string(object));
126
127 if (location != 0) {
128 items.emplace_back("Location", std::to_string(location));
129 }
130
131 if (message_code != 0) {
132 items.emplace_back("Message Code", std::to_string(message_code));
133 }
134
135 if (layer_prefix != nullptr) {
136 items.emplace_back("Layer", layer_prefix);
137 }
138
139 if (message != nullptr) {
140 items.emplace_back("Message", message);
141 }
142
143 size_t padding = 0;
144
145 for (const auto& item : items) {
146 padding = std::max(padding, item.first.size());
147 }
148
149 padding += 1;
150
151 std::stringstream stream;
152
153 stream << std::endl;
154
155 stream << "--- Vulkan Debug Report ----------------------------------------";
156
157 stream << std::endl;
158
159 for (const auto& item : items) {
160 stream << "| " << std::setw(static_cast<int>(padding)) << item.first
161 << std::setw(0) << ": " << item.second << std::endl;
162 }
163
164 stream << "-----------------------------------------------------------------";
165
166 if (flags & kVulkanErrorFlags) {
167 if (ValidationErrorsFatal()) {
168 FML_DCHECK(false) << stream.str();
169 } else {
170 FML_LOG(ERROR) << stream.str();
171 }
172 } else {
173 FML_LOG(INFO) << stream.str();
174 }
175
176 // Returning false tells the layer not to stop when the event occurs, so
177 // they see the same behavior with and without validation layers enabled.
178 return VK_FALSE;
179}
180
181VulkanDebugReport::VulkanDebugReport(
182 const VulkanProcTable& p_vk,
183 const VulkanHandle<VkInstance>& application)
184 : vk(p_vk), application_(application), valid_(false) {
185 if (!vk.CreateDebugReportCallbackEXT || !vk.DestroyDebugReportCallbackEXT) {
186 return;
187 }
188
189 if (!application_) {
190 return;
191 }
192
193 VkDebugReportFlagsEXT flags = kVulkanErrorFlags;
194 if (ValidationLayerInfoMessagesEnabled()) {
195 flags |= kVulkanInfoFlags;
196 }
197 const VkDebugReportCallbackCreateInfoEXT create_info = {
198 .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
199 .pNext = nullptr,
200 .flags = flags,
201 .pfnCallback = &vulkan::OnVulkanDebugReportCallback,
202 .pUserData = nullptr,
203 };
204
205 VkDebugReportCallbackEXT handle = VK_NULL_HANDLE;
206 if (VK_CALL_LOG_ERROR(vk.CreateDebugReportCallbackEXT(
207 application_, &create_info, nullptr, &handle)) != VK_SUCCESS) {
208 return;
209 }
210
211 handle_ = {handle, [this](VkDebugReportCallbackEXT handle) {
212 vk.DestroyDebugReportCallbackEXT(application_, handle, nullptr);
213 }};
214
215 valid_ = true;
216}
217
218VulkanDebugReport::~VulkanDebugReport() = default;
219
220bool VulkanDebugReport::IsValid() const {
221 return valid_;
222}
223
224} // namespace vulkan
225