From 04a088f94925efe1a43d7a4e58b5c6270d5a58d7 Mon Sep 17 00:00:00 2001 From: "zmo@chromium.org" Date: Mon, 10 Sep 2012 20:55:42 +0000 Subject: [PATCH] Move gpu blacklist to content side (second try) When it's on the content side, it can be part of the GpuDataManager, so we don't need to make it a Singleton. Also, this CL did some cleanup related to this moving. The main reason for this refactoring is because blacklist is tightly coupled with GpuDataManager. Putting them on the this side makes it much easier to test the code, and the design is much better. BUG= TEST=bots Review URL: https://chromiumcodereview.appspot.com/10907106 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@155823 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/chrome_browser_field_trials.cc | 2 +- chrome/browser/chrome_browser_main.cc | 25 +- chrome/browser/chrome_gpu_util.cc | 123 ++++ chrome/browser/chrome_gpu_util.h | 22 + .../webstore_private_apitest.cc | 7 +- chrome/browser/gpu_util.cc | 631 ------------------ chrome/browser/gpu_util.h | 78 --- chrome/browser/ui/webui/gpu_internals_ui.cc | 331 ++++++++- chrome/browser/ui/webui/tracing_ui.cc | 49 +- chrome/chrome_browser.gypi | 6 +- chrome/chrome_tests.gypi | 2 - chrome/test/gpu/gpu_feature_browsertest.cc | 9 +- .../browser/gpu}/gpu_blacklist.cc | 32 +- .../browser/gpu}/gpu_blacklist.h | 37 +- .../browser/gpu}/gpu_blacklist_unittest.cc | 3 +- content/browser/gpu/gpu_data_manager_impl.cc | 62 +- content/browser/gpu/gpu_data_manager_impl.h | 27 +- .../gpu/gpu_data_manager_impl_unittest.cc | 3 +- content/browser/gpu/gpu_util.cc | 223 +++++++ content/browser/gpu/gpu_util.h | 37 + .../browser/gpu}/gpu_util_unittest.cc | 39 +- content/content_browser.gypi | 4 + content/content_tests.gypi | 2 + content/public/browser/gpu_data_manager.h | 25 +- 24 files changed, 891 insertions(+), 888 deletions(-) create mode 100644 chrome/browser/chrome_gpu_util.cc create mode 100644 chrome/browser/chrome_gpu_util.h delete mode 100644 chrome/browser/gpu_util.cc delete mode 100644 chrome/browser/gpu_util.h rename {chrome/browser => content/browser/gpu}/gpu_blacklist.cc (97%) rename {chrome/browser => content/browser/gpu}/gpu_blacklist.h (93%) rename {chrome/browser => content/browser/gpu}/gpu_blacklist_unittest.cc (99%) create mode 100644 content/browser/gpu/gpu_util.cc create mode 100644 content/browser/gpu/gpu_util.h rename {chrome/browser => content/browser/gpu}/gpu_util_unittest.cc (62%) diff --git a/chrome/browser/chrome_browser_field_trials.cc b/chrome/browser/chrome_browser_field_trials.cc index 7ca49a1d142b81..2f436e6183c41e 100644 --- a/chrome/browser/chrome_browser_field_trials.cc +++ b/chrome/browser/chrome_browser_field_trials.cc @@ -15,9 +15,9 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/auto_launch_trial.h" #include "chrome/browser/autocomplete/autocomplete_field_trial.h" +#include "chrome/browser/chrome_gpu_util.h" #include "chrome/browser/extensions/default_apps_trial.h" #include "chrome/browser/google/google_util.h" -#include "chrome/browser/gpu_util.h" #include "chrome/browser/instant/instant_field_trials.h" #include "chrome/browser/net/predictor.h" #include "chrome/browser/prerender/prerender_field_trial.h" diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 4eda935afb78f2..6900a07bdf032e 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc @@ -34,6 +34,7 @@ #include "chrome/browser/browser_process_impl.h" #include "chrome/browser/browser_shutdown.h" #include "chrome/browser/chrome_browser_main_extra_parts.h" +#include "chrome/browser/chrome_gpu_util.h" #include "chrome/browser/defaults.h" #include "chrome/browser/extensions/extension_protocols.h" #include "chrome/browser/extensions/extension_service.h" @@ -41,7 +42,6 @@ #include "chrome/browser/first_run/upgrade_util.h" #include "chrome/browser/google/google_search_counter.h" #include "chrome/browser/google/google_util.h" -#include "chrome/browser/gpu_blacklist.h" #include "chrome/browser/jankometer.h" #include "chrome/browser/language_usage_metrics.h" #include "chrome/browser/managed_mode.h" @@ -396,25 +396,6 @@ Profile* CreateProfile(const content::MainFunctionParams& parameters, return NULL; } -// Load GPU Blacklist, collect preliminary gpu info, and compute preliminary -// gpu feature flags. -void InitializeGpuDataManager(const CommandLine& parsed_command_line) { - content::GpuDataManager::GetInstance()->InitializeGpuInfo(); - if (parsed_command_line.HasSwitch(switches::kSkipGpuDataLoading) || - parsed_command_line.HasSwitch(switches::kIgnoreGpuBlacklist)) { - return; - } - - const base::StringPiece gpu_blacklist_json( - ResourceBundle::GetSharedInstance().GetRawDataResource( - IDR_GPU_BLACKLIST, ui::SCALE_FACTOR_NONE)); - GpuBlacklist* gpu_blacklist = GpuBlacklist::GetInstance(); - bool succeed = gpu_blacklist->LoadGpuBlacklist( - gpu_blacklist_json.as_string(), GpuBlacklist::kCurrentOsOnly); - DCHECK(succeed); - gpu_blacklist->UpdateGpuDataManager(); -} - #if defined(OS_MACOSX) OSStatus KeychainCallback(SecKeychainEvent keychain_event, SecKeychainCallbackInfo* info, void* context) { @@ -1333,8 +1314,8 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() { CloudPrintProxyServiceFactory::GetForProfile(profile_); #endif - // Load GPU Blacklist. - InitializeGpuDataManager(parsed_command_line()); + // Load GPU Blacklist; load preliminary GPU info. + gpu_util::InitializeGpuDataManager(parsed_command_line()); // Start watching all browser threads for responsiveness. ThreadWatcherList::StartWatchingAll(parsed_command_line()); diff --git a/chrome/browser/chrome_gpu_util.cc b/chrome/browser/chrome_gpu_util.cc new file mode 100644 index 00000000000000..0371917acbd514 --- /dev/null +++ b/chrome/browser/chrome_gpu_util.cc @@ -0,0 +1,123 @@ +// Copyright (c) 2012 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/chrome_gpu_util.h" + +#include "base/command_line.h" +#include "base/metrics/field_trial.h" +#include "base/metrics/histogram.h" +#include "base/version.h" +#if defined(OS_WIN) +#include "base/win/windows_version.h" +#endif +#include "chrome/common/chrome_switches.h" +#include "chrome/common/chrome_version_info.h" +#include "content/public/browser/gpu_data_manager.h" +#include "content/public/common/content_constants.h" +#include "content/public/common/content_switches.h" +#include "grit/browser_resources.h" +#include "ui/base/resource/resource_bundle.h" + +using content::GpuDataManager; + +namespace gpu_util { + +void InitializeCompositingFieldTrial() { +// Enable the field trial only on desktop OS's. +#if !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)) + return; +#endif +#if defined(OS_WIN) + // Don't run the trial on Windows XP. + if (base::win::GetVersion() < base::win::VERSION_VISTA) + return; +#endif + + // The performance of accelerated compositing is too low with software + // rendering. + if (content::GpuDataManager::GetInstance()->ShouldUseSoftwareRendering()) + return; + + // Don't activate the field trial if force-compositing-mode has been + // explicitly disabled from the command line. + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableForceCompositingMode)) + return; + + const base::FieldTrial::Probability kDivisor = 3; + scoped_refptr trial( + base::FieldTrialList::FactoryGetFieldTrial( + content::kGpuCompositingFieldTrialName, kDivisor, + "disable", 2012, 12, 31, NULL)); + + // Produce the same result on every run of this client. + trial->UseOneTimeRandomization(); + + base::FieldTrial::Probability force_compositing_mode_probability = 0; + base::FieldTrial::Probability threaded_compositing_probability = 0; + + chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); + if (channel == chrome::VersionInfo::CHANNEL_STABLE || + channel == chrome::VersionInfo::CHANNEL_BETA) { + // Stable and Beta channels: Non-threaded force-compositing-mode on by + // default (mac and windows only). +#if defined(OS_WIN) || defined(OS_MACOSX) + force_compositing_mode_probability = 3; +#endif + } else if (channel == chrome::VersionInfo::CHANNEL_DEV || + channel == chrome::VersionInfo::CHANNEL_CANARY) { + // Dev and Canary channels: force-compositing-mode and + // threaded-compositing on with 1/3 probability each. + force_compositing_mode_probability = 1; + +#if defined(OS_MACOSX) || defined(OS_LINUX) + // Threaded compositing mode isn't feature complete on mac or linux yet: + // http://crbug.com/133602 for mac + // http://crbug.com/140866 for linux + threaded_compositing_probability = 0; +#else + if (!CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableThreadedCompositing)) + threaded_compositing_probability = 1; +#endif + } + + int force_compositing_group = trial->AppendGroup( + content::kGpuCompositingFieldTrialForceCompositingEnabledName, + force_compositing_mode_probability); + int thread_group = trial->AppendGroup( + content::kGpuCompositingFieldTrialThreadEnabledName, + threaded_compositing_probability); + + bool force_compositing = (trial->group() == force_compositing_group); + bool thread = (trial->group() == thread_group); + UMA_HISTOGRAM_BOOLEAN("GPU.InForceCompositingModeFieldTrial", + force_compositing); + UMA_HISTOGRAM_BOOLEAN("GPU.InCompositorThreadFieldTrial", thread); +} + +// Load GPU Blacklist, collect preliminary gpu info, and compute preliminary +// gpu feature flags. +void InitializeGpuDataManager(const CommandLine& command_line) { + if (command_line.HasSwitch(switches::kSkipGpuDataLoading)) + return; + + std::string chrome_version_string = "0"; + std::string gpu_blacklist_json_string; + if (!command_line.HasSwitch(switches::kIgnoreGpuBlacklist)) { + chrome::VersionInfo chrome_version_info; + if (chrome_version_info.is_valid()) + chrome_version_string = chrome_version_info.Version(); + + const base::StringPiece gpu_blacklist_json( + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_GPU_BLACKLIST, ui::SCALE_FACTOR_NONE)); + gpu_blacklist_json_string = gpu_blacklist_json.as_string(); + } + content::GpuDataManager::GetInstance()->Initialize( + chrome_version_string, gpu_blacklist_json_string); +} + +} // namespace gpu_util; + diff --git a/chrome/browser/chrome_gpu_util.h b/chrome/browser/chrome_gpu_util.h new file mode 100644 index 00000000000000..b24a3aac542d2c --- /dev/null +++ b/chrome/browser/chrome_gpu_util.h @@ -0,0 +1,22 @@ +// Copyright (c) 2012 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_CHROME_GPU_UTIL_H_ +#define CHROME_BROWSER_CHROME_GPU_UTIL_H_ + +class CommandLine; + +namespace gpu_util { + +// Sets up force-compositing-mode and threaded compositing field trials. +void InitializeCompositingFieldTrial(); + +// Load GPU Blacklist, collect preliminary gpu info, and compute preliminary +// gpu feature flags. +void InitializeGpuDataManager(const CommandLine& command_line); + +} // namespace gpu_util + +#endif // CHROME_BROWSER_CHROME_GPU_UTIL_H_ + diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc index b15227d4943889..bb2d0690f59240 100644 --- a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc +++ b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc @@ -16,7 +16,6 @@ #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h" #include "chrome/browser/extensions/webstore_installer.h" -#include "chrome/browser/gpu_blacklist.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_notification_types.h" @@ -436,11 +435,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebstoreGetWebGLStatusTest, Blocked) { " }\n" " ]\n" "}"; - GpuBlacklist* blacklist = GpuBlacklist::GetInstance(); - - ASSERT_TRUE(blacklist->LoadGpuBlacklist( - json_blacklist, GpuBlacklist::kAllOs)); - blacklist->UpdateGpuDataManager(); + content::GpuDataManager::GetInstance()->Initialize("0", json_blacklist); GpuFeatureType type = content::GpuDataManager::GetInstance()->GetBlacklistedFeatures(); EXPECT_EQ(type, content::GPU_FEATURE_TYPE_WEBGL); diff --git a/chrome/browser/gpu_util.cc b/chrome/browser/gpu_util.cc deleted file mode 100644 index e81de8e58206b3..00000000000000 --- a/chrome/browser/gpu_util.cc +++ /dev/null @@ -1,631 +0,0 @@ -// Copyright (c) 2012 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_util.h" - -#include - -#include "base/command_line.h" -#include "base/metrics/field_trial.h" -#include "base/metrics/histogram.h" -#include "base/string_number_conversions.h" -#include "base/string_util.h" -#include "base/stringprintf.h" -#include "base/sys_info.h" -#include "base/values.h" -#include "base/version.h" -#include "chrome/browser/gpu_blacklist.h" -#include "chrome/common/chrome_version_info.h" -#include "content/public/browser/gpu_data_manager.h" -#include "content/public/common/compositor_util.h" -#include "content/public/common/content_constants.h" -#include "content/public/common/content_switches.h" -#include "content/public/common/gpu_info.h" - -#if defined(OS_WIN) -#include "base/win/windows_version.h" -#endif - -using content::GpuDataManager; -using content::GpuFeatureType; - -namespace { - -const char kGpuFeatureNameAccelerated2dCanvas[] = "accelerated_2d_canvas"; -const char kGpuFeatureNameAcceleratedCompositing[] = "accelerated_compositing"; -const char kGpuFeatureNameWebgl[] = "webgl"; -const char kGpuFeatureNameMultisampling[] = "multisampling"; -const char kGpuFeatureNameFlash3d[] = "flash_3d"; -const char kGpuFeatureNameFlashStage3d[] = "flash_stage3d"; -const char kGpuFeatureNameTextureSharing[] = "texture_sharing"; -const char kGpuFeatureNameAcceleratedVideoDecode[] = "accelerated_video_decode"; -const char kGpuFeatureNameAll[] = "all"; -const char kGpuFeatureNameUnknown[] = "unknown"; - -enum GpuFeatureStatus { - kGpuFeatureEnabled = 0, - kGpuFeatureBlacklisted = 1, - kGpuFeatureDisabled = 2, // disabled by user but not blacklisted - kGpuFeatureNumStatus -}; - -struct GpuFeatureInfo { - std::string name; - uint32 blocked; - bool disabled; - std::string disabled_description; - bool fallback_to_software; -}; - -// Determine if accelerated-2d-canvas is supported, which depends on whether -// lose_context could happen and whether skia is the backend. -bool SupportsAccelerated2dCanvas() { - if (GpuDataManager::GetInstance()->GetGPUInfo().can_lose_context) - return false; -#if defined(USE_SKIA) - return true; -#else - return false; -#endif -} - -DictionaryValue* NewDescriptionValuePair(const std::string& desc, - const std::string& value) { - DictionaryValue* dict = new DictionaryValue(); - dict->SetString("description", desc); - dict->SetString("value", value); - return dict; -} - -DictionaryValue* NewDescriptionValuePair(const std::string& desc, - Value* value) { - DictionaryValue* dict = new DictionaryValue(); - dict->SetString("description", desc); - dict->Set("value", value); - return dict; -} - -Value* NewStatusValue(const char* name, const char* status) { - DictionaryValue* value = new DictionaryValue(); - value->SetString("name", name); - value->SetString("status", status); - return value; -} - -std::string GPUDeviceToString(const content::GPUInfo::GPUDevice& gpu) { - std::string vendor = base::StringPrintf("0x%04x", gpu.vendor_id); - if (!gpu.vendor_string.empty()) - vendor += " [" + gpu.vendor_string + "]"; - std::string device = base::StringPrintf("0x%04x", gpu.device_id); - if (!gpu.device_string.empty()) - device += " [" + gpu.device_string + "]"; - return base::StringPrintf( - "VENDOR = %s, DEVICE= %s", vendor.c_str(), device.c_str()); -} - -#if defined(OS_WIN) - -enum WinSubVersion { - kWinOthers = 0, - kWinXP, - kWinVista, - kWin7, - kNumWinSubVersions -}; - -// Output DxDiagNode tree as nested array of {description,value} pairs -ListValue* DxDiagNodeToList(const content::DxDiagNode& node) { - ListValue* list = new ListValue(); - for (std::map::const_iterator it = - node.values.begin(); - it != node.values.end(); - ++it) { - list->Append(NewDescriptionValuePair(it->first, it->second)); - } - - for (std::map::const_iterator it = - node.children.begin(); - it != node.children.end(); - ++it) { - ListValue* sublist = DxDiagNodeToList(it->second); - list->Append(NewDescriptionValuePair(it->first, sublist)); - } - return list; -} - -int GetGpuBlacklistHistogramValueWin(GpuFeatureStatus status) { - static WinSubVersion sub_version = kNumWinSubVersions; - if (sub_version == kNumWinSubVersions) { - sub_version = kWinOthers; - std::string version_str = base::SysInfo::OperatingSystemVersion(); - size_t pos = version_str.find_first_not_of("0123456789."); - if (pos != std::string::npos) - version_str = version_str.substr(0, pos); - Version os_version(version_str); - if (os_version.IsValid() && os_version.components().size() >= 2) { - const std::vector& version_numbers = os_version.components(); - if (version_numbers[0] == 5) - sub_version = kWinXP; - else if (version_numbers[0] == 6 && version_numbers[1] == 0) - sub_version = kWinVista; - else if (version_numbers[0] == 6 && version_numbers[1] == 1) - sub_version = kWin7; - } - } - int entry_index = static_cast(sub_version) * kGpuFeatureNumStatus; - switch (status) { - case kGpuFeatureEnabled: - break; - case kGpuFeatureBlacklisted: - entry_index++; - break; - case kGpuFeatureDisabled: - entry_index += 2; - break; - } - return entry_index; -} -#endif // OS_WIN - -} // namespace - -namespace gpu_util { - -void InitializeCompositingFieldTrial() { -// Enable the field trial only on desktop OS's. -#if !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)) - return; -#endif -#if defined(OS_WIN) - // Don't run the trial on Windows XP. - if (base::win::GetVersion() < base::win::VERSION_VISTA) - return; -#endif - - // The performance of accelerated compositing is too low with software - // rendering. - if (content::GpuDataManager::GetInstance()->ShouldUseSoftwareRendering()) - return; - - // Don't activate the field trial if force-compositing-mode has been - // explicitly disabled from the command line. - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableForceCompositingMode)) - return; - - const base::FieldTrial::Probability kDivisor = 3; - scoped_refptr trial( - base::FieldTrialList::FactoryGetFieldTrial( - content::kGpuCompositingFieldTrialName, kDivisor, - "disable", 2012, 12, 31, NULL)); - - // Produce the same result on every run of this client. - trial->UseOneTimeRandomization(); - - base::FieldTrial::Probability force_compositing_mode_probability = 0; - base::FieldTrial::Probability threaded_compositing_probability = 0; - - chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); - if (channel == chrome::VersionInfo::CHANNEL_STABLE || - channel == chrome::VersionInfo::CHANNEL_BETA) { - // Stable and Beta channels: Non-threaded force-compositing-mode on by - // default (mac and windows only). -#if defined(OS_WIN) || defined(OS_MACOSX) - force_compositing_mode_probability = 3; -#endif - } else if (channel == chrome::VersionInfo::CHANNEL_DEV || - channel == chrome::VersionInfo::CHANNEL_CANARY) { - // Dev and Canary channels: force-compositing-mode and - // threaded-compositing on with 1/3 probability each. - force_compositing_mode_probability = 1; - -#if defined(OS_MACOSX) || defined(OS_LINUX) - // Threaded compositing mode isn't feature complete on mac or linux yet: - // http://crbug.com/133602 for mac - // http://crbug.com/140866 for linux - threaded_compositing_probability = 0; -#else - if (!CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableThreadedCompositing)) - threaded_compositing_probability = 1; -#endif - } - - - int force_compositing_group = trial->AppendGroup( - content::kGpuCompositingFieldTrialForceCompositingEnabledName, - force_compositing_mode_probability); - int thread_group = trial->AppendGroup( - content::kGpuCompositingFieldTrialThreadEnabledName, - threaded_compositing_probability); - - bool force_compositing = (trial->group() == force_compositing_group); - bool thread = (trial->group() == thread_group); - UMA_HISTOGRAM_BOOLEAN("GPU.InForceCompositingModeFieldTrial", - force_compositing); - UMA_HISTOGRAM_BOOLEAN("GPU.InCompositorThreadFieldTrial", thread); -} - -GpuFeatureType StringToGpuFeatureType(const std::string& feature_string) { - if (feature_string == kGpuFeatureNameAccelerated2dCanvas) - return content::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS; - else if (feature_string == kGpuFeatureNameAcceleratedCompositing) - return content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING; - else if (feature_string == kGpuFeatureNameWebgl) - return content::GPU_FEATURE_TYPE_WEBGL; - else if (feature_string == kGpuFeatureNameMultisampling) - return content::GPU_FEATURE_TYPE_MULTISAMPLING; - else if (feature_string == kGpuFeatureNameFlash3d) - return content::GPU_FEATURE_TYPE_FLASH3D; - else if (feature_string == kGpuFeatureNameFlashStage3d) - return content::GPU_FEATURE_TYPE_FLASH_STAGE3D; - else if (feature_string == kGpuFeatureNameTextureSharing) - return content::GPU_FEATURE_TYPE_TEXTURE_SHARING; - else if (feature_string == kGpuFeatureNameAcceleratedVideoDecode) - return content::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE; - else if (feature_string == kGpuFeatureNameAll) - return content::GPU_FEATURE_TYPE_ALL; - return content::GPU_FEATURE_TYPE_UNKNOWN; -} - -std::string GpuFeatureTypeToString(GpuFeatureType type) { - std::vector matches; - if (type == content::GPU_FEATURE_TYPE_ALL) { - matches.push_back(kGpuFeatureNameAll); - } else { - if (type & content::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS) - matches.push_back(kGpuFeatureNameAccelerated2dCanvas); - if (type & content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) - matches.push_back(kGpuFeatureNameAcceleratedCompositing); - if (type & content::GPU_FEATURE_TYPE_WEBGL) - matches.push_back(kGpuFeatureNameWebgl); - if (type & content::GPU_FEATURE_TYPE_MULTISAMPLING) - matches.push_back(kGpuFeatureNameMultisampling); - if (type & content::GPU_FEATURE_TYPE_FLASH3D) - matches.push_back(kGpuFeatureNameFlash3d); - if (type & content::GPU_FEATURE_TYPE_FLASH_STAGE3D) - matches.push_back(kGpuFeatureNameFlashStage3d); - if (type & content::GPU_FEATURE_TYPE_TEXTURE_SHARING) - matches.push_back(kGpuFeatureNameTextureSharing); - if (!matches.size()) - matches.push_back(kGpuFeatureNameUnknown); - } - return JoinString(matches, ','); -} - -Value* GetFeatureStatus() { - const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - bool gpu_access_blocked = !GpuDataManager::GetInstance()->GpuAccessAllowed(); - - uint32 flags = GpuDataManager::GetInstance()->GetBlacklistedFeatures(); - DictionaryValue* status = new DictionaryValue(); - - const GpuFeatureInfo kGpuFeatureInfo[] = { - { - "2d_canvas", - flags & content::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS, - command_line.HasSwitch(switches::kDisableAccelerated2dCanvas) || - !SupportsAccelerated2dCanvas(), - "Accelerated 2D canvas is unavailable: either disabled at the command" - " line or not supported by the current system.", - true - }, - { - "compositing", - flags & content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING, - command_line.HasSwitch(switches::kDisableAcceleratedCompositing), - "Accelerated compositing has been disabled, either via about:flags or" - " command line. This adversely affects performance of all hardware" - " accelerated features.", - true - }, - { - "3d_css", - flags & content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING, - command_line.HasSwitch(switches::kDisableAcceleratedLayers), - "Accelerated layers have been disabled at the command line.", - false - }, - { - "css_animation", - flags & content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING, - command_line.HasSwitch(switches::kDisableThreadedAnimation) || - command_line.HasSwitch(switches::kDisableAcceleratedCompositing), - "Accelerated CSS animation has been disabled at the command line.", - true - }, - { - "webgl", - flags & content::GPU_FEATURE_TYPE_WEBGL, -#if defined(OS_ANDROID) - !command_line.HasSwitch(switches::kEnableExperimentalWebGL), -#else - command_line.HasSwitch(switches::kDisableExperimentalWebGL), -#endif - "WebGL has been disabled, either via about:flags or command line.", - false - }, - { - "multisampling", - flags & content::GPU_FEATURE_TYPE_MULTISAMPLING, - command_line.HasSwitch(switches::kDisableGLMultisampling), - "Multisampling has been disabled, either via about:flags or command" - " line.", - false - }, - { - "flash_3d", - flags & content::GPU_FEATURE_TYPE_FLASH3D, - command_line.HasSwitch(switches::kDisableFlash3d), - "Using 3d in flash has been disabled, either via about:flags or" - " command line.", - false - }, - { - "flash_stage3d", - flags & content::GPU_FEATURE_TYPE_FLASH_STAGE3D, - command_line.HasSwitch(switches::kDisableFlashStage3d), - "Using Stage3d in Flash has been disabled, either via about:flags or" - " command line.", - false - }, - { - "texture_sharing", - flags & content::GPU_FEATURE_TYPE_TEXTURE_SHARING, - command_line.HasSwitch(switches::kDisableImageTransportSurface), - "Sharing textures between processes has been disabled, either via" - " about:flags or command line.", - false - }, - { - "video_decode", - flags & content::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE, - command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode), - "Accelerated video decode has been disabled, either via about:flags" - " or command line.", - true - } - }; - const size_t kNumFeatures = sizeof(kGpuFeatureInfo) / sizeof(GpuFeatureInfo); - - // Build the feature_status field. - { - ListValue* feature_status_list = new ListValue(); - - for (size_t i = 0; i < kNumFeatures; ++i) { - std::string status; - if (kGpuFeatureInfo[i].disabled) { - status = "disabled"; - if (kGpuFeatureInfo[i].name == "css_animation") { - status += "_software_animated"; - } else { - if (kGpuFeatureInfo[i].fallback_to_software) - status += "_software"; - else - status += "_off"; - } - } else if (GpuDataManager::GetInstance()->ShouldUseSoftwareRendering()) { - status = "unavailable_software"; - } else if (kGpuFeatureInfo[i].blocked || - gpu_access_blocked) { - status = "unavailable"; - if (kGpuFeatureInfo[i].fallback_to_software) - status += "_software"; - else - status += "_off"; - } else { - status = "enabled"; - if (kGpuFeatureInfo[i].name == "webgl" && - (command_line.HasSwitch(switches::kDisableAcceleratedCompositing) || - (flags & content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING))) - status += "_readback"; - bool has_thread = content::IsThreadedCompositingEnabled(); - if (kGpuFeatureInfo[i].name == "compositing") { - bool force_compositing = - content::IsForceCompositingModeEnabled(); - if (force_compositing) - status += "_force"; - if (has_thread) - status += "_threaded"; - } - if (kGpuFeatureInfo[i].name == "css_animation") { - if (has_thread) - status = "accelerated_threaded"; - else - status = "accelerated"; - } - } - feature_status_list->Append( - NewStatusValue(kGpuFeatureInfo[i].name.c_str(), status.c_str())); - } - - status->Set("featureStatus", feature_status_list); - } - - // Build the problems list. - { - ListValue* problem_list = new ListValue(); - - if (gpu_access_blocked) { - DictionaryValue* problem = new DictionaryValue(); - problem->SetString("description", - "GPU process was unable to boot. Access to GPU disallowed."); - problem->Set("crBugs", new ListValue()); - problem->Set("webkitBugs", new ListValue()); - problem_list->Append(problem); - } - - for (size_t i = 0; i < kNumFeatures; ++i) { - if (kGpuFeatureInfo[i].disabled) { - DictionaryValue* problem = new DictionaryValue(); - problem->SetString( - "description", kGpuFeatureInfo[i].disabled_description); - problem->Set("crBugs", new ListValue()); - problem->Set("webkitBugs", new ListValue()); - problem_list->Append(problem); - } - } - - GpuBlacklist::GetInstance()->GetBlacklistReasons(problem_list); - - status->Set("problems", problem_list); - } - - return status; -} - -DictionaryValue* GpuInfoAsDictionaryValue() { - content::GPUInfo gpu_info = GpuDataManager::GetInstance()->GetGPUInfo(); - ListValue* basic_info = new ListValue(); - basic_info->Append(NewDescriptionValuePair( - "Initialization time", - base::Int64ToString(gpu_info.initialization_time.InMilliseconds()))); - basic_info->Append(NewDescriptionValuePair( - "GPU0", GPUDeviceToString(gpu_info.gpu))); - for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) { - basic_info->Append(NewDescriptionValuePair( - base::StringPrintf("GPU%d", static_cast(i + 1)), - GPUDeviceToString(gpu_info.secondary_gpus[i]))); - } - basic_info->Append(NewDescriptionValuePair( - "Optimus", Value::CreateBooleanValue(gpu_info.optimus))); - basic_info->Append(NewDescriptionValuePair( - "AMD switchable", Value::CreateBooleanValue(gpu_info.amd_switchable))); - basic_info->Append(NewDescriptionValuePair("Driver vendor", - gpu_info.driver_vendor)); - basic_info->Append(NewDescriptionValuePair("Driver version", - gpu_info.driver_version)); - basic_info->Append(NewDescriptionValuePair("Driver date", - gpu_info.driver_date)); - basic_info->Append(NewDescriptionValuePair("Pixel shader version", - gpu_info.pixel_shader_version)); - basic_info->Append(NewDescriptionValuePair("Vertex shader version", - gpu_info.vertex_shader_version)); - basic_info->Append(NewDescriptionValuePair("GL version", - gpu_info.gl_version)); - basic_info->Append(NewDescriptionValuePair("GL_VENDOR", - gpu_info.gl_vendor)); - basic_info->Append(NewDescriptionValuePair("GL_RENDERER", - gpu_info.gl_renderer)); - basic_info->Append(NewDescriptionValuePair("GL_VERSION", - gpu_info.gl_version_string)); - basic_info->Append(NewDescriptionValuePair("GL_EXTENSIONS", - gpu_info.gl_extensions)); - - DictionaryValue* info = new DictionaryValue(); - info->Set("basic_info", basic_info); - -#if defined(OS_WIN) - ListValue* perf_info = new ListValue(); - perf_info->Append(NewDescriptionValuePair( - "Graphics", - base::StringPrintf("%.1f", gpu_info.performance_stats.graphics))); - perf_info->Append(NewDescriptionValuePair( - "Gaming", - base::StringPrintf("%.1f", gpu_info.performance_stats.gaming))); - perf_info->Append(NewDescriptionValuePair( - "Overall", - base::StringPrintf("%.1f", gpu_info.performance_stats.overall))); - info->Set("performance_info", perf_info); - - Value* dx_info; - if (gpu_info.dx_diagnostics.children.size()) - dx_info = DxDiagNodeToList(gpu_info.dx_diagnostics); - else - dx_info = Value::CreateNullValue(); - info->Set("diagnostics", dx_info); -#endif - - return info; -} - -void UpdateStats() { - GpuBlacklist* blacklist = GpuBlacklist::GetInstance(); - uint32 max_entry_id = blacklist->max_entry_id(); - if (max_entry_id == 0) { - // GPU Blacklist was not loaded. No need to go further. - return; - } - - const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - uint32 flags = GpuDataManager::GetInstance()->GetBlacklistedFeatures(); - bool disabled = false; - if (flags == 0) { - UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry", - 0, max_entry_id + 1); - } else { - std::vector flag_entries; - blacklist->GetGpuFeatureTypeEntries( - content::GPU_FEATURE_TYPE_ALL, flag_entries, disabled); - DCHECK_GT(flag_entries.size(), 0u); - for (size_t i = 0; i < flag_entries.size(); ++i) { - UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry", - flag_entries[i], max_entry_id + 1); - } - } - - // This counts how many users are affected by a disabled entry - this allows - // us to understand the impact of an entry before enable it. - std::vector flag_disabled_entries; - disabled = true; - blacklist->GetGpuFeatureTypeEntries( - content::GPU_FEATURE_TYPE_ALL, flag_disabled_entries, disabled); - for (size_t i = 0; i < flag_disabled_entries.size(); ++i) { - UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerDisabledEntry", - flag_disabled_entries[i], max_entry_id + 1); - } - - const content::GpuFeatureType kGpuFeatures[] = { - content::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS, - content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING, - content::GPU_FEATURE_TYPE_WEBGL - }; - const std::string kGpuBlacklistFeatureHistogramNames[] = { - "GPU.BlacklistFeatureTestResults.Accelerated2dCanvas", - "GPU.BlacklistFeatureTestResults.AcceleratedCompositing", - "GPU.BlacklistFeatureTestResults.Webgl" - }; - const bool kGpuFeatureUserFlags[] = { - command_line.HasSwitch(switches::kDisableAccelerated2dCanvas), - command_line.HasSwitch(switches::kDisableAcceleratedCompositing), -#if defined(OS_ANDROID) - !command_line.HasSwitch(switches::kEnableExperimentalWebGL) -#else - command_line.HasSwitch(switches::kDisableExperimentalWebGL) -#endif - }; -#if defined(OS_WIN) - const std::string kGpuBlacklistFeatureHistogramNamesWin[] = { - "GPU.BlacklistFeatureTestResultsWindows.Accelerated2dCanvas", - "GPU.BlacklistFeatureTestResultsWindows.AcceleratedCompositing", - "GPU.BlacklistFeatureTestResultsWindows.Webgl" - }; -#endif - const size_t kNumFeatures = - sizeof(kGpuFeatures) / sizeof(content::GpuFeatureType); - for (size_t i = 0; i < kNumFeatures; ++i) { - // We can't use UMA_HISTOGRAM_ENUMERATION here because the same name is - // expected if the macro is used within a loop. - GpuFeatureStatus value = kGpuFeatureEnabled; - if (flags & kGpuFeatures[i]) - value = kGpuFeatureBlacklisted; - else if (kGpuFeatureUserFlags[i]) - value = kGpuFeatureDisabled; - base::Histogram* histogram_pointer = base::LinearHistogram::FactoryGet( - kGpuBlacklistFeatureHistogramNames[i], - 1, kGpuFeatureNumStatus, kGpuFeatureNumStatus + 1, - base::Histogram::kUmaTargetedHistogramFlag); - histogram_pointer->Add(value); -#if defined(OS_WIN) - histogram_pointer = base::LinearHistogram::FactoryGet( - kGpuBlacklistFeatureHistogramNamesWin[i], - 1, kNumWinSubVersions * kGpuFeatureNumStatus, - kNumWinSubVersions * kGpuFeatureNumStatus + 1, - base::Histogram::kUmaTargetedHistogramFlag); - histogram_pointer->Add(GetGpuBlacklistHistogramValueWin(value)); -#endif - } -} - -} // namespace gpu_util; diff --git a/chrome/browser/gpu_util.h b/chrome/browser/gpu_util.h deleted file mode 100644 index 89924cf55cd76d..00000000000000 --- a/chrome/browser/gpu_util.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2012 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_UTIL_H_ -#define CHROME_BROWSER_GPU_UTIL_H_ - -#include - -#include "content/public/common/gpu_feature_type.h" - -namespace base { -class DictionaryValue; -class Value; -} - -namespace gpu_util { - -// Maps string to GpuFeatureType; returns GPU_FEATURE_TYPE_UNKNOWN if none of -// the following is input (case-sensitive): -// "accelerated_2d_canvas" -// "accelerated_compositing" -// "webgl" -// "multisampling" -content::GpuFeatureType StringToGpuFeatureType( - const std::string& feature_string); - -// Gets a string version of a feature type for use in about:gpu. Will yield -// strings from StringToGpuFeatureType, e.g. -// GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS becomes "accelerated_2d_canvas" -std::string GpuFeatureTypeToString(content::GpuFeatureType feature); - -// Returns status of various GPU features. This is two parted: -// { -// featureStatus: [] -// problems: [] -// } -// -// Each entry in feature_status has: -// { -// name: "name of feature" -// status: "enabled" | "unavailable_software" | "unavailable_off" | -// "software" | "disabled_off" | "disabled_softare"; -// } -// -// The features reported are not 1:1 with GpuFeatureType. Rather, they are: -// '2d_canvas' -// '3d_css' -// 'composting', -// 'webgl', -// 'multisampling', -// 'flash_3d', -// 'flash_stage3d', -// 'texture_sharing' -// 'video_decode' -// -// Each problems has: -// { -// "description": "Your GPU is too old", -// "crBugs": [1234], -// "webkitBugs": [] -// } -// -// Caller is responsible for deleting the returned value. -base::Value* GetFeatureStatus(); - -// Returns the GpuInfo as a DictionaryValue. -base::DictionaryValue* GpuInfoAsDictionaryValue(); - -// Send UMA histograms about the enabled features. -void UpdateStats(); - -// Sets up force-compositing-mode and threaded compositing field trials. -void InitializeCompositingFieldTrial(); - -} // namespace gpu_util - -#endif // CHROME_BROWSER_GPU_UTIL_H_ diff --git a/chrome/browser/ui/webui/gpu_internals_ui.cc b/chrome/browser/ui/webui/gpu_internals_ui.cc index 219a75ba7b24eb..287a68c5d7278c 100644 --- a/chrome/browser/ui/webui/gpu_internals_ui.cc +++ b/chrome/browser/ui/webui/gpu_internals_ui.cc @@ -15,8 +15,6 @@ #include "base/sys_info.h" #include "base/values.h" #include "chrome/browser/crash_upload_list.h" -#include "chrome/browser/gpu_blacklist.h" -#include "chrome/browser/gpu_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/chrome_url_data_manager.h" #include "chrome/browser/ui/webui/chrome_web_ui_data_source.h" @@ -29,6 +27,9 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_message_handler.h" +#include "content/public/common/compositor_util.h" +#include "content/public/common/content_switches.h" +#include "content/public/common/gpu_info.h" #include "grit/browser_resources.h" #include "grit/generated_resources.h" #include "third_party/angle/src/common/version.h" @@ -41,11 +42,20 @@ using content::BrowserThread; using content::GpuDataManager; +using content::GpuFeatureType; using content::WebContents; using content::WebUIMessageHandler; namespace { +struct GpuFeatureInfo { + std::string name; + uint32 blocked; + bool disabled; + std::string disabled_description; + bool fallback_to_software; +}; + ChromeWebUIDataSource* CreateGpuHTMLSource() { ChromeWebUIDataSource* source = new ChromeWebUIDataSource(chrome::kChromeUIGpuInternalsHost); @@ -56,6 +66,317 @@ ChromeWebUIDataSource* CreateGpuHTMLSource() { return source; } +DictionaryValue* NewDescriptionValuePair(const std::string& desc, + const std::string& value) { + DictionaryValue* dict = new DictionaryValue(); + dict->SetString("description", desc); + dict->SetString("value", value); + return dict; +} + +DictionaryValue* NewDescriptionValuePair(const std::string& desc, + Value* value) { + DictionaryValue* dict = new DictionaryValue(); + dict->SetString("description", desc); + dict->Set("value", value); + return dict; +} + +Value* NewStatusValue(const char* name, const char* status) { + DictionaryValue* value = new DictionaryValue(); + value->SetString("name", name); + value->SetString("status", status); + return value; +} + +// Output DxDiagNode tree as nested array of {description,value} pairs +ListValue* DxDiagNodeToList(const content::DxDiagNode& node) { + ListValue* list = new ListValue(); + for (std::map::const_iterator it = + node.values.begin(); + it != node.values.end(); + ++it) { + list->Append(NewDescriptionValuePair(it->first, it->second)); + } + + for (std::map::const_iterator it = + node.children.begin(); + it != node.children.end(); + ++it) { + ListValue* sublist = DxDiagNodeToList(it->second); + list->Append(NewDescriptionValuePair(it->first, sublist)); + } + return list; +} + +std::string GPUDeviceToString(const content::GPUInfo::GPUDevice& gpu) { + std::string vendor = base::StringPrintf("0x%04x", gpu.vendor_id); + if (!gpu.vendor_string.empty()) + vendor += " [" + gpu.vendor_string + "]"; + std::string device = base::StringPrintf("0x%04x", gpu.device_id); + if (!gpu.device_string.empty()) + device += " [" + gpu.device_string + "]"; + return base::StringPrintf( + "VENDOR = %s, DEVICE= %s", vendor.c_str(), device.c_str()); +} + +DictionaryValue* GpuInfoAsDictionaryValue() { + content::GPUInfo gpu_info = GpuDataManager::GetInstance()->GetGPUInfo(); + ListValue* basic_info = new ListValue(); + basic_info->Append(NewDescriptionValuePair( + "Initialization time", + base::Int64ToString(gpu_info.initialization_time.InMilliseconds()))); + basic_info->Append(NewDescriptionValuePair( + "GPU0", GPUDeviceToString(gpu_info.gpu))); + for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) { + basic_info->Append(NewDescriptionValuePair( + base::StringPrintf("GPU%d", static_cast(i + 1)), + GPUDeviceToString(gpu_info.secondary_gpus[i]))); + } + basic_info->Append(NewDescriptionValuePair( + "Optimus", Value::CreateBooleanValue(gpu_info.optimus))); + basic_info->Append(NewDescriptionValuePair( + "AMD switchable", Value::CreateBooleanValue(gpu_info.amd_switchable))); + basic_info->Append(NewDescriptionValuePair("Driver vendor", + gpu_info.driver_vendor)); + basic_info->Append(NewDescriptionValuePair("Driver version", + gpu_info.driver_version)); + basic_info->Append(NewDescriptionValuePair("Driver date", + gpu_info.driver_date)); + basic_info->Append(NewDescriptionValuePair("Pixel shader version", + gpu_info.pixel_shader_version)); + basic_info->Append(NewDescriptionValuePair("Vertex shader version", + gpu_info.vertex_shader_version)); + basic_info->Append(NewDescriptionValuePair("GL version", + gpu_info.gl_version)); + basic_info->Append(NewDescriptionValuePair("GL_VENDOR", + gpu_info.gl_vendor)); + basic_info->Append(NewDescriptionValuePair("GL_RENDERER", + gpu_info.gl_renderer)); + basic_info->Append(NewDescriptionValuePair("GL_VERSION", + gpu_info.gl_version_string)); + basic_info->Append(NewDescriptionValuePair("GL_EXTENSIONS", + gpu_info.gl_extensions)); + + DictionaryValue* info = new DictionaryValue(); + info->Set("basic_info", basic_info); + +#if defined(OS_WIN) + ListValue* perf_info = new ListValue(); + perf_info->Append(NewDescriptionValuePair( + "Graphics", + base::StringPrintf("%.1f", gpu_info.performance_stats.graphics))); + perf_info->Append(NewDescriptionValuePair( + "Gaming", + base::StringPrintf("%.1f", gpu_info.performance_stats.gaming))); + perf_info->Append(NewDescriptionValuePair( + "Overall", + base::StringPrintf("%.1f", gpu_info.performance_stats.overall))); + info->Set("performance_info", perf_info); + + Value* dx_info; + if (gpu_info.dx_diagnostics.children.size()) + dx_info = DxDiagNodeToList(gpu_info.dx_diagnostics); + else + dx_info = Value::CreateNullValue(); + info->Set("diagnostics", dx_info); +#endif + + return info; +} + +// Determine if accelerated-2d-canvas is supported, which depends on whether +// lose_context could happen and whether skia is the backend. +bool SupportsAccelerated2dCanvas() { + if (GpuDataManager::GetInstance()->GetGPUInfo().can_lose_context) + return false; +#if defined(USE_SKIA) + return true; +#else + return false; +#endif +} + +Value* GetFeatureStatus() { + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + bool gpu_access_blocked = !GpuDataManager::GetInstance()->GpuAccessAllowed(); + + uint32 flags = GpuDataManager::GetInstance()->GetBlacklistedFeatures(); + DictionaryValue* status = new DictionaryValue(); + + const GpuFeatureInfo kGpuFeatureInfo[] = { + { + "2d_canvas", + flags & content::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS, + command_line.HasSwitch(switches::kDisableAccelerated2dCanvas) || + !SupportsAccelerated2dCanvas(), + "Accelerated 2D canvas is unavailable: either disabled at the command" + " line or not supported by the current system.", + true + }, + { + "compositing", + flags & content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING, + command_line.HasSwitch(switches::kDisableAcceleratedCompositing), + "Accelerated compositing has been disabled, either via about:flags or" + " command line. This adversely affects performance of all hardware" + " accelerated features.", + true + }, + { + "3d_css", + flags & content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING, + command_line.HasSwitch(switches::kDisableAcceleratedLayers), + "Accelerated layers have been disabled at the command line.", + false + }, + { + "css_animation", + flags & content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING, + command_line.HasSwitch(switches::kDisableThreadedAnimation) || + command_line.HasSwitch(switches::kDisableAcceleratedCompositing), + "Accelerated CSS animation has been disabled at the command line.", + true + }, + { + "webgl", + flags & content::GPU_FEATURE_TYPE_WEBGL, +#if defined(OS_ANDROID) + !command_line.HasSwitch(switches::kEnableExperimentalWebGL), +#else + command_line.HasSwitch(switches::kDisableExperimentalWebGL), +#endif + "WebGL has been disabled, either via about:flags or command line.", + false + }, + { + "multisampling", + flags & content::GPU_FEATURE_TYPE_MULTISAMPLING, + command_line.HasSwitch(switches::kDisableGLMultisampling), + "Multisampling has been disabled, either via about:flags or command" + " line.", + false + }, + { + "flash_3d", + flags & content::GPU_FEATURE_TYPE_FLASH3D, + command_line.HasSwitch(switches::kDisableFlash3d), + "Using 3d in flash has been disabled, either via about:flags or" + " command line.", + false + }, + { + "flash_stage3d", + flags & content::GPU_FEATURE_TYPE_FLASH_STAGE3D, + command_line.HasSwitch(switches::kDisableFlashStage3d), + "Using Stage3d in Flash has been disabled, either via about:flags or" + " command line.", + false + }, + { + "texture_sharing", + flags & content::GPU_FEATURE_TYPE_TEXTURE_SHARING, + command_line.HasSwitch(switches::kDisableImageTransportSurface), + "Sharing textures between processes has been disabled, either via" + " about:flags or command line.", + false + }, + { + "video_decode", + flags & content::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE, + command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode), + "Accelerated video decode has been disabled, either via about:flags" + " or command line.", + true + } + }; + const size_t kNumFeatures = sizeof(kGpuFeatureInfo) / sizeof(GpuFeatureInfo); + + // Build the feature_status field. + { + ListValue* feature_status_list = new ListValue(); + + for (size_t i = 0; i < kNumFeatures; ++i) { + std::string status; + if (kGpuFeatureInfo[i].disabled) { + status = "disabled"; + if (kGpuFeatureInfo[i].name == "css_animation") { + status += "_software_animated"; + } else { + if (kGpuFeatureInfo[i].fallback_to_software) + status += "_software"; + else + status += "_off"; + } + } else if (GpuDataManager::GetInstance()->ShouldUseSoftwareRendering()) { + status = "unavailable_software"; + } else if (kGpuFeatureInfo[i].blocked || + gpu_access_blocked) { + status = "unavailable"; + if (kGpuFeatureInfo[i].fallback_to_software) + status += "_software"; + else + status += "_off"; + } else { + status = "enabled"; + if (kGpuFeatureInfo[i].name == "webgl" && + (command_line.HasSwitch(switches::kDisableAcceleratedCompositing) || + (flags & content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING))) + status += "_readback"; + bool has_thread = content::IsThreadedCompositingEnabled(); + if (kGpuFeatureInfo[i].name == "compositing") { + bool force_compositing = + content::IsForceCompositingModeEnabled(); + if (force_compositing) + status += "_force"; + if (has_thread) + status += "_threaded"; + } + if (kGpuFeatureInfo[i].name == "css_animation") { + if (has_thread) + status = "accelerated_threaded"; + else + status = "accelerated"; + } + } + feature_status_list->Append( + NewStatusValue(kGpuFeatureInfo[i].name.c_str(), status.c_str())); + } + + status->Set("featureStatus", feature_status_list); + } + + // Build the problems list. + { + ListValue* problem_list = + GpuDataManager::GetInstance()->GetBlacklistReasons(); + + if (gpu_access_blocked) { + DictionaryValue* problem = new DictionaryValue(); + problem->SetString("description", + "GPU process was unable to boot. Access to GPU disallowed."); + problem->Set("crBugs", new ListValue()); + problem->Set("webkitBugs", new ListValue()); + problem_list->Append(problem); + } + + for (size_t i = 0; i < kNumFeatures; ++i) { + if (kGpuFeatureInfo[i].disabled) { + DictionaryValue* problem = new DictionaryValue(); + problem->SetString( + "description", kGpuFeatureInfo[i].disabled_description); + problem->Set("crBugs", new ListValue()); + problem->Set("webkitBugs", new ListValue()); + problem_list->Append(problem); + } + } + + status->Set("problems", problem_list); + } + + return status; +} + // This class receives javascript messages from the renderer. // Note that the WebUI infrastructure runs on the UI thread, therefore all of // this class's methods are expected to run on the UI thread. @@ -240,7 +561,7 @@ Value* GpuMessageHandler::OnRequestClientInfo(const ListValue* list) { dict->SetString("graphics_backend", "Core Graphics"); #endif dict->SetString("blacklist_version", - GpuBlacklist::GetInstance()->GetVersion()); + GpuDataManager::GetInstance()->GetBlacklistVersion()); return dict; } @@ -310,10 +631,10 @@ Value* GpuMessageHandler::OnRequestCrashList(const ListValue*) { void GpuMessageHandler::OnGpuInfoUpdate() { // Get GPU Info. scoped_ptr gpu_info_val( - gpu_util::GpuInfoAsDictionaryValue()); + GpuInfoAsDictionaryValue()); // Add in blacklisting features - Value* feature_status = gpu_util::GetFeatureStatus(); + Value* feature_status = GetFeatureStatus(); if (feature_status) gpu_info_val->Set("featureStatus", feature_status); diff --git a/chrome/browser/ui/webui/tracing_ui.cc b/chrome/browser/ui/webui/tracing_ui.cc index 584cd30b84dc22..9e61feec581975 100644 --- a/chrome/browser/ui/webui/tracing_ui.cc +++ b/chrome/browser/ui/webui/tracing_ui.cc @@ -15,8 +15,6 @@ #include "base/string_number_conversions.h" #include "base/stringprintf.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/gpu_blacklist.h" -#include "chrome/browser/gpu_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/chrome_select_file_policy.h" #include "chrome/browser/ui/webui/chrome_url_data_manager.h" @@ -70,8 +68,7 @@ class TracingMessageHandler : public WebUIMessageHandler, public ui::SelectFileDialog::Listener, public base::SupportsWeakPtr, - public content::TraceSubscriber, - public content::GpuDataManagerObserver { + public content::TraceSubscriber { public: TracingMessageHandler(); virtual ~TracingMessageHandler(); @@ -89,11 +86,6 @@ class TracingMessageHandler const scoped_refptr& trace_fragment); virtual void OnTraceBufferPercentFullReply(float percent_full); - // GpuDataManagerObserver implementation. - virtual void OnGpuInfoUpdate() OVERRIDE; - virtual void OnVideoMemoryUsageStatsUpdate( - const content::GPUVideoMemoryUsageStats& video_memory) OVERRIDE {} - // Messages. void OnTracingControllerInitialized(const ListValue* list); void OnBeginTracing(const ListValue* list); @@ -123,10 +115,6 @@ class TracingMessageHandler // True while system tracing is active. bool system_trace_in_progress_; - // True if observing the GpuDataManager (re-attaching as observer would - // DCHECK). - bool observing_; - void OnEndSystemTracingAck( const scoped_refptr& events_str_ptr); @@ -169,13 +157,10 @@ class TaskProxy : public base::RefCountedThreadSafe { TracingMessageHandler::TracingMessageHandler() : select_trace_file_dialog_type_(ui::SelectFileDialog::SELECT_NONE), trace_enabled_(false), - system_trace_in_progress_(false), - observing_(false) { + system_trace_in_progress_(false) { } TracingMessageHandler::~TracingMessageHandler() { - GpuDataManager::GetInstance()->RemoveObserver(this); - if (select_trace_file_dialog_) select_trace_file_dialog_->ListenerDestroyed(); @@ -219,19 +204,6 @@ void TracingMessageHandler::OnTracingControllerInitialized( const ListValue* args) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // Watch for changes in GPUInfo - if (!observing_) - GpuDataManager::GetInstance()->AddObserver(this); - observing_ = true; - - // Tell GpuDataManager it should have full GpuInfo. If the - // Gpu process has not run yet, this will trigger its launch. - GpuDataManager::GetInstance()->RequestCompleteGpuInfoIfNeeded(); - - // Run callback immediately in case the info is ready and no update in the - // future. - OnGpuInfoUpdate(); - // Send the client info to the tracingController { scoped_ptr dict(new DictionaryValue()); @@ -256,7 +228,7 @@ void TracingMessageHandler::OnTracingControllerInitialized( } dict->SetString("blacklist_version", - GpuBlacklist::GetInstance()->GetVersion()); + GpuDataManager::GetInstance()->GetBlacklistVersion()); web_ui()->CallJavascriptFunction("tracingController.onClientInfoUpdate", *dict); } @@ -267,21 +239,6 @@ void TracingMessageHandler::OnBeginRequestBufferPercentFull( TraceController::GetInstance()->GetTraceBufferPercentFullAsync(this); } -void TracingMessageHandler::OnGpuInfoUpdate() { - // Get GPU Info. - scoped_ptr gpu_info_val( - gpu_util::GpuInfoAsDictionaryValue()); - - // Add in blacklisting features - Value* feature_status = gpu_util::GetFeatureStatus(); - if (feature_status) - gpu_info_val->Set("featureStatus", feature_status); - - // Send GPU Info to javascript. - web_ui()->CallJavascriptFunction("tracingController.onGpuInfoUpdate", - *(gpu_info_val.get())); -} - // A callback used for asynchronously reading a file to a string. Calls the // TaskProxy callback when reading is complete. void ReadTraceFileCallback(TaskProxy* proxy, const FilePath& path) { diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index d0359ece1db15f..435d485189ef80 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -446,6 +446,8 @@ 'browser/chrome_browser_main_x11.h', 'browser/chrome_content_browser_client.cc', 'browser/chrome_content_browser_client.h', + 'browser/chrome_gpu_util.cc', + 'browser/chrome_gpu_util.h', 'browser/chrome_page_zoom.cc', 'browser/chrome_page_zoom.h', 'browser/chrome_page_zoom_constants.cc', @@ -657,12 +659,8 @@ 'browser/google/google_url_tracker_factory.h', 'browser/google/google_util.cc', 'browser/google/google_util.h', - 'browser/gpu_blacklist.cc', - 'browser/gpu_blacklist.h', 'browser/gpu_feature_checker.cc', 'browser/gpu_feature_checker.h', - 'browser/gpu_util.cc', - 'browser/gpu_util.h', 'browser/hang_monitor/hang_crash_dump_win.cc', 'browser/hang_monitor/hang_crash_dump_win.h', 'browser/hang_monitor/hung_plugin_action.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index b2e7db90ea78c3..1b85a5a0daf1cb 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1325,8 +1325,6 @@ 'browser/google/google_update_settings_unittest.cc', 'browser/google/google_url_tracker_unittest.cc', 'browser/google/google_util_unittest.cc', - 'browser/gpu_blacklist_unittest.cc', - 'browser/gpu_util_unittest.cc', 'browser/history/android/android_cache_database_unittest.cc', 'browser/history/android/android_history_provider_service_unittest.cc', 'browser/history/android/android_history_types_unittest.cc', diff --git a/chrome/test/gpu/gpu_feature_browsertest.cc b/chrome/test/gpu/gpu_feature_browsertest.cc index ce486c124d913d..be8a825ff1210f 100644 --- a/chrome/test/gpu/gpu_feature_browsertest.cc +++ b/chrome/test/gpu/gpu_feature_browsertest.cc @@ -8,7 +8,6 @@ #include "base/path_service.h" #include "base/test/trace_event_analyzer.h" #include "base/version.h" -#include "chrome/browser/gpu_blacklist.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" @@ -18,6 +17,7 @@ #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/gpu_data_manager.h" #include "content/public/common/content_switches.h" +#include "content/public/common/gpu_info.h" #include "content/test/gpu/gpu_test_config.h" #include "content/test/gpu/test_switches.h" #include "net/base/net_util.h" @@ -67,10 +67,9 @@ class GpuFeatureTest : public InProcessBrowserTest { } void SetupBlacklist(const std::string& json_blacklist) { - GpuBlacklist* blacklist = GpuBlacklist::GetInstance(); - ASSERT_TRUE(blacklist->LoadGpuBlacklist( - json_blacklist, GpuBlacklist::kAllOs)); - blacklist->UpdateGpuDataManager(); + content::GPUInfo gpu_info; + GpuDataManager::GetInstance()->Initialize( + "0", json_blacklist, gpu_info); } // If expected_reply is NULL, we don't check the reply content. diff --git a/chrome/browser/gpu_blacklist.cc b/content/browser/gpu/gpu_blacklist.cc similarity index 97% rename from chrome/browser/gpu_blacklist.cc rename to content/browser/gpu/gpu_blacklist.cc index 39f228e1a7d354..403a894f92d21c 100644 --- a/chrome/browser/gpu_blacklist.cc +++ b/content/browser/gpu/gpu_blacklist.cc @@ -2,7 +2,7 @@ // 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 "content/browser/gpu/gpu_blacklist.h" #include "base/command_line.h" #include "base/json/json_reader.h" @@ -12,13 +12,10 @@ #include "base/string_util.h" #include "base/sys_info.h" #include "base/version.h" -#include "chrome/browser/gpu_util.h" -#include "chrome/common/chrome_version_info.h" -#include "content/public/browser/gpu_data_manager.h" +#include "content/browser/gpu/gpu_util.h" #include "content/public/common/content_switches.h" #include "content/public/common/gpu_info.h" -using content::GpuDataManager; using content::GpuFeatureType; namespace { @@ -919,28 +916,19 @@ GpuFeatureType GpuBlacklist::GpuBlacklistEntry::GetGpuFeatureType() const { return feature_type_; } -// static -GpuBlacklist* GpuBlacklist::GetInstance() { - return Singleton::get(); -} - GpuBlacklist::GpuBlacklist() : max_entry_id_(0), contains_unknown_fields_(false) { - GpuDataManager::GetInstance()->AddObserver(this); } GpuBlacklist::~GpuBlacklist() { Clear(); - GpuDataManager::GetInstance()->RemoveObserver(this); } bool GpuBlacklist::LoadGpuBlacklist( const std::string& json_context, GpuBlacklist::OsFilter os_filter) { - chrome::VersionInfo chrome_version_info; - std::string chrome_version_string = - chrome_version_info.is_valid() ? chrome_version_info.Version() : "0"; - return LoadGpuBlacklist(chrome_version_string, json_context, os_filter); + const std::string browser_version_string = "0"; + return LoadGpuBlacklist(browser_version_string, json_context, os_filter); } bool GpuBlacklist::LoadGpuBlacklist( @@ -1050,14 +1038,6 @@ GpuFeatureType GpuBlacklist::DetermineGpuFeatureType( return static_cast(type); } -void GpuBlacklist::UpdateGpuDataManager() { - content::GpuFeatureType feature_type = DetermineGpuFeatureType( - GpuBlacklist::kOsAny, NULL, GpuDataManager::GetInstance()->GetGPUInfo()); - GpuDataManager::GetInstance()->SetPreliminaryBlacklistedFeatures( - feature_type); - gpu_util::UpdateStats(); -} - void GpuBlacklist::GetGpuFeatureTypeEntries( content::GpuFeatureType feature, std::vector& entry_ids, @@ -1163,10 +1143,6 @@ GpuBlacklist::IsEntrySupportedByCurrentBrowserVersion( return kSupported; } -void GpuBlacklist::OnGpuInfoUpdate() { - UpdateGpuDataManager(); -} - // static GpuBlacklist::NumericOp GpuBlacklist::StringToNumericOp( const std::string& op) { diff --git a/chrome/browser/gpu_blacklist.h b/content/browser/gpu/gpu_blacklist.h similarity index 93% rename from chrome/browser/gpu_blacklist.h rename to content/browser/gpu/gpu_blacklist.h index c4c72c7d859731..61801c3ef1c41e 100644 --- a/chrome/browser/gpu_blacklist.h +++ b/content/browser/gpu/gpu_blacklist.h @@ -2,8 +2,8 @@ // 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_ +#ifndef CONTENT_BROWSER_GPU_GPU_BLACKLIST_H_ +#define CONTENT_BROWSER_GPU_GPU_BLACKLIST_H_ #include #include @@ -12,9 +12,9 @@ #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include "base/memory/singleton.h" #include "base/values.h" -#include "content/public/browser/gpu_data_manager_observer.h" +#include "build/build_config.h" +#include "content/common/content_export.h" #include "content/public/common/gpu_feature_type.h" class Version; @@ -23,7 +23,7 @@ namespace content { struct GPUInfo; } -class GpuBlacklist : public content::GpuDataManagerObserver { +class CONTENT_EXPORT GpuBlacklist { public: enum OsType { kOsLinux, @@ -41,14 +41,14 @@ class GpuBlacklist : public content::GpuDataManagerObserver { kAllOs }; - // Getter for the singleton. This will return NULL on failure. - static GpuBlacklist* GetInstance(); - + GpuBlacklist(); virtual ~GpuBlacklist(); // Loads blacklist information from a json file. // If failed, the current GpuBlacklist is un-touched. - bool LoadGpuBlacklist(const std::string& json_context, + bool LoadGpuBlacklist(const std::string& json_context, OsFilter os_filter); + bool LoadGpuBlacklist(const std::string& browser_version_string, + const std::string& json_context, OsFilter os_filter); // Collects system information and combines them with gpu_info and blacklist @@ -58,10 +58,6 @@ class GpuBlacklist : public content::GpuDataManagerObserver { content::GpuFeatureType DetermineGpuFeatureType( OsType os, Version* os_version, const content::GPUInfo& gpu_info); - // Helper function that calls DetermineGpuFeatureType and sets the updated - // features on GpuDataManager. - void UpdateGpuDataManager(); - // Collects the active entries that set the "feature" flag from the last // DetermineGpuFeatureType() call. This tells which entries are responsible // for raising a certain flag, i.e, for blacklisting a certain feature. @@ -95,7 +91,6 @@ class GpuBlacklist : public content::GpuDataManagerObserver { private: friend class GpuBlacklistTest; - friend struct DefaultSingletonTraits; FRIEND_TEST_ALL_PREFIXES(GpuBlacklistTest, ChromeVersionEntry); FRIEND_TEST_ALL_PREFIXES(GpuBlacklistTest, CurrentBlacklistValidation); FRIEND_TEST_ALL_PREFIXES(GpuBlacklistTest, UnknownField); @@ -366,12 +361,6 @@ class GpuBlacklist : public content::GpuDataManagerObserver { // Gets the current OS type. static OsType GetOsType(); - GpuBlacklist(); - - bool LoadGpuBlacklist(const std::string& browser_version_string, - const std::string& json_context, - OsFilter os_filter); - bool LoadGpuBlacklist(const base::DictionaryValue& parsed_json, OsFilter os_filter); @@ -383,11 +372,6 @@ class GpuBlacklist : public content::GpuDataManagerObserver { BrowserVersionSupport IsEntrySupportedByCurrentBrowserVersion( const base::DictionaryValue* value); - // GpuDataManager::Observer implementation. - virtual void OnGpuInfoUpdate() OVERRIDE; - virtual void OnVideoMemoryUsageStatsUpdate( - const content::GPUVideoMemoryUsageStats& video_memory) OVERRIDE {} - // Returns the number of entries. This is only for tests. size_t num_entries() const; @@ -413,4 +397,5 @@ class GpuBlacklist : public content::GpuDataManagerObserver { DISALLOW_COPY_AND_ASSIGN(GpuBlacklist); }; -#endif // CHROME_BROWSER_GPU_BLACKLIST_H_ +#endif // CONTENT_BROWSER_GPU_GPU_BLACKLIST_H_ + diff --git a/chrome/browser/gpu_blacklist_unittest.cc b/content/browser/gpu/gpu_blacklist_unittest.cc similarity index 99% rename from chrome/browser/gpu_blacklist_unittest.cc rename to content/browser/gpu/gpu_blacklist_unittest.cc index 403a81f16c7919..6e921b8c66cd53 100644 --- a/chrome/browser/gpu_blacklist_unittest.cc +++ b/content/browser/gpu/gpu_blacklist_unittest.cc @@ -10,8 +10,7 @@ #include "base/memory/scoped_ptr.h" #include "base/path_service.h" #include "base/version.h" -#include "chrome/browser/gpu_blacklist.h" -#include "content/public/browser/gpu_data_manager.h" +#include "content/browser/gpu/gpu_blacklist.h" #include "content/public/common/gpu_info.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/content/browser/gpu/gpu_data_manager_impl.cc b/content/browser/gpu/gpu_data_manager_impl.cc index 44dfe6a957a105..d8f0428776a349 100644 --- a/content/browser/gpu/gpu_data_manager_impl.cc +++ b/content/browser/gpu/gpu_data_manager_impl.cc @@ -13,6 +13,7 @@ #include "base/values.h" #include "base/version.h" #include "content/browser/gpu/gpu_process_host.h" +#include "content/browser/gpu/gpu_util.h" #include "content/common/gpu/gpu_messages.h" #include "content/gpu/gpu_info_collector.h" #include "content/public/browser/browser_thread.h" @@ -58,14 +59,39 @@ GpuDataManagerImpl::GpuDataManagerImpl() BlacklistCard(); } -void GpuDataManagerImpl::InitializeGpuInfo() { +void GpuDataManagerImpl::Initialize( + const std::string& browser_version_string, + const std::string& gpu_blacklist_json) { content::GPUInfo gpu_info; - if (!CommandLine::ForCurrentProcess()->HasSwitch( - switches::kSkipGpuDataLoading)) - gpu_info_collector::CollectPreliminaryGraphicsInfo(&gpu_info); - else - gpu_info.finalized = true; + gpu_info_collector::CollectPreliminaryGraphicsInfo(&gpu_info); + + Initialize(browser_version_string, gpu_blacklist_json, gpu_info); +} + +void GpuDataManagerImpl::Initialize( + const std::string& browser_version_string, + const std::string& gpu_blacklist_json, + const content::GPUInfo& gpu_info) { + { + // This function should only be called in testing. + // We need clean up the gpu_info_ for a clean initialization. + const content::GPUInfo empty_gpu_info; + base::AutoLock auto_lock(gpu_info_lock_); + gpu_info_ = empty_gpu_info; + } + + if (!gpu_blacklist_json.empty()) { + CHECK(!browser_version_string.empty()); + gpu_blacklist_.reset(new GpuBlacklist()); + bool succeed = gpu_blacklist_->LoadGpuBlacklist( + browser_version_string, + gpu_blacklist_json, + GpuBlacklist::kCurrentOsOnly); + CHECK(succeed); + } + UpdateGpuInfo(gpu_info); + UpdatePreliminaryBlacklistedFeatures(); } GpuDataManagerImpl::~GpuDataManagerImpl() { @@ -92,6 +118,13 @@ void GpuDataManagerImpl::UpdateGpuInfo(const content::GPUInfo& gpu_info) { content::GetContentClient()->SetGpuInfo(gpu_info); + if (gpu_blacklist_.get()) { + GpuFeatureType feature_type = gpu_blacklist_->DetermineGpuFeatureType( + GpuBlacklist::kOsAny, NULL, gpu_info); + gpu_util::UpdateStats(gpu_blacklist_.get(), feature_type); + UpdateBlacklistedFeatures(feature_type); + } + { base::AutoLock auto_lock(gpu_info_lock_); gpu_info_ = gpu_info; @@ -142,6 +175,12 @@ base::ListValue* GpuDataManagerImpl::GetLogMessages() const { return value; } +std::string GpuDataManagerImpl::GetBlacklistVersion() const { + if (gpu_blacklist_.get()) + return gpu_blacklist_->GetVersion(); + return "0"; +} + GpuFeatureType GpuDataManagerImpl::GetBlacklistedFeatures() const { if (software_rendering_) { GpuFeatureType flags; @@ -155,6 +194,13 @@ GpuFeatureType GpuDataManagerImpl::GetBlacklistedFeatures() const { return gpu_feature_type_; } +base::ListValue* GpuDataManagerImpl::GetBlacklistReasons() const { + ListValue* reasons = new ListValue(); + if (gpu_blacklist_.get()) + gpu_blacklist_->GetBlacklistReasons(reasons); + return reasons; +} + bool GpuDataManagerImpl::GpuAccessAllowed() const { if (software_rendering_) return true; @@ -308,9 +354,7 @@ void GpuDataManagerImpl::AppendPluginCommandLine( #endif } -void GpuDataManagerImpl::SetPreliminaryBlacklistedFeatures( - GpuFeatureType feature_type) { - UpdateBlacklistedFeatures(feature_type); +void GpuDataManagerImpl::UpdatePreliminaryBlacklistedFeatures() { preliminary_gpu_feature_type_ = gpu_feature_type_; } diff --git a/content/browser/gpu/gpu_data_manager_impl.h b/content/browser/gpu/gpu_data_manager_impl.h index f7f0989c5bd2e2..64b25d2713a4f0 100644 --- a/content/browser/gpu/gpu_data_manager_impl.h +++ b/content/browser/gpu/gpu_data_manager_impl.h @@ -16,6 +16,7 @@ #include "base/observer_list_threadsafe.h" #include "base/synchronization/lock.h" #include "base/values.h" +#include "content/browser/gpu/gpu_blacklist.h" #include "content/public/browser/gpu_data_manager.h" #include "content/public/common/gpu_info.h" #include "content/public/common/gpu_memory_stats.h" @@ -29,10 +30,16 @@ class CONTENT_EXPORT GpuDataManagerImpl static GpuDataManagerImpl* GetInstance(); // GpuDataManager implementation. - virtual void InitializeGpuInfo() OVERRIDE; + virtual void Initialize( + const std::string& browser_version_string, + const std::string& gpu_blacklist_json) OVERRIDE; + virtual void Initialize( + const std::string& browser_version_string, + const std::string& gpu_blacklist_json, + const content::GPUInfo& gpu_info) OVERRIDE; virtual content::GpuFeatureType GetBlacklistedFeatures() const OVERRIDE; - virtual void SetPreliminaryBlacklistedFeatures( - content::GpuFeatureType features) OVERRIDE; + virtual base::ListValue* GetBlacklistReasons() const OVERRIDE; + virtual std::string GetBlacklistVersion() const OVERRIDE; virtual content::GPUInfo GetGPUInfo() const OVERRIDE; virtual bool GpuAccessAllowed() const OVERRIDE; virtual void RequestCompleteGpuInfoIfNeeded() OVERRIDE; @@ -47,7 +54,8 @@ class CONTENT_EXPORT GpuDataManagerImpl virtual void RemoveObserver( content::GpuDataManagerObserver* observer) OVERRIDE; - // Only update if the current GPUInfo is not finalized. + // Only update if the current GPUInfo is not finalized. If blacklist is + // loaded, run through blacklist and update blacklisted features. void UpdateGpuInfo(const content::GPUInfo& gpu_info); void UpdateVideoMemoryUsageStats( @@ -91,16 +99,21 @@ class CONTENT_EXPORT GpuDataManagerImpl GpuDataManagerImpl(); virtual ~GpuDataManagerImpl(); - // If flags hasn't been set and GPUInfo is available, run through blacklist - // and compute the flags. void UpdateBlacklistedFeatures(content::GpuFeatureType features); + // This should only be called once at initialization time, when preliminary + // gpu info is collected. + void UpdatePreliminaryBlacklistedFeatures(); + // Notify all observers whenever there is a GPU info update. void NotifyGpuInfoUpdate(); // Try to switch to software rendering, if possible and necessary. void EnableSoftwareRenderingIfNecessary(); + // Send UMA histograms about the disabled/enabled features. + void UpdateStats(); + bool complete_gpu_info_already_requested_; content::GpuFeatureType gpu_feature_type_; @@ -109,6 +122,8 @@ class CONTENT_EXPORT GpuDataManagerImpl content::GPUInfo gpu_info_; mutable base::Lock gpu_info_lock_; + scoped_ptr gpu_blacklist_; + const scoped_refptr observer_list_; ListValue log_messages_; diff --git a/content/browser/gpu/gpu_data_manager_impl_unittest.cc b/content/browser/gpu/gpu_data_manager_impl_unittest.cc index ea3d216788065d..29b37c3af8160e 100644 --- a/content/browser/gpu/gpu_data_manager_impl_unittest.cc +++ b/content/browser/gpu/gpu_data_manager_impl_unittest.cc @@ -69,8 +69,9 @@ TEST_F(GpuDataManagerImplTest, GpuSideBlacklisting) { EXPECT_EQ(0, manager->GetBlacklistedFeatures()); EXPECT_TRUE(manager->GpuAccessAllowed()); - manager->SetPreliminaryBlacklistedFeatures( + manager->UpdateBlacklistedFeatures( content::GPU_FEATURE_TYPE_WEBGL); + manager->UpdatePreliminaryBlacklistedFeatures(); EXPECT_TRUE(manager->GpuAccessAllowed()); EXPECT_EQ(content::GPU_FEATURE_TYPE_WEBGL, manager->GetBlacklistedFeatures()); diff --git a/content/browser/gpu/gpu_util.cc b/content/browser/gpu/gpu_util.cc new file mode 100644 index 00000000000000..267b2b4b78edbc --- /dev/null +++ b/content/browser/gpu/gpu_util.cc @@ -0,0 +1,223 @@ +// Copyright (c) 2012 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 "content/browser/gpu/gpu_util.h" + +#include + +#include "base/command_line.h" +#include "base/metrics/histogram.h" +#include "base/string_util.h" +#include "base/sys_info.h" +#include "base/version.h" +#include "content/browser/gpu/gpu_blacklist.h" +#include "content/public/common/content_switches.h" + +using content::GpuFeatureType; + +namespace { + +const char kGpuFeatureNameAccelerated2dCanvas[] = "accelerated_2d_canvas"; +const char kGpuFeatureNameAcceleratedCompositing[] = "accelerated_compositing"; +const char kGpuFeatureNameWebgl[] = "webgl"; +const char kGpuFeatureNameMultisampling[] = "multisampling"; +const char kGpuFeatureNameFlash3d[] = "flash_3d"; +const char kGpuFeatureNameFlashStage3d[] = "flash_stage3d"; +const char kGpuFeatureNameTextureSharing[] = "texture_sharing"; +const char kGpuFeatureNameAcceleratedVideoDecode[] = "accelerated_video_decode"; +const char kGpuFeatureNameAll[] = "all"; +const char kGpuFeatureNameUnknown[] = "unknown"; + +enum GpuFeatureStatus { + kGpuFeatureEnabled = 0, + kGpuFeatureBlacklisted = 1, + kGpuFeatureDisabled = 2, // disabled by user but not blacklisted + kGpuFeatureNumStatus +}; + +#if defined(OS_WIN) + +enum WinSubVersion { + kWinOthers = 0, + kWinXP, + kWinVista, + kWin7, + kNumWinSubVersions +}; + +int GetGpuBlacklistHistogramValueWin(GpuFeatureStatus status) { + static WinSubVersion sub_version = kNumWinSubVersions; + if (sub_version == kNumWinSubVersions) { + sub_version = kWinOthers; + std::string version_str = base::SysInfo::OperatingSystemVersion(); + size_t pos = version_str.find_first_not_of("0123456789."); + if (pos != std::string::npos) + version_str = version_str.substr(0, pos); + Version os_version(version_str); + if (os_version.IsValid() && os_version.components().size() >= 2) { + const std::vector& version_numbers = os_version.components(); + if (version_numbers[0] == 5) + sub_version = kWinXP; + else if (version_numbers[0] == 6 && version_numbers[1] == 0) + sub_version = kWinVista; + else if (version_numbers[0] == 6 && version_numbers[1] == 1) + sub_version = kWin7; + } + } + int entry_index = static_cast(sub_version) * kGpuFeatureNumStatus; + switch (status) { + case kGpuFeatureEnabled: + break; + case kGpuFeatureBlacklisted: + entry_index++; + break; + case kGpuFeatureDisabled: + entry_index += 2; + break; + } + return entry_index; +} +#endif // OS_WIN + +} // namespace + +namespace gpu_util { + +GpuFeatureType StringToGpuFeatureType(const std::string& feature_string) { + if (feature_string == kGpuFeatureNameAccelerated2dCanvas) + return content::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS; + else if (feature_string == kGpuFeatureNameAcceleratedCompositing) + return content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING; + else if (feature_string == kGpuFeatureNameWebgl) + return content::GPU_FEATURE_TYPE_WEBGL; + else if (feature_string == kGpuFeatureNameMultisampling) + return content::GPU_FEATURE_TYPE_MULTISAMPLING; + else if (feature_string == kGpuFeatureNameFlash3d) + return content::GPU_FEATURE_TYPE_FLASH3D; + else if (feature_string == kGpuFeatureNameFlashStage3d) + return content::GPU_FEATURE_TYPE_FLASH_STAGE3D; + else if (feature_string == kGpuFeatureNameTextureSharing) + return content::GPU_FEATURE_TYPE_TEXTURE_SHARING; + else if (feature_string == kGpuFeatureNameAcceleratedVideoDecode) + return content::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE; + else if (feature_string == kGpuFeatureNameAll) + return content::GPU_FEATURE_TYPE_ALL; + return content::GPU_FEATURE_TYPE_UNKNOWN; +} + +std::string GpuFeatureTypeToString(GpuFeatureType type) { + std::vector matches; + if (type == content::GPU_FEATURE_TYPE_ALL) { + matches.push_back(kGpuFeatureNameAll); + } else { + if (type & content::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS) + matches.push_back(kGpuFeatureNameAccelerated2dCanvas); + if (type & content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) + matches.push_back(kGpuFeatureNameAcceleratedCompositing); + if (type & content::GPU_FEATURE_TYPE_WEBGL) + matches.push_back(kGpuFeatureNameWebgl); + if (type & content::GPU_FEATURE_TYPE_MULTISAMPLING) + matches.push_back(kGpuFeatureNameMultisampling); + if (type & content::GPU_FEATURE_TYPE_FLASH3D) + matches.push_back(kGpuFeatureNameFlash3d); + if (type & content::GPU_FEATURE_TYPE_FLASH_STAGE3D) + matches.push_back(kGpuFeatureNameFlashStage3d); + if (type & content::GPU_FEATURE_TYPE_TEXTURE_SHARING) + matches.push_back(kGpuFeatureNameTextureSharing); + if (type & content::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) + matches.push_back(kGpuFeatureNameAcceleratedVideoDecode); + if (!matches.size()) + matches.push_back(kGpuFeatureNameUnknown); + } + return JoinString(matches, ','); +} + +void UpdateStats(const GpuBlacklist* blacklist, + uint32 blacklisted_features) { + uint32 max_entry_id = blacklist->max_entry_id(); + if (max_entry_id == 0) { + // GPU Blacklist was not loaded. No need to go further. + return; + } + + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + bool disabled = false; + if (blacklisted_features == 0) { + UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry", + 0, max_entry_id + 1); + } else { + std::vector flag_entries; + blacklist->GetGpuFeatureTypeEntries( + content::GPU_FEATURE_TYPE_ALL, flag_entries, disabled); + DCHECK_GT(flag_entries.size(), 0u); + for (size_t i = 0; i < flag_entries.size(); ++i) { + UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry", + flag_entries[i], max_entry_id + 1); + } + } + + // This counts how many users are affected by a disabled entry - this allows + // us to understand the impact of an entry before enable it. + std::vector flag_disabled_entries; + disabled = true; + blacklist->GetGpuFeatureTypeEntries( + content::GPU_FEATURE_TYPE_ALL, flag_disabled_entries, disabled); + for (size_t i = 0; i < flag_disabled_entries.size(); ++i) { + UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerDisabledEntry", + flag_disabled_entries[i], max_entry_id + 1); + } + + const content::GpuFeatureType kGpuFeatures[] = { + content::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS, + content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING, + content::GPU_FEATURE_TYPE_WEBGL + }; + const std::string kGpuBlacklistFeatureHistogramNames[] = { + "GPU.BlacklistFeatureTestResults.Accelerated2dCanvas", + "GPU.BlacklistFeatureTestResults.AcceleratedCompositing", + "GPU.BlacklistFeatureTestResults.Webgl" + }; + const bool kGpuFeatureUserFlags[] = { + command_line.HasSwitch(switches::kDisableAccelerated2dCanvas), + command_line.HasSwitch(switches::kDisableAcceleratedCompositing), +#if defined(OS_ANDROID) + !command_line.HasSwitch(switches::kEnableExperimentalWebGL) +#else + command_line.HasSwitch(switches::kDisableExperimentalWebGL) +#endif + }; +#if defined(OS_WIN) + const std::string kGpuBlacklistFeatureHistogramNamesWin[] = { + "GPU.BlacklistFeatureTestResultsWindows.Accelerated2dCanvas", + "GPU.BlacklistFeatureTestResultsWindows.AcceleratedCompositing", + "GPU.BlacklistFeatureTestResultsWindows.Webgl" + }; +#endif + const size_t kNumFeatures = + sizeof(kGpuFeatures) / sizeof(content::GpuFeatureType); + for (size_t i = 0; i < kNumFeatures; ++i) { + // We can't use UMA_HISTOGRAM_ENUMERATION here because the same name is + // expected if the macro is used within a loop. + GpuFeatureStatus value = kGpuFeatureEnabled; + if (blacklisted_features & kGpuFeatures[i]) + value = kGpuFeatureBlacklisted; + else if (kGpuFeatureUserFlags[i]) + value = kGpuFeatureDisabled; + base::Histogram* histogram_pointer = base::LinearHistogram::FactoryGet( + kGpuBlacklistFeatureHistogramNames[i], + 1, kGpuFeatureNumStatus, kGpuFeatureNumStatus + 1, + base::Histogram::kUmaTargetedHistogramFlag); + histogram_pointer->Add(value); +#if defined(OS_WIN) + histogram_pointer = base::LinearHistogram::FactoryGet( + kGpuBlacklistFeatureHistogramNamesWin[i], + 1, kNumWinSubVersions * kGpuFeatureNumStatus, + kNumWinSubVersions * kGpuFeatureNumStatus + 1, + base::Histogram::kUmaTargetedHistogramFlag); + histogram_pointer->Add(GetGpuBlacklistHistogramValueWin(value)); +#endif + } +} + +} // namespace gpu_util; diff --git a/content/browser/gpu/gpu_util.h b/content/browser/gpu/gpu_util.h new file mode 100644 index 00000000000000..7732dce54db4b6 --- /dev/null +++ b/content/browser/gpu/gpu_util.h @@ -0,0 +1,37 @@ +// Copyright (c) 2012 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 CONTENT_BROWSER_GPU_GPU_UTIL_H_ +#define CONTENT_BROWSER_GPU_GPU_UTIL_H_ + +#include + +#include "base/basictypes.h" +#include "build/build_config.h" +#include "content/common/content_export.h" +#include "content/public/common/gpu_feature_type.h" + +class GpuBlacklist; + +namespace gpu_util { + +// Maps string to GpuFeatureType; returns GPU_FEATURE_TYPE_UNKNOWN if an +// unknown name is input (case-sensitive). +CONTENT_EXPORT content::GpuFeatureType StringToGpuFeatureType( + const std::string& feature_string); + +// Gets a string version of a feature type for use in about:gpu. Will yield +// strings from StringToGpuFeatureType, e.g. +// GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS becomes "accelerated_2d_canvas" +CONTENT_EXPORT std::string GpuFeatureTypeToString( + content::GpuFeatureType feature); + +// Send UMA histograms about the enabled features. +CONTENT_EXPORT void UpdateStats( + const GpuBlacklist* blacklist, uint32 blacklisted_features); + +} // namespace gpu_util + +#endif // CONTENT_BROWSER_GPU_GPU_UTIL_H_ + diff --git a/chrome/browser/gpu_util_unittest.cc b/content/browser/gpu/gpu_util_unittest.cc similarity index 62% rename from chrome/browser/gpu_util_unittest.cc rename to content/browser/gpu/gpu_util_unittest.cc index affa5876d259c6..b92b5f81017bf2 100644 --- a/chrome/browser/gpu_util_unittest.cc +++ b/content/browser/gpu/gpu_util_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/gpu_util.h" +#include "content/browser/gpu/gpu_util.h" #include "testing/gtest/include/gtest/gtest.h" using content::GpuFeatureType; @@ -17,6 +17,14 @@ TEST(GpuUtilsTest, GpuFeatureTypFromString) { content::GPU_FEATURE_TYPE_WEBGL); EXPECT_EQ(gpu_util::StringToGpuFeatureType("multisampling"), content::GPU_FEATURE_TYPE_MULTISAMPLING); + EXPECT_EQ(gpu_util::StringToGpuFeatureType("flash_3d"), + content::GPU_FEATURE_TYPE_FLASH3D); + EXPECT_EQ(gpu_util::StringToGpuFeatureType("flash_stage3d"), + content::GPU_FEATURE_TYPE_FLASH_STAGE3D); + EXPECT_EQ(gpu_util::StringToGpuFeatureType("texture_sharing"), + content::GPU_FEATURE_TYPE_TEXTURE_SHARING); + EXPECT_EQ(gpu_util::StringToGpuFeatureType("accelerated_video_decode"), + content::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE); EXPECT_EQ(gpu_util::StringToGpuFeatureType("all"), content::GPU_FEATURE_TYPE_ALL); EXPECT_EQ(gpu_util::StringToGpuFeatureType("xxx"), @@ -41,6 +49,22 @@ TEST(GpuUtilsTest, GpuFeatureTypeToString) { gpu_util::GpuFeatureTypeToString( content::GPU_FEATURE_TYPE_MULTISAMPLING).c_str(), "multisampling"); + EXPECT_STREQ( + gpu_util::GpuFeatureTypeToString( + content::GPU_FEATURE_TYPE_FLASH3D).c_str(), + "flash_3d"); + EXPECT_STREQ( + gpu_util::GpuFeatureTypeToString( + content::GPU_FEATURE_TYPE_FLASH_STAGE3D).c_str(), + "flash_stage3d"); + EXPECT_STREQ( + gpu_util::GpuFeatureTypeToString( + content::GPU_FEATURE_TYPE_TEXTURE_SHARING).c_str(), + "texture_sharing"); + EXPECT_STREQ( + gpu_util::GpuFeatureTypeToString( + content::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE).c_str(), + "accelerated_video_decode"); EXPECT_STREQ( gpu_util::GpuFeatureTypeToString( content::GPU_FEATURE_TYPE_ALL).c_str(), @@ -54,11 +78,10 @@ TEST(GpuUtilsTest, GpuFeatureTypeToString) { content::GPU_FEATURE_TYPE_WEBGL | content::GPU_FEATURE_TYPE_MULTISAMPLING)).c_str(), "webgl,multisampling"); - - std::string tmp; - tmp = gpu_util::GpuFeatureTypeToString( - static_cast( - content::GPU_FEATURE_TYPE_WEBGL | - content::GPU_FEATURE_TYPE_ALL)); - EXPECT_STREQ(tmp.c_str(), "all"); + EXPECT_STREQ( + gpu_util::GpuFeatureTypeToString( + static_cast( + content::GPU_FEATURE_TYPE_WEBGL | + content::GPU_FEATURE_TYPE_ALL)).c_str(), + "all"); } diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 7f0886f90eee80..4f632efe231594 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -422,6 +422,8 @@ 'browser/geolocation/win7_location_provider_win.h', 'browser/gpu/browser_gpu_channel_host_factory.cc', 'browser/gpu/browser_gpu_channel_host_factory.h', + 'browser/gpu/gpu_blacklist.cc', + 'browser/gpu/gpu_blacklist.h', 'browser/gpu/gpu_data_manager_impl.cc', 'browser/gpu/gpu_data_manager_impl.h', 'browser/gpu/gpu_process_host.cc', @@ -430,6 +432,8 @@ 'browser/gpu/gpu_process_host_ui_shim.h', 'browser/gpu/gpu_surface_tracker.cc', 'browser/gpu/gpu_surface_tracker.h', + 'browser/gpu/gpu_util.cc', + 'browser/gpu/gpu_util.h', 'browser/histogram_controller.cc', 'browser/histogram_controller.h', 'browser/histogram_internals_request_job.cc', diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 2e37df13261619..a37c02a3c549a8 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -274,7 +274,9 @@ 'browser/geolocation/wifi_data_provider_unittest_win.cc', 'browser/geolocation/win7_location_api_unittest_win.cc', 'browser/geolocation/win7_location_provider_unittest_win.cc', + 'browser/gpu/gpu_blacklist_unittest.cc', 'browser/gpu/gpu_data_manager_impl_unittest.cc', + 'browser/gpu/gpu_util_unittest.cc', 'browser/host_zoom_map_impl_unittest.cc', 'browser/hyphenator/hyphenator_message_filter_unittest.cc', 'browser/in_process_webkit/indexed_db_quota_client_unittest.cc', diff --git a/content/public/browser/gpu_data_manager.h b/content/public/browser/gpu_data_manager.h index d1dfafc3351f64..0a8487005fc5fa 100644 --- a/content/public/browser/gpu_data_manager.h +++ b/content/public/browser/gpu_data_manager.h @@ -27,17 +27,26 @@ class GpuDataManager { // Getter for the singleton. CONTENT_EXPORT static GpuDataManager* GetInstance(); - // This collects preliminary GPU info; it should only be called at - // browser startup time in UI thread before the IO restriction is turned - // on. - virtual void InitializeGpuInfo() = 0; + // This collects preliminary GPU info, load GpuBlacklist, and compute the + // preliminary blacklisted features; it should only be called at browser + // startup time in UI thread before the IO restriction is turned on. + virtual void Initialize(const std::string& browser_version_string, + const std::string& gpu_blacklist_json) = 0; + // The same as above, except that the GPUInfo is provided. + // For testing only. + virtual void Initialize(const std::string& browser_version_string, + const std::string& gpu_blacklist_json, + const content::GPUInfo& gpu_info) = 0; + + virtual std::string GetBlacklistVersion() const = 0; - // Can be called on any thread. virtual GpuFeatureType GetBlacklistedFeatures() const = 0; - // Sets the blacklisted feature flags due to preliminary GPU info. - virtual void SetPreliminaryBlacklistedFeatures( - GpuFeatureType feature_type) = 0; + // Returns the reasons for the latest run of blacklisting decisions. + // For the structure of returned value, see documentation for + // GpuBlacklist::GetBlacklistedReasons(). + // Caller is responsible to release the returned value. + virtual base::ListValue* GetBlacklistReasons() const = 0; virtual GPUInfo GetGPUInfo() const = 0;