Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Impeller] add parsing of known GPU models #55196

Merged
merged 8 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 .
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This version of the PR doesn't actually affect that issue, right?

That is, this adds parsing but it doesn't yet change what set of GPUs get treated as known-bad.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're still going to try to aquire a device with a similar GPU and see what isn't working first.

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