Skip to content

Commit

Permalink
[Impeller] add parsing of known GPU models (#55196)
Browse files Browse the repository at this point in the history
We will need to denylist certain Vulkan drivers. This is easier to do if we have some mechanism of determining which GPU model we're currently using. This doesn't add any new denylisting, it just ads a mechanism to parse the driver name into an enum. I mean, there are only so many SoCs, right?

See also flutter/flutter#155185
  • Loading branch information
jonahwilliams authored Oct 7, 2024
1 parent a2715f0 commit e84e303
Show file tree
Hide file tree
Showing 3 changed files with 313 additions and 21 deletions.
160 changes: 152 additions & 8 deletions impeller/renderer/backend/vulkan/driver_info_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,138 @@
#include <iomanip>
#include <sstream>
#include <string_view>
#include <unordered_map>

#include "flutter/fml/build_config.h"

namespace impeller {

/// Non functional Vulkan driver, see:
/// https://github.com/flutter/flutter/issues/154103
///
/// Reports "VK_INCOMPLETE" when compiling certain entity shader with
/// vkCreateGraphicsPipelines, which is not a valid return status.
constexpr std::string_view kAdreno630 = "Adreno (TM) 630";
const std::unordered_map<std::string_view, AdrenoGPU> kAdrenoVersions = {
// X
// Note: I don't know if these strings actually match as there don't seem to
// be any android devices that use these GPUs.
{"X185", AdrenoGPU::kAdrenoX185},
{"X145", AdrenoGPU::kAdrenoX145},
// 700
{"750", AdrenoGPU::kAdreno750},
{"740", AdrenoGPU::kAdreno740},
{"735", AdrenoGPU::kAdreno735},
{"721", AdrenoGPU::kAdreno732},
{"730", AdrenoGPU::kAdreno730},
{"725", AdrenoGPU::kAdreno725},
{"720", AdrenoGPU::kAdreno720},
{"710", AdrenoGPU::kAdreno710},
{"702", AdrenoGPU::kAdreno702},

// 600
{"695", AdrenoGPU::kAdreno695},
{"690", AdrenoGPU::kAdreno690},
{"685", AdrenoGPU::kAdreno685},
{"680", AdrenoGPU::kAdreno680},
{"675", AdrenoGPU::kAdreno675},
{"663", AdrenoGPU::kAdreno663},
{"660", AdrenoGPU::kAdreno660},
{"650", AdrenoGPU::kAdreno650},
{"644", AdrenoGPU::kAdreno644},
{"643L", AdrenoGPU::kAdreno643L},
{"642", AdrenoGPU::kAdreno642},
{"642L", AdrenoGPU::kAdreno642L},
{"640", AdrenoGPU::kAdreno640},
{"630", AdrenoGPU::kAdreno630},
{"620", AdrenoGPU::kAdreno620},
{"619", AdrenoGPU::kAdreno619},
{"619L", AdrenoGPU::kAdreno619L},
{"618", AdrenoGPU::kAdreno618},
{"616", AdrenoGPU::kAdreno616},
{"615", AdrenoGPU::kAdreno615},
{"613", AdrenoGPU::kAdreno613},
{"612", AdrenoGPU::kAdreno612},
{"610", AdrenoGPU::kAdreno610},
{"608", AdrenoGPU::kAdreno608},
{"605", AdrenoGPU::kAdreno605},
// 500
{"540", AdrenoGPU::kAdreno540},
{"530", AdrenoGPU::kAdreno530},
{"512", AdrenoGPU::kAdreno512},
{"510", AdrenoGPU::kAdreno510},
{"509", AdrenoGPU::kAdreno509},
{"508", AdrenoGPU::kAdreno508},
{"506", AdrenoGPU::kAdreno506},
{"505", AdrenoGPU::kAdreno505},
{"504", AdrenoGPU::kAdreno504},
};

const std::unordered_map<std::string_view, MaliGPU> kMaliVersions = {
// 5th Gen.
{"G925", MaliGPU::kG925},
{"G725", MaliGPU::kG725},
{"G625", MaliGPU::kG625},
{"G720", MaliGPU::kG720},
{"G620", MaliGPU::kG620},

// Valhall
// Note: there is an Immortalis-G715 a Mali-G715
{"G715", MaliGPU::kG715},
{"G615", MaliGPU::kG615},
{"G710", MaliGPU::kG710},
{"G610", MaliGPU::kG610},
{"G510", MaliGPU::kG510},
{"G310", MaliGPU::kG310},
{"G78", MaliGPU::kG78},
{"G68", MaliGPU::kG68},
{"G77", MaliGPU::kG77},
{"G57", MaliGPU::kG57},

// Bifrost
{"G76", MaliGPU::kG76},
{"G72", MaliGPU::kG72},
{"G52", MaliGPU::kG52},
{"G71", MaliGPU::kG71},
{"G51", MaliGPU::kG51},
{"G31", MaliGPU::kG31},

// These might be Vulkan 1.0 Only.
{"T880", MaliGPU::kT880},
{"T860", MaliGPU::kT860},
{"T830", MaliGPU::kT830},
{"T820", MaliGPU::kT820},
{"T760", MaliGPU::kT760},
};

AdrenoGPU GetAdrenoVersion(std::string_view version) {
/// The format that Adreno names follow is "Adreno (TM) VERSION".
auto paren_pos = version.find("Adreno (TM) ");
if (paren_pos == std::string::npos) {
return AdrenoGPU::kUnknown;
}
auto version_string = version.substr(paren_pos + 12);
const auto& result = kAdrenoVersions.find(version_string);
if (result == kAdrenoVersions.end()) {
return AdrenoGPU::kUnknown;
}
return result->second;
}

MaliGPU GetMaliVersion(std::string_view version) {
// These names are usually Mali-VERSION or Mali-Version-EXTRA_CRAP.
auto dash_pos = version.find("Mali-");
if (dash_pos == std::string::npos) {
return MaliGPU::kUnknown;
}
auto version_string_with_trailing = version.substr(dash_pos + 5);
// Remove any trailing crap if present.
auto more_dash_pos = version_string_with_trailing.find("-");
if (more_dash_pos != std::string::npos) {
version_string_with_trailing =
version_string_with_trailing.substr(0, more_dash_pos);
}

const auto& result = kMaliVersions.find(version_string_with_trailing);
if (result == kMaliVersions.end()) {
return MaliGPU::kUnknown;
}
return result->second;
}

constexpr VendorVK IdentifyVendor(uint32_t vendor) {
// Check if the vendor has a PCI ID:
Expand Down Expand Up @@ -131,6 +252,17 @@ DriverInfoVK::DriverInfoVK(const vk::PhysicalDevice& device) {
if (props.deviceName.data() != nullptr) {
driver_name_ = props.deviceName.data();
}

switch (vendor_) {
case VendorVK::kQualcomm:
adreno_gpu_ = GetAdrenoVersion(driver_name_);
break;
case VendorVK::kARM:
mali_gpu_ = GetMaliVersion(driver_name_);
break;
default:
break;
}
}

DriverInfoVK::~DriverInfoVK() = default;
Expand Down Expand Up @@ -197,8 +329,20 @@ bool DriverInfoVK::IsEmulator() const {
}

bool DriverInfoVK::IsKnownBadDriver() const {
if (vendor_ == VendorVK::kQualcomm && driver_name_ == kAdreno630) {
return true;
if (adreno_gpu_.has_value()) {
auto adreno = adreno_gpu_.value();
switch (adreno) {
// see:
// https://github.com/flutter/flutter/issues/154103
//
// Reports "VK_INCOMPLETE" when compiling certain entity shader with
// vkCreateGraphicsPipelines, which is not a valid return status.
// See https://github.com/flutter/flutter/issues/155185 .
case AdrenoGPU::kAdreno630:
return true;
default:
return false;
}
}
return false;
}
Expand Down
108 changes: 108 additions & 0 deletions impeller/renderer/backend/vulkan/driver_info_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,104 @@

namespace impeller {

// https://en.wikipedia.org/wiki/Adreno
enum class AdrenoGPU {
// Unknown GPU, likely newer model.
kUnknown,
// X
kAdrenoX185,
kAdrenoX145,
// 700s
kAdreno750,
kAdreno740,
kAdreno735,
kAdreno732,
kAdreno730,
kAdreno725,
kAdreno720,
kAdreno710,
kAdreno702,
// 600s
kAdreno695,
kAdreno690,
kAdreno685,
kAdreno680,
kAdreno675,
kAdreno663,
kAdreno660,
kAdreno650,
kAdreno644,
kAdreno643L,
kAdreno642,
kAdreno642L,
// The 640 is the first GPU inside an Android device with upgradable drivers.
// Anything before this point exhibiting broken behavior is broken forever.
kAdreno640,
kAdreno630,
kAdreno620,
kAdreno619,
kAdreno619L,
kAdreno618,
kAdreno616,
kAdreno615,
kAdreno613,
kAdreno612,
kAdreno610,
kAdreno608,
kAdreno605,
// 500s
kAdreno540,
kAdreno530,
kAdreno512,
kAdreno510,
kAdreno509,
kAdreno508,
kAdreno506,
kAdreno505,
kAdreno504,
// I don't think the 400 series will ever run Vulkan, but if some show up we
// can add them here.
};

// https://en.wikipedia.org/wiki/Mali_(processor)
enum class MaliGPU {
kUnknown,
// 5th Gen
kG925,
kG725,
kG625,
kG720,
kG620,

// Valhall
// Note: there is an Immortalis-G715 a Mali-G715
kG715,
kG615,
kG710,
kG610,
kG510,
kG310,
kG78,
kG68,
kG77,
kG57,

// Bifrost
kG76,
kG72,
kG52,
kG71,
kG51,
kG31,

// These might be Vulkan 1.0 Only.
kT880,
kT860,
kT830,
kT820,
kT760,
};

enum class VendorVK {
kUnknown,
//----------------------------------------------------------------------------
Expand Down Expand Up @@ -55,6 +153,12 @@ enum class DeviceTypeVK {
kCPU,
};

// visible for testing.
AdrenoGPU GetAdrenoVersion(std::string_view version);

// visible for testing.
MaliGPU GetMaliVersion(std::string_view version);

//------------------------------------------------------------------------------
/// @brief Get information about the Vulkan driver.
///
Expand Down Expand Up @@ -139,6 +243,10 @@ class DriverInfoVK {
Version api_version_;
VendorVK vendor_ = VendorVK::kUnknown;
DeviceTypeVK type_ = DeviceTypeVK::kUnknown;
// If the VendorVK is VendorVK::kQualcomm, this will be populated with the
// identified Adreno GPU.
std::optional<AdrenoGPU> adreno_gpu_ = std::nullopt;
std::optional<MaliGPU> mali_gpu_ = std::nullopt;
std::string driver_name_;
};

Expand Down
66 changes: 53 additions & 13 deletions impeller/renderer/backend/vulkan/driver_info_vk_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,60 @@ TEST_P(DriverInfoVKTest, CanDumpToLog) {
EXPECT_TRUE(log.str().find("Driver Information") != std::string::npos);
}

bool IsBadVersionTest(std::string_view driver_name, bool qc = true) {
auto const context =
MockVulkanContextBuilder()
.SetPhysicalPropertiesCallback(
[&driver_name, qc](VkPhysicalDevice device,
VkPhysicalDeviceProperties* prop) {
if (qc) {
prop->vendorID = 0x168C; // Qualcomm
} else {
prop->vendorID = 0x13B5; // ARM
}
driver_name.copy(prop->deviceName, driver_name.size());
prop->deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
})
.Build();
return context->GetDriverInfo()->IsKnownBadDriver();
}

TEST(DriverInfoVKTest, DriverParsingMali) {
EXPECT_EQ(GetMaliVersion("Mali-G51-MORE STUFF"), MaliGPU::kG51);
EXPECT_EQ(GetMaliVersion("Mali-G51"), MaliGPU::kG51);
EXPECT_EQ(GetMaliVersion("Mali-111111"), MaliGPU::kUnknown);
}

TEST(DriverInfoVKTest, DriverParsingArm) {
EXPECT_EQ(GetAdrenoVersion("Adreno (TM) 540"), AdrenoGPU::kAdreno540);
EXPECT_EQ(GetAdrenoVersion("Foo Bar"), AdrenoGPU::kUnknown);
}

TEST(DriverInfoVKTest, DisabledDevices) {
std::string name = "Adreno (TM) 630";
auto const context = MockVulkanContextBuilder()
.SetPhysicalPropertiesCallback(
[&name](VkPhysicalDevice device,
VkPhysicalDeviceProperties* prop) {
prop->vendorID = 0x168C; // Qualcomm
name.copy(prop->deviceName, name.size());
prop->deviceType =
VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
})
.Build();

EXPECT_TRUE(context->GetDriverInfo()->IsKnownBadDriver());
EXPECT_TRUE(IsBadVersionTest("Adreno (TM) 630"));
}

TEST(DriverInfoVKTest, EnabledDevicesMali) {
EXPECT_FALSE(IsBadVersionTest("Mali-G52", /*qc=*/false));
EXPECT_FALSE(IsBadVersionTest("Mali-G54-MORE STUFF", /*qc=*/false));
}

TEST(DriverInfoVKTest, EnabledDevicesAdreno) {
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 750"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 740"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 732"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 730"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 725"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 720"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 710"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 702"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 530"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 512"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 509"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 508"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 506"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 505"));
EXPECT_FALSE(IsBadVersionTest("Adreno (TM) 504"));
}

} // namespace impeller::testing

0 comments on commit e84e303

Please sign in to comment.