diff options
author | zmo@google.com <zmo@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-11 21:07:18 +0000 |
---|---|---|
committer | zmo@google.com <zmo@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-11 21:07:18 +0000 |
commit | 2efc3118e5132ed7d3497f98d82cfb693490d552 (patch) | |
tree | 4e173c50c899c858155cc783c766db4d43a29ddf /chrome | |
parent | a71a22ff3045cc1523321fd81b82c97e4e53e097 (diff) | |
download | chromium_src-2efc3118e5132ed7d3497f98d82cfb693490d552.zip chromium_src-2efc3118e5132ed7d3497f98d82cfb693490d552.tar.gz chromium_src-2efc3118e5132ed7d3497f98d82cfb693490d552.tar.bz2 |
Blacklist bad GPU drivers: currenly we disable all gpu related features if a (os, device, driver) configuration is on the blacklist.
BUG=58182
TEST=unittest
Review URL: http://codereview.chromium.org/5612002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@68948 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/browser_resources.grd | 1 | ||||
-rw-r--r-- | chrome/browser/gpu_blacklist.cc | 420 | ||||
-rw-r--r-- | chrome/browser/gpu_blacklist.h | 190 | ||||
-rw-r--r-- | chrome/browser/gpu_blacklist_unittest.cc | 142 | ||||
-rw-r--r-- | chrome/browser/gpu_process_host.cc | 40 | ||||
-rw-r--r-- | chrome/browser/gpu_process_host.h | 5 | ||||
-rw-r--r-- | chrome/browser/resources/gpu_blacklist.json | 16 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_common.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 2 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 3 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 1 | ||||
-rw-r--r-- | chrome/common/gpu_feature_flags.cc | 45 | ||||
-rw-r--r-- | chrome/common/gpu_feature_flags.h | 58 | ||||
-rw-r--r-- | chrome/common/gpu_feature_flags_unittest.cc | 51 | ||||
-rw-r--r-- | chrome/common/gpu_messages_internal.h | 5 | ||||
-rw-r--r-- | chrome/gpu/gpu_thread.cc | 12 | ||||
-rw-r--r-- | chrome/gpu/gpu_thread.h | 5 |
18 files changed, 999 insertions, 1 deletions
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index c085150c..6bbf3ab 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd @@ -43,6 +43,7 @@ without changes to the corresponding grd file. etaa --> <include name="IDR_INCOGNITO_TAB_HTML" file="resources\incognito_tab.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_KEYBOARD_MANIFEST" file="resources\keyboard\manifest.json" type="BINDATA" /> <include name="IDR_LOGIN_HTML" file="resources\login.html" flattenhtml="true" type="BINDATA" /> + <include name="IDR_GPU_BLACKLIST" file="resources\gpu_blacklist.json" type="BINDATA" /> <include name="IDR_NEW_INCOGNITO_TAB_THEME_CSS" file="resources\new_incognito_tab_theme.css" flattenhtml="true" type="BINDATA" /> <include name="IDR_NEW_NEW_TAB_HTML" file="resources\new_new_tab.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_NEW_TAB_THEME_CSS" file="resources\new_tab_theme.css" flattenhtml="true" type="BINDATA" /> diff --git a/chrome/browser/gpu_blacklist.cc b/chrome/browser/gpu_blacklist.cc new file mode 100644 index 0000000..a3d3eab --- /dev/null +++ b/chrome/browser/gpu_blacklist.cc @@ -0,0 +1,420 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/gpu_blacklist.h" + +#include "base/json/json_reader.h" +#include "base/logging.h" +#include "base/string_number_conversions.h" +#include "base/stringprintf.h" +#include "base/sys_info.h" +#include "base/values.h" +#include "base/version.h" +#include "chrome/common/gpu_info.h" + +GpuBlacklist::VersionInfo::VersionInfo(const std::string& version_op, + const std::string& version_string, + const std::string& version_string2) { + op_ = StringToOp(version_op); + if (op_ == kUnknown || op_ == kAny) + return; + version_.reset(Version::GetVersionFromString(version_string)); + if (version_.get() == NULL) { + op_ = kUnknown; + return; + } + if (op_ == kBetween) { + version2_.reset(Version::GetVersionFromString(version_string2)); + if (version2_.get() == NULL) + op_ = kUnknown; + } +} + +GpuBlacklist::VersionInfo::~VersionInfo() { +} + +bool GpuBlacklist::VersionInfo::Contains(const Version& version) const { + if (op_ == kUnknown) + return false; + if (op_ == kAny) + return true; + if (op_ == kEQ) { + // Handles cases where 10.6 is considered as containing 10.6.*. + const std::vector<uint16>& components_reference = version_->components(); + const std::vector<uint16>& components = version.components(); + for (size_t i = 0; i < components_reference.size(); ++i) { + if (i >= components.size() && components_reference[i] != 0) + return false; + if (components[i] != components_reference[i]) + return false; + } + return true; + } + int relation = version.CompareTo(*version_); + if (op_ == kEQ) + return (relation == 0); + else if (op_ == kLT) + return (relation < 0); + else if (op_ == kLE) + return (relation <= 0); + else if (op_ == kGT) + return (relation > 0); + else if (op_ == kGE) + return (relation >= 0); + // op_ == kBetween + if (relation < 0) + return false; + return version.CompareTo(*version2_) <= 0; +} + +bool GpuBlacklist::VersionInfo::IsValid() const { + return op_ != kUnknown; +} + +GpuBlacklist::VersionInfo::Op GpuBlacklist::VersionInfo::StringToOp( + const std::string& version_op) { + if (version_op == "=") + return kEQ; + else if (version_op == "<") + return kLT; + else if (version_op == "<=") + return kLE; + else if (version_op == ">") + return kGT; + else if (version_op == ">=") + return kGE; + else if (version_op == "any") + return kAny; + else if (version_op == "between") + return kBetween; + return kUnknown; +} + +GpuBlacklist::OsInfo::OsInfo(const std::string& os, + const std::string& version_op, + const std::string& version_string, + const std::string& version_string2) { + type_ = StringToOsType(os); + if (type_ != kOsUnknown) { + version_info_.reset( + new VersionInfo(version_op, version_string, version_string2)); + } +} + +bool GpuBlacklist::OsInfo::Contains(OsType type, + const Version& version) const { + if (!IsValid()) + return false; + if (type_ != type && type_ != kOsAny) + return false; + return version_info_->Contains(version); +} + +bool GpuBlacklist::OsInfo::IsValid() const { + return type_ != kOsUnknown && version_info_->IsValid(); +} + +GpuBlacklist::OsType GpuBlacklist::OsInfo::type() const { + return type_; +} + +GpuBlacklist::OsType GpuBlacklist::OsInfo::StringToOsType( + const std::string& os) { + if (os == "win") + return kOsWin; + else if (os == "macosx") + return kOsMacosx; + else if (os == "linux") + return kOsLinux; + else if (os == "any") + return kOsAny; + return kOsUnknown; +} + +GpuBlacklist::GpuBlacklistEntry* +GpuBlacklist::GpuBlacklistEntry::GetGpuBlacklistEntryFromValue( + DictionaryValue* value) { + if (value == NULL) + return NULL; + + GpuBlacklistEntry* entry = new GpuBlacklistEntry(); + + DictionaryValue* os_value = NULL; + if (value->GetDictionary("os", &os_value)) { + std::string os_type; + std::string os_version_op = "any"; + std::string os_version_string; + std::string os_version_string2; + os_value->GetString("type", &os_type); + DictionaryValue* os_version_value = NULL; + if (os_value->GetDictionary("version", &os_version_value)) { + os_version_value->GetString("op", &os_version_op); + os_version_value->GetString("number", &os_version_string); + os_version_value->GetString("number2", &os_version_string2); + } + if (!entry->SetOsInfo(os_type, os_version_op, os_version_string, + os_version_string2)) { + delete entry; + return NULL; + } + } + + std::string vendor_id; + if (value->GetString("vendor_id", &vendor_id)) { + if (!entry->SetVendorId(vendor_id)) { + delete entry; + return NULL; + } + } + + std::string device_id; + if (value->GetString("device_id", &device_id)) { + if (!entry->SetDeviceId(device_id)) { + delete entry; + return NULL; + } + } + + DictionaryValue* driver_version_value = NULL; + if (value->GetDictionary("driver_version", &driver_version_value)) { + std::string driver_version_op = "any"; + std::string driver_version_string; + std::string driver_version_string2; + driver_version_value->GetString("op", &driver_version_op); + driver_version_value->GetString("number", &driver_version_string); + driver_version_value->GetString("number2", &driver_version_string2); + if (!entry->SetDriverVersionInfo(driver_version_op, driver_version_string, + driver_version_string2)) { + delete entry; + return NULL; + } + } + + ListValue* blacklist_value = NULL; + if (!value->GetList("blacklist", &blacklist_value)) { + delete entry; + return NULL; + } + std::vector<std::string> blacklist; + for (size_t i = 0; i < blacklist_value->GetSize(); ++i) { + std::string feature; + if (blacklist_value->GetString(i, &feature)) { + blacklist.push_back(feature); + } else { + delete entry; + return NULL; + } + } + if (!entry->SetBlacklistedFeatures(blacklist)) { + delete entry; + return NULL; + } + + return entry; +} + +GpuBlacklist::GpuBlacklistEntry::GpuBlacklistEntry() + : vendor_id_(0), + device_id_(0) { +} + +bool GpuBlacklist::GpuBlacklistEntry::SetOsInfo( + const std::string& os, + const std::string& version_op, + const std::string& version_string, + const std::string& version_string2) { + os_info_.reset(new OsInfo(os, version_op, version_string, version_string2)); + return os_info_->IsValid(); +} + +bool GpuBlacklist::GpuBlacklistEntry::SetVendorId( + const std::string& vendor_id_string) { + vendor_id_ = 0; + return base::HexStringToInt(vendor_id_string, + reinterpret_cast<int*>(&vendor_id_)); +} + +bool GpuBlacklist::GpuBlacklistEntry::SetDeviceId( + const std::string& device_id_string) { + device_id_ = 0; + return base::HexStringToInt(device_id_string, + reinterpret_cast<int*>(&device_id_)); +} + +bool GpuBlacklist::GpuBlacklistEntry::SetDriverVersionInfo( + const std::string& version_op, + const std::string& version_string, + const std::string& version_string2) { + driver_version_info_.reset( + new VersionInfo(version_op, version_string, version_string2)); + return driver_version_info_->IsValid(); +} + +bool GpuBlacklist::GpuBlacklistEntry::SetBlacklistedFeatures( + const std::vector<std::string>& blacklisted_features) { + size_t size = blacklisted_features.size(); + if (size == 0) + return false; + uint32 flags = 0; + for (size_t i = 0; i < size; ++i) { + GpuFeatureFlags::GpuFeatureType type = + GpuFeatureFlags::StringToGpuFeatureType(blacklisted_features[i]); + switch (type) { + case GpuFeatureFlags::kGpuFeatureAccelerated2dCanvas: + case GpuFeatureFlags::kGpuFeatureAcceleratedCompositing: + case GpuFeatureFlags::kGpuFeatureWebgl: + case GpuFeatureFlags::kGpuFeatureAll: + flags |= type; + break; + case GpuFeatureFlags::kGpuFeatureUnknown: + return false; + } + } + feature_flags_.reset(new GpuFeatureFlags()); + feature_flags_->set_flags(flags); + return true; +} + +bool GpuBlacklist::GpuBlacklistEntry::Contains( + OsType os_type, const Version& os_version, + uint32 vendor_id, uint32 device_id, + const Version& driver_version) const { + DCHECK(os_type != kOsAny); + if (os_info_.get() != NULL && !os_info_->Contains(os_type, os_version)) + return false; + if (vendor_id_ != 0 && vendor_id_ != vendor_id) + return false; + if (device_id_ != 0 && device_id_ != device_id) + return false; + if (driver_version_info_.get() == NULL) + return true; + return driver_version_info_->Contains(driver_version); +} + +GpuBlacklist::OsType GpuBlacklist::GpuBlacklistEntry::GetOsType() const { + if (os_info_.get() == NULL) + return kOsUnknown; + return os_info_->type(); +} + +GpuFeatureFlags GpuBlacklist::GpuBlacklistEntry::GetGpuFeatureFlags() const { + return *feature_flags_; +} + +GpuBlacklist::GpuBlacklist() { +} + +GpuBlacklist::~GpuBlacklist() { + Clear(); +} + +bool GpuBlacklist::LoadGpuBlacklist(const std::string& json_context, + bool current_os_only) { + std::vector<GpuBlacklistEntry*> entries; + scoped_ptr<Value> root; + root.reset(base::JSONReader::Read(json_context, false)); + if (root.get() == NULL || !root->IsType(Value::TYPE_DICTIONARY)) + return false; + + ListValue* list = NULL; + static_cast<DictionaryValue*>(root.get())->GetList("entries", &list); + if (list == NULL) + return false; + + for (size_t i = 0; i < list->GetSize(); ++i) { + DictionaryValue* list_item = NULL; + bool valid = list->GetDictionary(i, &list_item); + if (!valid) + break; + GpuBlacklistEntry* entry = + GpuBlacklistEntry::GetGpuBlacklistEntryFromValue(list_item); + if (entry == NULL) + break; + entries.push_back(entry); + } + + if (entries.size() < list->GetSize()) { + for (size_t i = 0; i < entries.size(); ++i) + delete entries[i]; + return false; + } + + Clear(); + // Don't apply GPU blacklist for a non-registered OS. + OsType os_filter = GetOsType(); + if (os_filter != kOsUnknown) { + for (size_t i = 0; i < entries.size(); ++i) { + OsType entry_os = entries[i]->GetOsType(); + if (!current_os_only || + entry_os == kOsAny || entry_os == os_filter) + blacklist_.push_back(entries[i]); + } + } + return true; +} + +GpuFeatureFlags GpuBlacklist::DetermineGpuFeatureFlags( + GpuBlacklist::OsType os, + Version* os_version, + const GPUInfo& gpu_info) const { + GpuFeatureFlags flags; + // No need to go through blacklist entries if GPUInfo isn't available. + if (gpu_info.progress() == GPUInfo::kUninitialized) + return flags; + scoped_ptr<Version> driver_version( + Version::GetVersionFromString(gpu_info.driver_version())); + if (driver_version.get() == NULL) + return flags; + + if (os == kOsAny) + os = GetOsType(); + scoped_ptr<Version> my_os_version; + if (os_version == NULL) { + std::string version_string; +#if defined(OS_MACOSX) + // Seems like base::SysInfo::OperatingSystemVersion() returns the wrong + // version in MacOsx. + int32 version_major, version_minor, version_bugfix; + base::SysInfo::OperatingSystemVersionNumbers( + &version_major, &version_minor, &version_bugfix); + version_string = base::StringPrintf("%d.%d.%d", + version_major, + version_minor, + version_bugfix); +#else + version_string = base::SysInfo::OperatingSystemVersion(); +#endif + my_os_version.reset(Version::GetVersionFromString(version_string)); + os_version = my_os_version.get(); + } + DCHECK(os_version != NULL); + + for (size_t i = 0; i < blacklist_.size(); ++i) { + if (blacklist_[i]->Contains(os, *os_version, + gpu_info.vendor_id(), gpu_info.device_id(), + *driver_version)) { + flags.Combine(blacklist_[i]->GetGpuFeatureFlags()); + } + } + return flags; +} + +GpuBlacklist::OsType GpuBlacklist::GetOsType() { +#if defined(OS_WIN) + return kOsWin; +#elif defined(OS_LINUX) + return kOsLinux; +#elif defined(OS_MACOSX) + return kOsMacosx; +#else + return kOsUnknown; +#endif +} + +void GpuBlacklist::Clear() { + for (size_t i = 0; i < blacklist_.size(); ++i) + delete blacklist_[i]; + blacklist_.clear(); +} + diff --git a/chrome/browser/gpu_blacklist.h b/chrome/browser/gpu_blacklist.h new file mode 100644 index 0000000..ee556b3 --- /dev/null +++ b/chrome/browser/gpu_blacklist.h @@ -0,0 +1,190 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_GPU_BLACKLIST_H_ +#define CHROME_BROWSER_GPU_BLACKLIST_H_ +#pragma once + +// Determines whether certain gpu-related features are blacklisted or not. +// A valid gpu_blacklist.json file are in the format of +// { +// "entries": [ +// { // entry 1 +// }, +// ... +// { // entry n +// } +// ] +// } +// Each entry contains the following fields: +// "os", "vendor_id", "device_id", "driver_version", and "blacklist". +// Only "blacklist" is mandatory. +// 1. "os" contains "type" and an optional "version". "type" could be "macosx", +// "linux", "win", or "any". "any" is the same as not specifying "os". +// "version" is a VERSION structure (defined later). +// 2. "vendor_id" has the value of a string. +// 3. "device_id" has the value of a string. +// 4. "driver_version" is a VERSION structure (defined later). +// 5. "blacklist" is a list of gpu feature strings, valid values include +// "accelerated_2d_canvas", "accelerated_compositing", "webgl", and "all". +// Currently whatever feature is selected, the effect is the same as "all", +// i.e., it's not supported to turn off one GPU feature and not the others. +// VERSION includes "op" "number", and "number2". "op" can be any of the +// following value: "=", "<", "<=", ">", ">=", "any", "between". "number2" is +// only used if "op" is "between". "number" is used for all "op" values except +// "any". "number" and "number2" are in the format of x, x.x, x.x.x, ect. +// Check out "gpu_blacklist_unittest.cc" for examples. + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "chrome/common/gpu_feature_flags.h" + +class DictionaryValue; +class GPUInfo; +class Version; + +class GpuBlacklist { + public: + enum OsType { + kOsLinux, + kOsMacosx, + kOsWin, + kOsAny, + kOsUnknown + }; + + GpuBlacklist(); + ~GpuBlacklist(); + + // Loads blacklist information from a json file. + // current_os_only==true indicates all blacklist entries that don't belong to + // the current OS are discarded; current_os_only==false should only be used + // for testing purpose. + // If failed, the current GpuBlacklist is un-touched. + bool LoadGpuBlacklist(const std::string& json_context, + bool current_os_only); + + // Collects system information and combines them with gpu_info and blacklist + // information to determine gpu feature flags. + // If os is kOsAny, use the current OS; if os_version is null, use the + // current OS version. + GpuFeatureFlags DetermineGpuFeatureFlags(OsType os, + Version* os_version, + const GPUInfo& gpu_info) const; + + private: + class VersionInfo { + public: + VersionInfo(const std::string& version_op, + const std::string& version_string, + const std::string& version_string2); + ~VersionInfo(); + + // Determines if a given version is included in the VersionInfo range. + bool Contains(const Version& version) const; + + // Determines if the VersionInfo contains valid information. + bool IsValid() const; + + private: + enum Op { + kBetween, // <= * <= + kEQ, // = + kLT, // < + kLE, // <= + kGT, // > + kGE, // >= + kAny, + kUnknown // Indicates VersionInfo data is invalid. + }; + + // Maps string to Op; returns kUnknown if it's not a valid Op. + static Op StringToOp(const std::string& version_op); + + Op op_; + scoped_ptr<Version> version_; + scoped_ptr<Version> version2_; + }; + + class OsInfo { + public: + OsInfo(const std::string& os, + const std::string& version_op, + const std::string& version_string, + const std::string& version_string2); + + // Determines if a given os/version is included in the OsInfo set. + bool Contains(OsType type, const Version& version) const; + + // Determines if the VersionInfo contains valid information. + bool IsValid() const; + + OsType type() const; + + // Maps string to OsType; returns kOsUnknown if it's not a valid os. + static OsType StringToOsType(const std::string& os); + + private: + OsType type_; + scoped_ptr<VersionInfo> version_info_; + }; + + class GpuBlacklistEntry { + public: + // Constructs GpuBlacklistEntry from DictionaryValue loaded from json. + static GpuBlacklistEntry* GetGpuBlacklistEntryFromValue( + DictionaryValue* value); + + // Determines if a given os/gc/driver is included in the Entry set. + bool Contains(OsType os_type, const Version& os_version, + uint32 vendor_id, uint32 device_id, + const Version& driver_version) const; + + // Returns the OsType. + OsType GetOsType() const; + + // Returns the GpuFeatureFlags. + GpuFeatureFlags GetGpuFeatureFlags() const; + + private: + GpuBlacklistEntry(); + + bool SetOsInfo(const std::string& os, + const std::string& version_op, + const std::string& version_string, + const std::string& version_string2); + + bool SetVendorId(const std::string& vendor_id_string); + + bool SetDeviceId(const std::string& device_id_string); + + bool SetDriverVersionInfo(const std::string& version_op, + const std::string& version_string, + const std::string& version_string2); + + bool SetBlacklistedFeatures( + const std::vector<std::string>& blacklisted_features); + + scoped_ptr<OsInfo> os_info_; + uint32 vendor_id_; + uint32 device_id_; + scoped_ptr<VersionInfo> driver_version_info_; + scoped_ptr<GpuFeatureFlags> feature_flags_; + }; + + // Gets the current OS type. + static OsType GetOsType(); + + void Clear(); + + std::vector<GpuBlacklistEntry*> blacklist_; + + DISALLOW_COPY_AND_ASSIGN(GpuBlacklist); +}; + +#endif // CHROME_BROWSER_GPU_BLACKLIST_H_ + diff --git a/chrome/browser/gpu_blacklist_unittest.cc b/chrome/browser/gpu_blacklist_unittest.cc new file mode 100644 index 0000000..f30d2ab --- /dev/null +++ b/chrome/browser/gpu_blacklist_unittest.cc @@ -0,0 +1,142 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/version.h" +#include "chrome/browser/gpu_blacklist.h" +#include "chrome/common/gpu_info.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(GpuBlacklistTest, BlacklistLogic) { + GPUInfo gpu_info; + gpu_info.SetGraphicsInfo(0x10de, // Vendor ID + 0x0640, // Device ID + L"1.6.18", // Driver Version + 0x0114, // Pixel Shader Version + 0x0114, // Vertex Shader Version + 0x0201, // GL version, + true); // can_lose_context + gpu_info.SetProgress(GPUInfo::kComplete); + scoped_ptr<Version> os_version(Version::GetVersionFromString("10.6.4")); + + GpuBlacklist blacklist; + + // Default blacklist settings: all feature are allowed. + GpuFeatureFlags flags = blacklist.DetermineGpuFeatureFlags( + GpuBlacklist::kOsMacosx, os_version.get(), gpu_info); + EXPECT_EQ(flags.flags(), 0u); + + // Empty list: all features are allowed. + const std::string empty_list_json = + "{\n" + " \"name\": \"gpu blacklist\",\n" + " \"version\": \"0.0\",\n" + " \"entries\": [\n" + " ]\n" + "}"; + EXPECT_TRUE(blacklist.LoadGpuBlacklist(empty_list_json, false)); + flags = blacklist.DetermineGpuFeatureFlags( + GpuBlacklist::kOsMacosx, os_version.get(), gpu_info); + EXPECT_EQ(flags.flags(), 0u); + + // Blacklist accelerated_compositing with exact setting. + const std::string exact_list_json = + "{\n" + " \"name\": \"gpu blacklist\",\n" + " \"version\": \"0.1\",\n" + " \"entries\": [\n" + " {\n" + " \"os\": {\n" + " \"type\": \"macosx\",\n" + " \"version\": {\n" + " \"op\": \"=\",\n" + " \"number\": \"10.6.4\"\n" + " }\n" + " },\n" + " \"vendor_id\": \"0x10de\",\n" + " \"device_id\": \"0x0640\",\n" + " \"driver_version\": {\n" + " \"op\": \"=\",\n" + " \"number\": \"1.6.18\"\n" + " },\n" + " \"blacklist\": [\n" + " \"accelerated_compositing\"\n" + " ]\n" + " }\n" + " ]\n" + "}"; + EXPECT_TRUE(blacklist.LoadGpuBlacklist(exact_list_json, false)); + flags = blacklist.DetermineGpuFeatureFlags( + GpuBlacklist::kOsMacosx, os_version.get(), gpu_info); + EXPECT_EQ( + flags.flags(), + static_cast<uint32>(GpuFeatureFlags::kGpuFeatureAcceleratedCompositing)); + + // Invalid json input should not change the current blacklist settings. + const std::string invalid_json = "invalid"; + EXPECT_FALSE(blacklist.LoadGpuBlacklist(invalid_json, false)); + flags = blacklist.DetermineGpuFeatureFlags( + GpuBlacklist::kOsMacosx, os_version.get(), gpu_info); + EXPECT_EQ( + flags.flags(), + static_cast<uint32>(GpuFeatureFlags::kGpuFeatureAcceleratedCompositing)); + + // Blacklist a vendor on all OS. + const std::string vendor_json = + "{\n" + " \"name\": \"gpu blacklist\",\n" + " \"version\": \"0.1\",\n" + " \"entries\": [\n" + " {\n" + " \"vendor_id\": \"0x10de\",\n" + " \"blacklist\": [\n" + " \"webgl\"\n" + " ]\n" + " }\n" + " ]\n" + "}"; + EXPECT_TRUE(blacklist.LoadGpuBlacklist(vendor_json, false)); + flags = blacklist.DetermineGpuFeatureFlags( + GpuBlacklist::kOsMacosx, os_version.get(), gpu_info); + EXPECT_EQ(flags.flags(), + static_cast<uint32>(GpuFeatureFlags::kGpuFeatureWebgl)); + flags = blacklist.DetermineGpuFeatureFlags( + GpuBlacklist::kOsWin, os_version.get(), gpu_info); + EXPECT_EQ(flags.flags(), + static_cast<uint32>(GpuFeatureFlags::kGpuFeatureWebgl)); + flags = blacklist.DetermineGpuFeatureFlags( + GpuBlacklist::kOsLinux, os_version.get(), gpu_info); + EXPECT_EQ(flags.flags(), + static_cast<uint32>(GpuFeatureFlags::kGpuFeatureWebgl)); + + // Blacklist a vendor on Linux only. + const std::string vendor_linux_json = + "{\n" + " \"name\": \"gpu blacklist\",\n" + " \"version\": \"0.1\",\n" + " \"entries\": [\n" + " {\n" + " \"os\": {\n" + " \"type\": \"linux\"\n" + " },\n" + " \"vendor_id\": \"0x10de\",\n" + " \"blacklist\": [\n" + " \"accelerated_2d_canvas\"\n" + " ]\n" + " }\n" + " ]\n" + "}"; + EXPECT_TRUE(blacklist.LoadGpuBlacklist(vendor_linux_json, false)); + flags = blacklist.DetermineGpuFeatureFlags( + GpuBlacklist::kOsMacosx, os_version.get(), gpu_info); + EXPECT_EQ(flags.flags(), 0u); + flags = blacklist.DetermineGpuFeatureFlags( + GpuBlacklist::kOsWin, os_version.get(), gpu_info); + EXPECT_EQ(flags.flags(), 0u); + flags = blacklist.DetermineGpuFeatureFlags( + GpuBlacklist::kOsLinux, os_version.get(), gpu_info); + EXPECT_EQ( + flags.flags(), + static_cast<uint32>(GpuFeatureFlags::kGpuFeatureAccelerated2dCanvas)); +} + diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc index 4f3958b..b9d1103 100644 --- a/chrome/browser/gpu_process_host.cc +++ b/chrome/browser/gpu_process_host.cc @@ -5,19 +5,24 @@ #include "chrome/browser/gpu_process_host.h" #include "app/app_switches.h" +#include "app/resource_bundle.h" #include "base/command_line.h" #include "base/metrics/histogram.h" +#include "base/string_piece.h" #include "base/thread.h" #include "chrome/browser/browser_thread.h" +#include "chrome/browser/gpu_blacklist.h" #include "chrome/browser/gpu_process_host_ui_shim.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/render_widget_host_view.h" #include "chrome/browser/renderer_host/resource_message_filter.h" #include "chrome/browser/tab_contents/render_view_host_delegate_helper.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/gpu_feature_flags.h" #include "chrome/common/gpu_info.h" #include "chrome/common/gpu_messages.h" #include "chrome/common/render_messages.h" +#include "grit/browser_resources.h" #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_switches.h" #include "media/base/media_switches.h" @@ -97,6 +102,9 @@ bool GpuProcessHost::EnsureInitialized() { } bool GpuProcessHost::Init() { + if (!LoadGpuBlacklist()) + return false; + if (!CreateChannel()) return false; @@ -199,8 +207,20 @@ void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) { void GpuProcessHost::OnChannelEstablished( const IPC::ChannelHandle& channel_handle, const GPUInfo& gpu_info) { + GpuFeatureFlags gpu_feature_flags; + if (channel_handle.name.size() != 0) { + gpu_feature_flags = gpu_blacklist_->DetermineGpuFeatureFlags( + GpuBlacklist::kOsAny, NULL, gpu_info); + } const ChannelRequest& request = sent_requests_.front(); - SendEstablishChannelReply(channel_handle, gpu_info, request.filter); + // Currently if any of the GPU features are blacklised, we don't establish a + // GPU channel. + if (gpu_feature_flags.flags() != 0) { + Send(new GpuMsg_CloseChannel(channel_handle)); + SendEstablishChannelReply(IPC::ChannelHandle(), gpu_info, request.filter); + } else { + SendEstablishChannelReply(channel_handle, gpu_info, request.filter); + } sent_requests_.pop(); } @@ -536,3 +556,21 @@ bool GpuProcessHost::LaunchGpuProcess() { kLaunched, kGPUProcessLifetimeEvent_Max); return true; } + +bool GpuProcessHost::LoadGpuBlacklist() { + if (gpu_blacklist_.get() != NULL) + return true; + static const base::StringPiece gpu_blacklist_json( + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_GPU_BLACKLIST)); + GpuBlacklist* blacklist = new GpuBlacklist(); + const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); + if (browser_command_line.HasSwitch(switches::kIgnoreGpuBlacklist) || + blacklist->LoadGpuBlacklist(gpu_blacklist_json.as_string(), true)) { + gpu_blacklist_.reset(blacklist); + return true; + } + delete blacklist; + return false; +} + diff --git a/chrome/browser/gpu_process_host.h b/chrome/browser/gpu_process_host.h index 6d8fc9d..a3c2dfc 100644 --- a/chrome/browser/gpu_process_host.h +++ b/chrome/browser/gpu_process_host.h @@ -16,6 +16,7 @@ struct GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params; struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params; +class GpuBlacklist; class GPUInfo; class ResourceMessageFilter; @@ -120,9 +121,13 @@ class GpuProcessHost : public BrowserChildProcessHost, public NonThreadSafe { bool CanLaunchGpuProcess() const; bool LaunchGpuProcess(); + bool LoadGpuBlacklist(); + bool initialized_; bool initialized_successfully_; + scoped_ptr<GpuBlacklist> gpu_blacklist_; + // These are the channel requests that we have already sent to // the GPU process, but haven't heard back about yet. std::queue<ChannelRequest> sent_requests_; diff --git a/chrome/browser/resources/gpu_blacklist.json b/chrome/browser/resources/gpu_blacklist.json new file mode 100644 index 0000000..188fead --- /dev/null +++ b/chrome/browser/resources/gpu_blacklist.json @@ -0,0 +1,16 @@ +{ + "name": "gpu blacklist", + "version": "0.1", + "entries": [ + { // ATI Radeon X1900 on Mac + "os": { + "type": "macosx" + }, + "vendor_id": "0x1002", + "device_id": "0x7249", + "blacklist": [ + "webgl" + ] + } + ] +} diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index da4858b..ad667e8 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1304,6 +1304,8 @@ 'browser/google/google_url_tracker.h', 'browser/google/google_util.cc', 'browser/google/google_util.h', + 'browser/gpu_blacklist.cc', + 'browser/gpu_blacklist.h', 'browser/gpu_process_host.cc', 'browser/gpu_process_host.h', 'browser/gpu_process_host_ui_shim.cc', diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index 88e4ebc..9a59de9 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -67,6 +67,8 @@ 'common/geoposition.h', 'common/gpu_create_command_buffer_config.cc', 'common/gpu_create_command_buffer_config.h', + 'common/gpu_feature_flags.cc', + 'common/gpu_feature_flags.h', 'common/gpu_info.h', 'common/gpu_info.cc', 'common/gpu_messages.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 0257151..6abcfd7 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1169,6 +1169,7 @@ 'browser/global_keyboard_shortcuts_mac_unittest.mm', 'browser/google/google_update_settings_unittest.cc', 'browser/google/google_url_tracker_unittest.cc', + 'browser/gpu_blacklist_unittest.cc', 'browser/gtk/accessibility_event_router_gtk_unittest.cc', 'browser/gtk/bookmark_bar_gtk_unittest.cc', 'browser/gtk/bookmark_editor_gtk_unittest.cc', @@ -1598,6 +1599,7 @@ 'common/extensions/url_pattern_unittest.cc', 'common/extensions/user_script_unittest.cc', 'common/font_descriptor_mac_unittest.mm', + 'common/gpu_feature_flags_unittest.cc', 'common/gpu_info_unittest.cc', 'common/gpu_messages_unittest.cc', 'common/important_file_writer_unittest.cc', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index bddc032..745ce0c 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -725,6 +725,9 @@ const char kHostResolverParallelism[] = "host-resolver-parallelism"; // These mappings only apply to the host resolver. const char kHostResolverRules[] = "host-resolver-rules"; +// Ignores GPU blacklist. +const char kIgnoreGpuBlacklist[] = "ignore-gpu-blacklist"; + // Perform importing from another browser. The value associated with this // setting encodes the target browser and what items to import. const char kImport[] = "import"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 8c3ecaf..139c084 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -207,6 +207,7 @@ extern const char kHomePage[]; extern const char kHostRules[]; extern const char kHostResolverParallelism[]; extern const char kHostResolverRules[]; +extern const char kIgnoreGpuBlacklist[]; extern const char kImport[]; extern const char kImportFromFile[]; extern const char kInProcessPlugins[]; diff --git a/chrome/common/gpu_feature_flags.cc b/chrome/common/gpu_feature_flags.cc new file mode 100644 index 0000000..12b857b --- /dev/null +++ b/chrome/common/gpu_feature_flags.cc @@ -0,0 +1,45 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/gpu_feature_flags.h" + +#include "base/logging.h" + +const char GpuFeatureFlags::kGpuFeatureNameAccelerated2dCanvas[] = + "accelerated_2d_canvas"; +const char GpuFeatureFlags::kGpuFeatureNameAcceleratedCompositing[] = + "accelerated_compositing"; +const char GpuFeatureFlags::kGpuFeatureNameWebgl[] = "webgl"; +const char GpuFeatureFlags::kGpuFeatureNameAll[] = "all"; + +GpuFeatureFlags::GpuFeatureFlags() + : flags_(0) { +} + +void GpuFeatureFlags::set_flags(uint32 flags) { + DCHECK_EQ(flags & (~kGpuFeatureAll), 0u); + flags_ = flags; +} + +uint32 GpuFeatureFlags::flags() const { + return flags_; +} + +void GpuFeatureFlags::Combine(const GpuFeatureFlags& other) { + flags_ |= other.flags_; +} + +GpuFeatureFlags::GpuFeatureType GpuFeatureFlags::StringToGpuFeatureType( + const std::string& feature_string) { + if (feature_string == kGpuFeatureNameAccelerated2dCanvas) + return kGpuFeatureAccelerated2dCanvas; + else if (feature_string == kGpuFeatureNameAcceleratedCompositing) + return kGpuFeatureAcceleratedCompositing; + else if (feature_string == kGpuFeatureNameWebgl) + return kGpuFeatureWebgl; + else if (feature_string == kGpuFeatureNameAll) + return kGpuFeatureAll; + return kGpuFeatureUnknown; +} + diff --git a/chrome/common/gpu_feature_flags.h b/chrome/common/gpu_feature_flags.h new file mode 100644 index 0000000..5b9d3ed --- /dev/null +++ b/chrome/common/gpu_feature_flags.h @@ -0,0 +1,58 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_COMMON_GPU_FEATURE_FLAGS_H__ +#define CHROME_COMMON_GPU_FEATURE_FLAGS_H__ +#pragma once + +// Provides flags indicating which gpu features are blacklisted for the system +// on which chrome is currently running. + +#include <string> + +#include "base/basictypes.h" + +class GpuFeatureFlags { + public: + enum GpuFeatureType { + kGpuFeatureAccelerated2dCanvas = 1 << 0, + kGpuFeatureAcceleratedCompositing = 1 << 1, + kGpuFeatureWebgl = 1 << 2, + kGpuFeatureAll = kGpuFeatureAccelerated2dCanvas | + kGpuFeatureAcceleratedCompositing | + kGpuFeatureWebgl, + kGpuFeatureUnknown = 0 + }; + + // All flags initialized to false, i.e., no feature is blacklisted. + GpuFeatureFlags(); + + // flags are OR combination of GpuFeatureType. + void set_flags(uint32 flags); + + uint32 flags() const; + + // Resets each flag by OR with the corresponding flag in "other". + void Combine(const GpuFeatureFlags& other); + + // Maps string to GpuFeatureType; returns kGpuFeatureUnknown if none of the + // following is input (case-sensitive): + // "accelerated_2d_canvas" + // "accelerated_compositing" + // "webgl" + static GpuFeatureType StringToGpuFeatureType( + const std::string& feature_string); + + private: + static const char kGpuFeatureNameAccelerated2dCanvas[]; + static const char kGpuFeatureNameAcceleratedCompositing[]; + static const char kGpuFeatureNameWebgl[]; + static const char kGpuFeatureNameAll[]; + + // If a bit is set to 1, corresponding feature is blacklisted. + uint32 flags_; +}; + +#endif // CHROME_COMMON_GPU_FEATURE_FLAGS_H__ + diff --git a/chrome/common/gpu_feature_flags_unittest.cc b/chrome/common/gpu_feature_flags_unittest.cc new file mode 100644 index 0000000..1bd8f40 --- /dev/null +++ b/chrome/common/gpu_feature_flags_unittest.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/gpu_feature_flags.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(GpuFeatureFlagsTest, GpuFeatureFlagsBasic) { + // Test that by default all flags are set to false. + GpuFeatureFlags flags; + EXPECT_EQ(flags.flags(), 0u); + + // Test SetFlags(). + GpuFeatureFlags flags2; + flags2.set_flags(GpuFeatureFlags::kGpuFeatureAcceleratedCompositing | + GpuFeatureFlags::kGpuFeatureWebgl); + EXPECT_EQ(flags2.flags(), + static_cast<uint32>( + GpuFeatureFlags::kGpuFeatureAcceleratedCompositing | + GpuFeatureFlags::kGpuFeatureWebgl)); + + // Test Combine() is basically OR operation per flag. + flags.set_flags(GpuFeatureFlags::kGpuFeatureAccelerated2dCanvas); + flags.Combine(flags2); + EXPECT_EQ(flags.flags(), + static_cast<uint32>( + GpuFeatureFlags::kGpuFeatureAccelerated2dCanvas | + GpuFeatureFlags::kGpuFeatureAcceleratedCompositing | + GpuFeatureFlags::kGpuFeatureWebgl)); + + // Test the currently supported feature set. + flags.set_flags(GpuFeatureFlags::kGpuFeatureAll); + EXPECT_EQ(flags.flags(), + static_cast<uint32>( + GpuFeatureFlags::kGpuFeatureAccelerated2dCanvas | + GpuFeatureFlags::kGpuFeatureAcceleratedCompositing | + GpuFeatureFlags::kGpuFeatureWebgl)); + + // Test StringToGpuFeatureType. + EXPECT_EQ(GpuFeatureFlags::StringToGpuFeatureType("accelerated_2d_canvas"), + GpuFeatureFlags::kGpuFeatureAccelerated2dCanvas); + EXPECT_EQ(GpuFeatureFlags::StringToGpuFeatureType("accelerated_compositing"), + GpuFeatureFlags::kGpuFeatureAcceleratedCompositing); + EXPECT_EQ(GpuFeatureFlags::StringToGpuFeatureType("webgl"), + GpuFeatureFlags::kGpuFeatureWebgl); + EXPECT_EQ(GpuFeatureFlags::StringToGpuFeatureType("all"), + GpuFeatureFlags::kGpuFeatureAll); + EXPECT_EQ(GpuFeatureFlags::StringToGpuFeatureType("xxx"), + GpuFeatureFlags::kGpuFeatureUnknown); +} + diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h index 57a8917..3814702 100644 --- a/chrome/common/gpu_messages_internal.h +++ b/chrome/common/gpu_messages_internal.h @@ -33,6 +33,11 @@ class GPUInfo; IPC_MESSAGE_CONTROL1(GpuMsg_EstablishChannel, int /* renderer_id */) +// Tells the GPU process to close the channel identified by IPC channel +// handle. If no channel can be identified, do nothing. +IPC_MESSAGE_CONTROL1(GpuMsg_CloseChannel, + IPC::ChannelHandle /* channel_handle */) + // Provides a synchronization point to guarantee that the processing of // previous asynchronous messages (i.e., GpuMsg_EstablishChannel) has // completed. (This message can't be synchronous because the diff --git a/chrome/gpu/gpu_thread.cc b/chrome/gpu/gpu_thread.cc index 411fbbb..d506dda 100644 --- a/chrome/gpu/gpu_thread.cc +++ b/chrome/gpu/gpu_thread.cc @@ -57,6 +57,8 @@ void GpuThread::OnControlMessageReceived(const IPC::Message& msg) { IPC_BEGIN_MESSAGE_MAP_EX(GpuThread, msg, msg_is_ok) IPC_MESSAGE_HANDLER(GpuMsg_EstablishChannel, OnEstablishChannel) + IPC_MESSAGE_HANDLER(GpuMsg_CloseChannel, + OnCloseChannel) IPC_MESSAGE_HANDLER(GpuMsg_Synchronize, OnSynchronize) IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo, @@ -103,6 +105,16 @@ void GpuThread::OnEstablishChannel(int renderer_id) { Send(new GpuHostMsg_ChannelEstablished(channel_handle, gpu_info_)); } +void GpuThread::OnCloseChannel(const IPC::ChannelHandle& channel_handle) { + for (GpuChannelMap::iterator iter = gpu_channels_.begin(); + iter != gpu_channels_.end(); ++iter) { + if (iter->second->GetChannelName() == channel_handle.name) { + gpu_channels_.erase(iter); + return; + } + } +} + void GpuThread::OnSynchronize() { Send(new GpuHostMsg_SynchronizeReply()); } diff --git a/chrome/gpu/gpu_thread.h b/chrome/gpu/gpu_thread.h index 26b7966..9aba2fd 100644 --- a/chrome/gpu/gpu_thread.h +++ b/chrome/gpu/gpu_thread.h @@ -17,6 +17,10 @@ #include "chrome/gpu/x_util.h" #include "gfx/native_widget_types.h" +namespace IPC { +struct ChannelHandle; +} + class GpuThread : public ChildThread { public: GpuThread(); @@ -33,6 +37,7 @@ class GpuThread : public ChildThread { // Message handlers. void OnEstablishChannel(int renderer_id); + void OnCloseChannel(const IPC::ChannelHandle& channel_handle); void OnSynchronize(); void OnCollectGraphicsInfo(); #if defined(OS_MACOSX) |