• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "flutter/fml/compiler_specific.h"
11 #include "flutter/vulkan/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 
DebugExtensionName()22 std::string VulkanDebugReport::DebugExtensionName() {
23   return VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
24 }
25 
VkDebugReportFlagsEXTToString(VkDebugReportFlagsEXT flags)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 
VkDebugReportObjectTypeEXTToString(VkDebugReportObjectTypeEXT type)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
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)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 
VulkanDebugReport(const VulkanProcTable & p_vk,const VulkanHandle<VkInstance> & application)181 VulkanDebugReport::VulkanDebugReport(
182     const VulkanProcTable& p_vk,
183     const VulkanHandle<VkInstance>& application)
184     : vk(p_vk), application_(application), valid_(false) {
185   if (!IsDebuggingEnabled() || !vk.CreateDebugReportCallbackEXT ||
186       !vk.DestroyDebugReportCallbackEXT) {
187     return;
188   }
189 
190   if (!application_) {
191     return;
192   }
193 
194   VkDebugReportFlagsEXT flags = kVulkanErrorFlags;
195   if (ValidationLayerInfoMessagesEnabled())
196     flags |= kVulkanInfoFlags;
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 
IsValid() const220 bool VulkanDebugReport::IsValid() const {
221   return valid_;
222 }
223 
224 }  // namespace vulkan
225