Flutter Impeller
driver_info_vk.cc
Go to the documentation of this file.
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 
6 
7 #include <iomanip>
8 #include <sstream>
9 #include <string_view>
10 #include <unordered_map>
11 
12 #include "flutter/fml/build_config.h"
13 
14 namespace impeller {
15 
16 namespace {
17 const std::unordered_map<std::string_view, AdrenoGPU> kAdrenoVersions = {
18  // X
19  // Note: I don't know if these strings actually match as there don't seem to
20  // be any android devices that use these GPUs.
21  {"X185", AdrenoGPU::kAdrenoX185},
22  {"X145", AdrenoGPU::kAdrenoX145},
23  // 700
24  {"750", AdrenoGPU::kAdreno750},
25  {"740", AdrenoGPU::kAdreno740},
26  {"735", AdrenoGPU::kAdreno735},
27  {"721", AdrenoGPU::kAdreno732},
28  {"730", AdrenoGPU::kAdreno730},
29  {"725", AdrenoGPU::kAdreno725},
30  {"720", AdrenoGPU::kAdreno720},
31  {"710", AdrenoGPU::kAdreno710},
32  {"702", AdrenoGPU::kAdreno702},
33 
34  // 600
35  {"695", AdrenoGPU::kAdreno695},
36  {"690", AdrenoGPU::kAdreno690},
37  {"685", AdrenoGPU::kAdreno685},
38  {"680", AdrenoGPU::kAdreno680},
39  {"675", AdrenoGPU::kAdreno675},
40  {"663", AdrenoGPU::kAdreno663},
41  {"660", AdrenoGPU::kAdreno660},
42  {"650", AdrenoGPU::kAdreno650},
43  {"644", AdrenoGPU::kAdreno644},
44  {"643L", AdrenoGPU::kAdreno643L},
45  {"642", AdrenoGPU::kAdreno642},
46  {"642L", AdrenoGPU::kAdreno642L},
47  {"640", AdrenoGPU::kAdreno640},
48  {"630", AdrenoGPU::kAdreno630},
49  {"620", AdrenoGPU::kAdreno620},
50  {"619", AdrenoGPU::kAdreno619},
51  {"619L", AdrenoGPU::kAdreno619L},
52  {"618", AdrenoGPU::kAdreno618},
53  {"616", AdrenoGPU::kAdreno616},
54  {"615", AdrenoGPU::kAdreno615},
55  {"613", AdrenoGPU::kAdreno613},
56  {"612", AdrenoGPU::kAdreno612},
57  {"610", AdrenoGPU::kAdreno610},
58  {"608", AdrenoGPU::kAdreno608},
59  {"605", AdrenoGPU::kAdreno605},
60  // 500
61  {"540", AdrenoGPU::kAdreno540},
62  {"530", AdrenoGPU::kAdreno530},
63  {"512", AdrenoGPU::kAdreno512},
64  {"510", AdrenoGPU::kAdreno510},
65  {"509", AdrenoGPU::kAdreno509},
66  {"508", AdrenoGPU::kAdreno508},
67  {"506", AdrenoGPU::kAdreno506},
68  {"505", AdrenoGPU::kAdreno505},
69  {"504", AdrenoGPU::kAdreno504},
70 };
71 
72 const std::unordered_map<std::string_view, MaliGPU> kMaliVersions = {
73  // 5th Gen.
74  {"G925", MaliGPU::kG925},
75  {"G725", MaliGPU::kG725},
76  {"G625", MaliGPU::kG625},
77  {"G720", MaliGPU::kG720},
78  {"G620", MaliGPU::kG620},
79 
80  // Valhall
81  // Note: there is an Immortalis-G715 a Mali-G715
82  {"G715", MaliGPU::kG715},
83  {"G615", MaliGPU::kG615},
84  {"G710", MaliGPU::kG710},
85  {"G610", MaliGPU::kG610},
86  {"G510", MaliGPU::kG510},
87  {"G310", MaliGPU::kG310},
88  {"G78", MaliGPU::kG78},
89  {"G68", MaliGPU::kG68},
90  {"G77", MaliGPU::kG77},
91  {"G57", MaliGPU::kG57},
92 
93  // Bifrost
94  {"G76", MaliGPU::kG76},
95  {"G72", MaliGPU::kG72},
96  {"G52", MaliGPU::kG52},
97  {"G71", MaliGPU::kG71},
98  {"G51", MaliGPU::kG51},
99  {"G31", MaliGPU::kG31},
100 
101  // These might be Vulkan 1.0 Only.
102  {"T880", MaliGPU::kT880},
103  {"T860", MaliGPU::kT860},
104  {"T830", MaliGPU::kT830},
105  {"T820", MaliGPU::kT820},
106  {"T760", MaliGPU::kT760},
107 };
108 
109 constexpr std::array<std::pair<std::string_view, PowerVRGPU>, 6> kGpuSeriesMap =
110  {{
111  {"BXE", PowerVRGPU::kBXE},
112  {"BXM", PowerVRGPU::kBXM},
113  {"BXS", PowerVRGPU::kBXS},
114  {"BXT", PowerVRGPU::kBXT},
115  {"CXT", PowerVRGPU::kCXT},
116  {"DXT", PowerVRGPU::kDXT},
117  }};
118 } // namespace
119 
120 AdrenoGPU GetAdrenoVersion(std::string_view version) {
121  /// The format that Adreno names follow is "Adreno (TM) VERSION".
122  auto paren_pos = version.find("Adreno (TM) ");
123  if (paren_pos == std::string::npos) {
124  return AdrenoGPU::kUnknown;
125  }
126  auto version_string = version.substr(paren_pos + 12);
127  const auto& result = kAdrenoVersions.find(version_string);
128  if (result == kAdrenoVersions.end()) {
129  return AdrenoGPU::kUnknown;
130  }
131  return result->second;
132 }
133 
134 PowerVRGPU GetPowerVRVersion(std::string_view version) {
135  for (const auto& entry : kGpuSeriesMap) {
136  if (version.find(entry.first) != std::string::npos) {
137  return entry.second;
138  }
139  }
140 
141  return PowerVRGPU::kUnknown;
142 }
143 
144 MaliGPU GetMaliVersion(std::string_view version) {
145  // These names are usually Mali-VERSION or Mali-Version-EXTRA_CRAP.
146  auto dash_pos = version.find("Mali-");
147  if (dash_pos == std::string::npos) {
148  return MaliGPU::kUnknown;
149  }
150  auto version_string_with_trailing = version.substr(dash_pos + 5);
151  // Remove any trailing crap if present.
152  auto more_dash_pos = version_string_with_trailing.find("-");
153  if (more_dash_pos != std::string::npos) {
154  version_string_with_trailing =
155  version_string_with_trailing.substr(0, more_dash_pos);
156  }
157 
158  const auto& result = kMaliVersions.find(version_string_with_trailing);
159  if (result == kMaliVersions.end()) {
160  return MaliGPU::kUnknown;
161  }
162  return result->second;
163 }
164 
165 constexpr VendorVK IdentifyVendor(uint32_t vendor) {
166  // Check if the vendor has a PCI ID:
167  // https://pcisig.com/membership/member-companies
168  switch (vendor) {
169  case 0x1AE0:
170  return VendorVK::kGoogle;
171  case 0x168C:
172  case 0x17CB:
173  case 0x1969:
174  case 0x5143:
175  return VendorVK::kQualcomm;
176  case 0x13B5:
177  return VendorVK::kARM;
178  case 0x1010:
179  return VendorVK::kImgTec;
180  case 0x1002:
181  case 0x1022:
182  return VendorVK::kAMD;
183  case 0x10DE:
184  return VendorVK::kNvidia;
185  case 0x8086: // :)
186  return VendorVK::kIntel;
187  case 0x106B:
188  return VendorVK::kApple;
189  case 0x19E5:
190  return VendorVK::kHuawei;
191  case 0x144D:
192  return VendorVK::kSamsung;
193  }
194  // Check if the ID is a known Khronos vendor.
195  switch (vendor) {
196  case VK_VENDOR_ID_MESA:
197  return VendorVK::kMesa;
198  // There are others but have never been observed. These can be added as
199  // needed.
200  }
201  return VendorVK::kUnknown;
202 }
203 
204 constexpr const char* VendorToString(VendorVK vendor) {
205  switch (vendor) {
206  case VendorVK::kUnknown:
207  return "Unknown";
208  case VendorVK::kGoogle:
209  return "Google";
210  case VendorVK::kQualcomm:
211  return "Qualcomm";
212  case VendorVK::kARM:
213  return "ARM";
214  case VendorVK::kImgTec:
215  return "ImgTec PowerVR";
216  case VendorVK::kAMD:
217  return "AMD";
218  case VendorVK::kNvidia:
219  return "Nvidia";
220  case VendorVK::kIntel:
221  return "Intel";
222  case VendorVK::kMesa:
223  return "Mesa";
224  case VendorVK::kApple:
225  return "Apple";
226  case VendorVK::kHuawei:
227  return "Huawei";
228  case VendorVK::kSamsung:
229  return "Samsung";
230  }
231  FML_UNREACHABLE();
232 }
233 
234 constexpr const char* DeviceTypeToString(DeviceTypeVK type) {
235  switch (type) {
237  return "Unknown";
239  return "Integrated GPU";
241  return "Discrete GPU";
243  return "Virtual GPU";
244  case DeviceTypeVK::kCPU:
245  return "CPU";
246  }
247  FML_UNREACHABLE();
248 }
249 
250 constexpr DeviceTypeVK ToDeviceType(const vk::PhysicalDeviceType& type) {
251  switch (type) {
252  case vk::PhysicalDeviceType::eOther:
253  return DeviceTypeVK::kUnknown;
254  case vk::PhysicalDeviceType::eIntegratedGpu:
256  case vk::PhysicalDeviceType::eDiscreteGpu:
258  case vk::PhysicalDeviceType::eVirtualGpu:
260  case vk::PhysicalDeviceType::eCpu:
261  return DeviceTypeVK::kCPU;
262  break;
263  }
264  return DeviceTypeVK::kUnknown;
265 }
266 
267 DriverInfoVK::DriverInfoVK(const vk::PhysicalDevice& device) {
268  auto props = device.getProperties();
269  api_version_ = Version{VK_API_VERSION_MAJOR(props.apiVersion),
270  VK_API_VERSION_MINOR(props.apiVersion),
271  VK_API_VERSION_PATCH(props.apiVersion)};
272  vendor_ = IdentifyVendor(props.vendorID);
273  if (vendor_ == VendorVK::kUnknown) {
274  FML_LOG(WARNING) << "Unknown GPU Driver Vendor: " << props.vendorID
275  << ". This is not an error.";
276  }
277  type_ = ToDeviceType(props.deviceType);
278  if (props.deviceName.data() != nullptr) {
279  driver_name_ = props.deviceName.data();
280  }
281 
282  switch (vendor_) {
283  case VendorVK::kQualcomm:
284  adreno_gpu_ = GetAdrenoVersion(driver_name_);
285  break;
286  case VendorVK::kARM:
287  mali_gpu_ = GetMaliVersion(driver_name_);
288  break;
289  case VendorVK::kPowerVR:
290  powervr_gpu_ = GetPowerVRVersion(driver_name_);
291  break;
292  default:
293  break;
294  }
295 }
296 
297 DriverInfoVK::~DriverInfoVK() = default;
298 
300  return api_version_;
301 }
302 
304  return vendor_;
305 }
306 
308  return type_;
309 }
310 
311 const std::string& DriverInfoVK::GetDriverName() const {
312  return driver_name_;
313 }
314 
316  std::vector<std::pair<std::string, std::string>> items;
317  items.emplace_back("Name", driver_name_);
318  items.emplace_back("API Version", api_version_.ToString());
319  items.emplace_back("Vendor", VendorToString(vendor_));
320  items.emplace_back("Device Type", DeviceTypeToString(type_));
321  items.emplace_back("Is Emulator", std::to_string(IsEmulator()));
322 
323  size_t padding = 0;
324 
325  for (const auto& item : items) {
326  padding = std::max(padding, item.first.size());
327  }
328 
329  padding += 1;
330 
331  std::stringstream stream;
332 
333  stream << std::endl;
334 
335  stream << "--- Driver Information ------------------------------------------";
336 
337  stream << std::endl;
338 
339  for (const auto& item : items) {
340  stream << "| " << std::setw(static_cast<int>(padding)) << item.first
341  << std::setw(0) << ": " << item.second << std::endl;
342  }
343 
344  stream << "-----------------------------------------------------------------";
345 
346  FML_LOG(IMPORTANT) << stream.str();
347 }
348 
350 #if FML_OS_ANDROID
351  // Google SwiftShader on Android.
352  if (type_ == DeviceTypeVK::kCPU && vendor_ == VendorVK::kGoogle &&
353  driver_name_.find("SwiftShader") != std::string::npos) {
354  return true;
355  }
356 #endif // FML_OS_ANDROID
357  return false;
358 }
359 
361  // Disable Maleoon series GPUs, see:
362  // https://github.com/flutter/flutter/issues/156623
363  if (vendor_ == VendorVK::kHuawei) {
364  return true;
365  }
366 
367  if (vendor_ == VendorVK::kSamsung) {
368  // The first version of the Xclipse series GPU has reported
369  // bugs, unfortunately all versions of this GPU report the
370  // same driver version. Instead we use the Vulkan version
371  // as a proxy, assuming that any newer devices would not
372  // lower the supported Vulkan API level.
373  // See
374  // https://vulkan.gpuinfo.org/listreports.php?devicename=samsung+SM-S906B&platform=android
375  // https://github.com/flutter/flutter/issues/161334
376  return !api_version_.IsAtLeast(Version{1, 3, 0});
377  }
378 
379  // https://github.com/flutter/flutter/issues/161122
380  // https://github.com/flutter/flutter/issues/160960
381  // https://github.com/flutter/flutter/issues/160866
382  // https://github.com/flutter/flutter/issues/160804
383  // https://github.com/flutter/flutter/issues/160406
384  if (powervr_gpu_.has_value() && powervr_gpu_.value() < PowerVRGPU::kBXE) {
385  return true;
386  }
387  return false;
388 }
389 
390 std::optional<MaliGPU> DriverInfoVK::GetMaliGPUInfo() const {
391  return mali_gpu_;
392 }
393 
394 std::optional<AdrenoGPU> DriverInfoVK::GetAdrenoGPUInfo() const {
395  return adreno_gpu_;
396 }
397 
398 std::optional<PowerVRGPU> DriverInfoVK::GetPowerVRGPUInfo() const {
399  return powervr_gpu_;
400 }
401 
402 } // namespace impeller
GLenum type
const VendorVK & GetVendor() const
Get the vendor of the Vulkan implementation. This is a broad check and includes multiple drivers and ...
DriverInfoVK(const vk::PhysicalDevice &device)
std::optional< PowerVRGPU > GetPowerVRGPUInfo() const
Returns PowerVR GPU info if this is a PowerVR GPU, otherwise std::nullopt.
bool IsKnownBadDriver() const
Determines if the driver has been tested and determined to be non-functional.
const std::string & GetDriverName() const
Get the self-reported name of the graphics driver.
std::optional< AdrenoGPU > GetAdrenoGPUInfo() const
Returns Adreno GPU info if this is a Adreno GPU, otherwise std::nullopt.
void DumpToLog() const
Dumps the current driver info to the log.
std::optional< MaliGPU > GetMaliGPUInfo() const
Returns Mali GPU info if this is a Mali GPU, otherwise std::nullopt.
bool IsEmulator() const
Determines if the driver represents an emulator. There is no definitive way to tell if a driver is an...
const DeviceTypeVK & GetDeviceType() const
Get the device type. Typical use might be to check if the device is a CPU implementation.
const Version & GetAPIVersion() const
Gets the Vulkan API version. Should be at or above Vulkan 1.1 which is the Impeller baseline.
Vector2 padding
The halo padding in source space.
constexpr VendorVK IdentifyVendor(uint32_t vendor)
MaliGPU GetMaliVersion(std::string_view version)
AdrenoGPU GetAdrenoVersion(std::string_view version)
constexpr const char * VendorToString(VendorVK vendor)
constexpr const char * DeviceTypeToString(DeviceTypeVK type)
PowerVRGPU GetPowerVRVersion(std::string_view version)
constexpr DeviceTypeVK ToDeviceType(const vk::PhysicalDeviceType &type)
constexpr bool IsAtLeast(const Version &other) const
Definition: version.h:31
std::string ToString() const
Definition: version.cc:27