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