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 | |
13 | namespace vulkan { |
14 | |
15 | static 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 | |
19 | static const VkDebugReportFlagsEXT kVulkanInfoFlags FML_ALLOW_UNUSED_TYPE = |
20 | VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT; |
21 | |
22 | std::string VulkanDebugReport::DebugExtensionName() { |
23 | return VK_EXT_DEBUG_REPORT_EXTENSION_NAME; |
24 | } |
25 | |
26 | static 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 | |
41 | static 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 | |
109 | static VKAPI_ATTR VkBool32 |
110 | OnVulkanDebugReportCallback(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 | |
181 | VulkanDebugReport::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 | |
218 | VulkanDebugReport::~VulkanDebugReport() = default; |
219 | |
220 | bool VulkanDebugReport::IsValid() const { |
221 | return valid_; |
222 | } |
223 | |
224 | } // namespace vulkan |
225 | |