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