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