summaryrefslogtreecommitdiffstats
path: root/content/browser/gpu
diff options
context:
space:
mode:
authorzmo@chromium.org <zmo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-10 20:42:52 +0000
committerzmo@chromium.org <zmo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-10 20:42:52 +0000
commitd7867f32ddeb1118191871e2a7cec81bfd9766ad (patch)
treee57b0a618cb050c1c856bb5fde08d1a6ae699be4 /content/browser/gpu
parent0078195f0a0ca601ad4d5d5d5090ffc5128d1396 (diff)
downloadchromium_src-d7867f32ddeb1118191871e2a7cec81bfd9766ad.zip
chromium_src-d7867f32ddeb1118191871e2a7cec81bfd9766ad.tar.gz
chromium_src-d7867f32ddeb1118191871e2a7cec81bfd9766ad.tar.bz2
Refactor GpuDataManagerImpl to make it thread-safe, now and forever.
The original impl of GpuDataManagerImpl is thread-safe, but gradurally it regressed. In order to make sure this class is thread-safe in the future, we move all code to GpuDataManagerImplPrivate, and make GpuDataManagerImpl a simple wrapper around GpuDataManagerImplPrivate's public functions, where each function call is guarded by lock, thus thread-safe. BUG=232556 TEST=asan bots no longer crashes as described in crbug.com/232556 R=joi@chromium.org, kbr@chromium.org, piman@chromium.org Review URL: https://codereview.chromium.org/14794006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@199530 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/gpu')
-rw-r--r--content/browser/gpu/gpu_data_manager_impl.cc920
-rw-r--r--content/browser/gpu/gpu_data_manager_impl.h164
-rw-r--r--content/browser/gpu/gpu_data_manager_impl_private.cc928
-rw-r--r--content/browser/gpu/gpu_data_manager_impl_private.h239
-rw-r--r--content/browser/gpu/gpu_data_manager_impl_private_unittest.cc619
-rw-r--r--content/browser/gpu/gpu_data_manager_impl_unittest.cc656
-rw-r--r--content/browser/gpu/gpu_internals_ui.cc19
7 files changed, 1931 insertions, 1614 deletions
diff --git a/content/browser/gpu/gpu_data_manager_impl.cc b/content/browser/gpu/gpu_data_manager_impl.cc
index 7b29ea4..f53094e 100644
--- a/content/browser/gpu/gpu_data_manager_impl.cc
+++ b/content/browser/gpu/gpu_data_manager_impl.cc
@@ -1,106 +1,12 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2013 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_data_manager_impl.h"
-#if defined(OS_MACOSX)
-#include <ApplicationServices/ApplicationServices.h>
-#endif // OS_MACOSX
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/file_util.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/histogram.h"
-#include "base/stringprintf.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "base/sys_info.h"
-#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"
-#include "content/public/browser/gpu_data_manager_observer.h"
-#include "content/public/common/content_client.h"
-#include "content/public/common/content_constants.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/gpu_feature_type.h"
-#include "gpu/command_buffer/service/gpu_switches.h"
-#include "grit/content_resources.h"
-#include "ui/base/ui_base_switches.h"
-#include "ui/gl/gl_implementation.h"
-#include "ui/gl/gl_switches.h"
-#include "ui/gl/gpu_switching_manager.h"
-#include "webkit/glue/webpreferences.h"
-#include "webkit/plugins/plugin_switches.h"
-
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
+#include "content/browser/gpu/gpu_data_manager_impl_private.h"
namespace content {
-namespace {
-
-// Strip out the non-digital info; if after that, we get an empty string,
-// return "0".
-std::string ProcessVersionString(const std::string& raw_string) {
- const std::string valid_set = "0123456789.";
- size_t start_pos = raw_string.find_first_of(valid_set);
- if (start_pos == std::string::npos)
- return "0";
- size_t end_pos = raw_string.find_first_not_of(raw_string, start_pos);
- std::string version_string = raw_string.substr(
- start_pos, end_pos - start_pos);
- if (version_string.empty())
- return "0";
- return version_string;
-}
-
-// Combine the integers into a string, seperated by ','.
-std::string IntSetToString(const std::set<int>& list) {
- std::string rt;
- for (std::set<int>::const_iterator it = list.begin();
- it != list.end(); ++it) {
- if (!rt.empty())
- rt += ",";
- rt += base::IntToString(*it);
- }
- return rt;
-}
-
-#if defined(OS_MACOSX)
-void DisplayReconfigCallback(CGDirectDisplayID display,
- CGDisplayChangeSummaryFlags flags,
- void* gpu_data_manager) {
- if (flags & kCGDisplayAddFlag) {
- GpuDataManagerImpl* manager =
- reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager);
- DCHECK(manager);
- manager->HandleGpuSwitch();
- }
-}
-#endif // OS_MACOSX
-
-// Block all domains' use of 3D APIs for this many milliseconds if
-// approaching a threshold where system stability might be compromised.
-const int64 kBlockAllDomainsMs = 10000;
-const int kNumResetsWithinDuration = 1;
-
-// Enums for UMA histograms.
-enum BlockStatusHistogram {
- BLOCK_STATUS_NOT_BLOCKED,
- BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
- BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
- BLOCK_STATUS_MAX
-};
-
-} // namespace anonymous
// static
GpuDataManager* GpuDataManager::GetInstance() {
@@ -113,839 +19,223 @@ GpuDataManagerImpl* GpuDataManagerImpl::GetInstance() {
}
void GpuDataManagerImpl::InitializeForTesting(
- const std::string& gpu_blacklist_json,
- const GPUInfo& gpu_info) {
- // This function is for testing only, so disable histograms.
- update_histograms_ = false;
-
- InitializeImpl(gpu_blacklist_json, std::string(), std::string(), gpu_info);
+ const std::string& gpu_blacklist_json, const GPUInfo& gpu_info) {
+ base::AutoLock auto_lock(lock_);
+ private_->InitializeForTesting(gpu_blacklist_json, gpu_info);
}
bool GpuDataManagerImpl::IsFeatureBlacklisted(int feature) const {
- if (use_swiftshader_) {
- // Skia's software rendering is probably more efficient than going through
- // software emulation of the GPU, so use that.
- if (feature == GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)
- return true;
- return false;
- }
-
- return (blacklisted_features_.count(feature) == 1);
-}
-
-size_t GpuDataManagerImpl::GetBlacklistedFeatureCount() const {
- if (use_swiftshader_)
- return 1;
- return blacklisted_features_.size();
-}
-
-void GpuDataManagerImpl::AddGpuSwitchCallback(
- const GpuSwitchCallback& callback) {
- gpu_switch_callbacks_.push_back(callback);
-}
-
-void GpuDataManagerImpl::RemoveGpuSwitchCallback(
- const GpuSwitchCallback& callback) {
- for (size_t i = 0; i < gpu_switch_callbacks_.size(); i++) {
- if (gpu_switch_callbacks_[i].Equals(callback)) {
- gpu_switch_callbacks_.erase(gpu_switch_callbacks_.begin() + i);
- return;
- }
- }
+ base::AutoLock auto_lock(lock_);
+ return private_->IsFeatureBlacklisted(feature);
}
GPUInfo GpuDataManagerImpl::GetGPUInfo() const {
- GPUInfo gpu_info;
- {
- base::AutoLock auto_lock(gpu_info_lock_);
- gpu_info = gpu_info_;
- }
- return gpu_info;
+ base::AutoLock auto_lock(lock_);
+ return private_->GetGPUInfo();
}
void GpuDataManagerImpl::GetGpuProcessHandles(
const GetGpuProcessHandlesCallback& callback) const {
- GpuProcessHost::GetProcessHandles(callback);
+ base::AutoLock auto_lock(lock_);
+ private_->GetGpuProcessHandles(callback);
}
bool GpuDataManagerImpl::GpuAccessAllowed(std::string* reason) const {
- if (use_swiftshader_)
- return true;
-
- if (!gpu_info_.gpu_accessible) {
- if (reason) {
- *reason = "GPU process launch failed.";
- }
- return false;
- }
-
- if (card_blacklisted_) {
- if (reason) {
- *reason = "GPU access is disabled ";
- CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kDisableGpu))
- *reason += "through commandline switch --disable-gpu.";
- else
- *reason += "in chrome://settings.";
- }
- return false;
- }
-
- // We only need to block GPU process if more features are disallowed other
- // than those in the preliminary gpu feature flags because the latter work
- // through renderer commandline switches.
- std::set<int> features = preliminary_blacklisted_features_;
- MergeFeatureSets(&features, blacklisted_features_);
- if (features.size() > preliminary_blacklisted_features_.size()) {
- if (reason) {
- *reason = "Features are disabled upon full but not preliminary GPU info.";
- }
- return false;
- }
-
- if (blacklisted_features_.size() == NUMBER_OF_GPU_FEATURE_TYPES) {
- // On Linux, we use cached GL strings to make blacklist decsions at browser
- // startup time. We need to launch the GPU process to validate these
- // strings even if all features are blacklisted. If all GPU features are
- // disabled, the GPU process will only initialize GL bindings, create a GL
- // context, and collect full GPU info.
-#if !defined(OS_LINUX)
- if (reason) {
- *reason = "All GPU features are blacklisted.";
- }
- return false;
-#endif
- }
-
- return true;
+ base::AutoLock auto_lock(lock_);
+ return private_->GpuAccessAllowed(reason);
}
void GpuDataManagerImpl::RequestCompleteGpuInfoIfNeeded() {
- if (complete_gpu_info_already_requested_ || gpu_info_.finalized)
- return;
- complete_gpu_info_already_requested_ = true;
-
- GpuProcessHost::SendOnIO(
-#if defined(OS_WIN)
- GpuProcessHost::GPU_PROCESS_KIND_UNSANDBOXED,
-#else
- GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
-#endif
- CAUSE_FOR_GPU_LAUNCH_GPUDATAMANAGER_REQUESTCOMPLETEGPUINFOIFNEEDED,
- new GpuMsg_CollectGraphicsInfo());
+ base::AutoLock auto_lock(lock_);
+ private_->RequestCompleteGpuInfoIfNeeded();
}
bool GpuDataManagerImpl::IsCompleteGpuInfoAvailable() const {
- return gpu_info_.finalized;
+ base::AutoLock auto_lock(lock_);
+ return private_->IsCompleteGpuInfoAvailable();
}
void GpuDataManagerImpl::RequestVideoMemoryUsageStatsUpdate() const {
- GpuProcessHost::SendOnIO(
- GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
- CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
- new GpuMsg_GetVideoMemoryUsageStats());
+ base::AutoLock auto_lock(lock_);
+ private_->RequestVideoMemoryUsageStatsUpdate();
}
bool GpuDataManagerImpl::ShouldUseSwiftShader() const {
- return use_swiftshader_;
+ base::AutoLock auto_lock(lock_);
+ return private_->ShouldUseSwiftShader();
}
-void GpuDataManagerImpl::RegisterSwiftShaderPath(const base::FilePath& path) {
- swiftshader_path_ = path;
- EnableSwiftShaderIfNecessary();
+void GpuDataManagerImpl::RegisterSwiftShaderPath(
+ const base::FilePath& path) {
+ base::AutoLock auto_lock(lock_);
+ private_->RegisterSwiftShaderPath(path);
}
-void GpuDataManagerImpl::AddObserver(GpuDataManagerObserver* observer) {
- observer_list_->AddObserver(observer);
+void GpuDataManagerImpl::AddObserver(
+ GpuDataManagerObserver* observer) {
+ base::AutoLock auto_lock(lock_);
+ private_->AddObserver(observer);
}
-void GpuDataManagerImpl::RemoveObserver(GpuDataManagerObserver* observer) {
- observer_list_->RemoveObserver(observer);
+void GpuDataManagerImpl::RemoveObserver(
+ GpuDataManagerObserver* observer) {
+ base::AutoLock auto_lock(lock_);
+ private_->RemoveObserver(observer);
}
void GpuDataManagerImpl::UnblockDomainFrom3DAPIs(const GURL& url) {
- // This method must do two things:
- //
- // 1. If the specific domain is blocked, then unblock it.
- //
- // 2. Reset our notion of how many GPU resets have occurred recently.
- // This is necessary even if the specific domain was blocked.
- // Otherwise, if we call Are3DAPIsBlocked with the same domain right
- // after unblocking it, it will probably still be blocked because of
- // the recent GPU reset caused by that domain.
- //
- // These policies could be refined, but at a certain point the behavior
- // will become difficult to explain.
- std::string domain = GetDomainFromURL(url);
-
- base::AutoLock auto_lock(gpu_info_lock_);
- blocked_domains_.erase(domain);
- timestamps_of_gpu_resets_.clear();
+ base::AutoLock auto_lock(lock_);
+ private_->UnblockDomainFrom3DAPIs(url);
}
void GpuDataManagerImpl::DisableGpuWatchdog() {
- GpuProcessHost::SendOnIO(
- GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
- CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
- new GpuMsg_DisableWatchdog);
+ base::AutoLock auto_lock(lock_);
+ private_->DisableGpuWatchdog();
}
void GpuDataManagerImpl::SetGLStrings(const std::string& gl_vendor,
const std::string& gl_renderer,
const std::string& gl_version) {
- if (gl_vendor.empty() && gl_renderer.empty() && gl_version.empty())
- return;
-
- GPUInfo gpu_info;
- {
- base::AutoLock auto_lock(gpu_info_lock_);
- // If GPUInfo already got GL strings, do nothing. This is for the rare
- // situation where GPU process collected GL strings before this call.
- if (!gpu_info_.gl_vendor.empty() ||
- !gpu_info_.gl_renderer.empty() ||
- !gpu_info_.gl_version_string.empty())
- return;
- gpu_info = gpu_info_;
- }
-
- gpu_info.gl_vendor = gl_vendor;
- gpu_info.gl_renderer = gl_renderer;
- gpu_info.gl_version_string = gl_version;
-
- gpu_info_collector::CollectDriverInfoGL(&gpu_info);
-
- UpdateGpuInfo(gpu_info);
- UpdateGpuSwitchingManager(gpu_info);
- UpdatePreliminaryBlacklistedFeatures();
+ base::AutoLock auto_lock(lock_);
+ private_->SetGLStrings(gl_vendor, gl_renderer, gl_version);
}
void GpuDataManagerImpl::GetGLStrings(std::string* gl_vendor,
std::string* gl_renderer,
std::string* gl_version) {
- DCHECK(gl_vendor && gl_renderer && gl_version);
-
- base::AutoLock auto_lock(gpu_info_lock_);
- *gl_vendor = gpu_info_.gl_vendor;
- *gl_renderer = gpu_info_.gl_renderer;
- *gl_version = gpu_info_.gl_version_string;
+ base::AutoLock auto_lock(lock_);
+ private_->GetGLStrings(gl_vendor, gl_renderer, gl_version);
}
+void GpuDataManagerImpl::DisableHardwareAcceleration() {
+ base::AutoLock auto_lock(lock_);
+ private_->DisableHardwareAcceleration();
+}
void GpuDataManagerImpl::Initialize() {
- TRACE_EVENT0("startup", "GpuDataManagerImpl::Initialize");
- CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kSkipGpuDataLoading))
- return;
-
- GPUInfo gpu_info;
- {
- TRACE_EVENT0("startup",
- "GpuDataManagerImpl::Initialize:CollectBasicGraphicsInfo");
- gpu_info_collector::CollectBasicGraphicsInfo(&gpu_info);
- }
-#if defined(ARCH_CPU_X86_FAMILY)
- if (!gpu_info.gpu.vendor_id || !gpu_info.gpu.device_id)
- gpu_info.finalized = true;
-#endif
-
- std::string gpu_blacklist_string;
- std::string gpu_switching_list_string;
- std::string gpu_driver_bug_list_string;
- if (!command_line->HasSwitch(switches::kIgnoreGpuBlacklist)) {
- const base::StringPiece gpu_blacklist_json =
- GetContentClient()->GetDataResource(
- IDR_GPU_BLACKLIST, ui::SCALE_FACTOR_NONE);
- gpu_blacklist_string = gpu_blacklist_json.as_string();
- const base::StringPiece gpu_switching_list_json =
- GetContentClient()->GetDataResource(
- IDR_GPU_SWITCHING_LIST, ui::SCALE_FACTOR_NONE);
- gpu_switching_list_string = gpu_switching_list_json.as_string();
- }
- if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
- const base::StringPiece gpu_driver_bug_list_json =
- GetContentClient()->GetDataResource(
- IDR_GPU_DRIVER_BUG_LIST, ui::SCALE_FACTOR_NONE);
- gpu_driver_bug_list_string = gpu_driver_bug_list_json.as_string();
- }
- InitializeImpl(gpu_blacklist_string,
- gpu_switching_list_string,
- gpu_driver_bug_list_string,
- gpu_info);
- // We pass down the list to GPU command buffer through commandline
- // switches at GPU process launch. However, in situations where we don't
- // have a GPU process, we append the browser process commandline.
- if (command_line->HasSwitch(switches::kSingleProcess) ||
- command_line->HasSwitch(switches::kInProcessGPU)) {
- if (!gpu_driver_bugs_.empty()) {
- command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
- IntSetToString(gpu_driver_bugs_));
- }
- }
+ base::AutoLock auto_lock(lock_);
+ private_->Initialize();
}
void GpuDataManagerImpl::UpdateGpuInfo(const GPUInfo& gpu_info) {
- // No further update of gpu_info if falling back to SwiftShader.
- if (use_swiftshader_)
- return;
-
- GPUInfo my_gpu_info;
- {
- base::AutoLock auto_lock(gpu_info_lock_);
- gpu_info_collector::MergeGPUInfo(&gpu_info_, gpu_info);
- complete_gpu_info_already_requested_ =
- complete_gpu_info_already_requested_ || gpu_info_.finalized;
- my_gpu_info = gpu_info_;
- }
-
- GetContentClient()->SetGpuInfo(my_gpu_info);
-
- if (gpu_blacklist_) {
- std::set<int> features = gpu_blacklist_->MakeDecision(
- GpuControlList::kOsAny, std::string(), my_gpu_info);
- if (update_histograms_)
- UpdateStats(gpu_blacklist_.get(), features);
-
- UpdateBlacklistedFeatures(features);
- }
- if (gpu_switching_list_) {
- std::set<int> option = gpu_switching_list_->MakeDecision(
- GpuControlList::kOsAny, std::string(), my_gpu_info);
- if (option.size() == 1) {
- // Blacklist decision should not overwrite commandline switch from users.
- CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (!command_line->HasSwitch(switches::kGpuSwitching))
- gpu_switching_ = static_cast<GpuSwitchingOption>(*(option.begin()));
- }
- }
- if (gpu_driver_bug_list_)
- gpu_driver_bugs_ = gpu_driver_bug_list_->MakeDecision(
- GpuControlList::kOsAny, std::string(), my_gpu_info);
-
- // We have to update GpuFeatureType before notify all the observers.
- NotifyGpuInfoUpdate();
+ base::AutoLock auto_lock(lock_);
+ private_->UpdateGpuInfo(gpu_info);
}
void GpuDataManagerImpl::UpdateVideoMemoryUsageStats(
const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
- observer_list_->Notify(&GpuDataManagerObserver::OnVideoMemoryUsageStatsUpdate,
- video_memory_usage_stats);
+ base::AutoLock auto_lock(lock_);
+ private_->UpdateVideoMemoryUsageStats(video_memory_usage_stats);
}
void GpuDataManagerImpl::AppendRendererCommandLine(
CommandLine* command_line) const {
- DCHECK(command_line);
-
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL)) {
-#if !defined(OS_ANDROID)
- if (!command_line->HasSwitch(switches::kDisableExperimentalWebGL))
- command_line->AppendSwitch(switches::kDisableExperimentalWebGL);
-#endif
- if (!command_line->HasSwitch(switches::kDisablePepper3d))
- command_line->AppendSwitch(switches::kDisablePepper3d);
- }
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_MULTISAMPLING) &&
- !command_line->HasSwitch(switches::kDisableGLMultisampling))
- command_line->AppendSwitch(switches::kDisableGLMultisampling);
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) &&
- !command_line->HasSwitch(switches::kDisableAcceleratedCompositing))
- command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS) &&
- !command_line->HasSwitch(switches::kDisableAccelerated2dCanvas))
- command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
- !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
- command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
- if (ShouldUseSwiftShader())
- command_line->AppendSwitch(switches::kDisableFlashFullscreen3d);
+ base::AutoLock auto_lock(lock_);
+ private_->AppendRendererCommandLine(command_line);
}
void GpuDataManagerImpl::AppendGpuCommandLine(
CommandLine* command_line) const {
- DCHECK(command_line);
-
- std::string use_gl =
- CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL);
- base::FilePath swiftshader_path =
- CommandLine::ForCurrentProcess()->GetSwitchValuePath(
- switches::kSwiftShaderPath);
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_MULTISAMPLING) &&
- !command_line->HasSwitch(switches::kDisableGLMultisampling))
- command_line->AppendSwitch(switches::kDisableGLMultisampling);
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_TEXTURE_SHARING))
- command_line->AppendSwitch(switches::kDisableImageTransportSurface);
-
- if (use_swiftshader_) {
- command_line->AppendSwitchASCII(switches::kUseGL, "swiftshader");
- if (swiftshader_path.empty())
- swiftshader_path = swiftshader_path_;
- } else if ((IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL) ||
- IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
- IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)) &&
- (use_gl == "any")) {
- command_line->AppendSwitchASCII(
- switches::kUseGL, gfx::kGLImplementationOSMesaName);
- } else if (!use_gl.empty()) {
- command_line->AppendSwitchASCII(switches::kUseGL, use_gl);
- }
- if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
- command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "true");
- switch (gpu_switching_) {
- case GPU_SWITCHING_OPTION_FORCE_DISCRETE:
- command_line->AppendSwitchASCII(switches::kGpuSwitching,
- switches::kGpuSwitchingOptionNameForceDiscrete);
- break;
- case GPU_SWITCHING_OPTION_FORCE_INTEGRATED:
- command_line->AppendSwitchASCII(switches::kGpuSwitching,
- switches::kGpuSwitchingOptionNameForceIntegrated);
- break;
- case GPU_SWITCHING_OPTION_AUTOMATIC:
- case GPU_SWITCHING_OPTION_UNKNOWN:
- break;
- }
- } else {
- command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "false");
- }
-
- if (!swiftshader_path.empty())
- command_line->AppendSwitchPath(switches::kSwiftShaderPath,
- swiftshader_path);
-
- if (!gpu_driver_bugs_.empty()) {
- command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
- IntSetToString(gpu_driver_bugs_));
- }
-
-#if defined(OS_WIN)
- // DisplayLink 7.1 and earlier can cause the GPU process to crash on startup.
- // http://crbug.com/177611
- // Thinkpad USB Port Replicator driver causes GPU process to crash when the
- // sandbox is enabled. http://crbug.com/181665.
- if ((gpu_info_.display_link_version.IsValid()
- && gpu_info_.display_link_version.IsOlderThan("7.2")) ||
- gpu_info_.lenovo_dcute) {
- command_line->AppendSwitch(switches::kReduceGpuSandbox);
- }
-#endif
-
- {
- base::AutoLock auto_lock(gpu_info_lock_);
- if (gpu_info_.optimus)
- command_line->AppendSwitch(switches::kReduceGpuSandbox);
- if (gpu_info_.amd_switchable) {
- // The image transport surface currently doesn't work with AMD Dynamic
- // Switchable graphics.
- command_line->AppendSwitch(switches::kReduceGpuSandbox);
- command_line->AppendSwitch(switches::kDisableImageTransportSurface);
- }
- // Pass GPU and driver information to GPU process. We try to avoid full GPU
- // info collection at GPU process startup, but we need gpu vendor_id,
- // device_id, driver_vendor, driver_version for deciding whether we need to
- // collect full info (on Linux) and for crash reporting purpose.
- command_line->AppendSwitchASCII(switches::kGpuVendorID,
- base::StringPrintf("0x%04x", gpu_info_.gpu.vendor_id));
- command_line->AppendSwitchASCII(switches::kGpuDeviceID,
- base::StringPrintf("0x%04x", gpu_info_.gpu.device_id));
- command_line->AppendSwitchASCII(switches::kGpuDriverVendor,
- gpu_info_.driver_vendor);
- command_line->AppendSwitchASCII(switches::kGpuDriverVersion,
- gpu_info_.driver_version);
- }
+ base::AutoLock auto_lock(lock_);
+ private_->AppendGpuCommandLine(command_line);
}
void GpuDataManagerImpl::AppendPluginCommandLine(
CommandLine* command_line) const {
- DCHECK(command_line);
-
-#if defined(OS_MACOSX)
- // TODO(jbauman): Add proper blacklist support for core animation plugins so
- // special-casing this video card won't be necessary. See
- // http://crbug.com/134015
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
- CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableAcceleratedCompositing)) {
- if (!command_line->HasSwitch(
- switches::kDisableCoreAnimationPlugins))
- command_line->AppendSwitch(
- switches::kDisableCoreAnimationPlugins);
- }
-#endif
+ base::AutoLock auto_lock(lock_);
+ private_->AppendPluginCommandLine(command_line);
}
-void GpuDataManagerImpl::UpdateRendererWebPrefs(WebPreferences* prefs) const {
- DCHECK(prefs);
-
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING))
- prefs->accelerated_compositing_enabled = false;
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL))
- prefs->experimental_webgl_enabled = false;
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_FLASH3D))
- prefs->flash_3d_enabled = false;
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_FLASH_STAGE3D)) {
- prefs->flash_stage3d_enabled = false;
- prefs->flash_stage3d_baseline_enabled = false;
- }
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE))
- prefs->flash_stage3d_baseline_enabled = false;
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS))
- prefs->accelerated_2d_canvas_enabled = false;
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_MULTISAMPLING))
- prefs->gl_multisampling_enabled = false;
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_3D_CSS)) {
- prefs->accelerated_compositing_for_3d_transforms_enabled = false;
- prefs->accelerated_compositing_for_animation_enabled = false;
- }
- if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_VIDEO))
- prefs->accelerated_compositing_for_video_enabled = false;
-
- // Accelerated video and animation are slower than regular when using
- // SwiftShader. 3D CSS may also be too slow to be worthwhile.
- if (ShouldUseSwiftShader()) {
- prefs->accelerated_compositing_for_video_enabled = false;
- prefs->accelerated_compositing_for_animation_enabled = false;
- prefs->accelerated_compositing_for_3d_transforms_enabled = false;
- prefs->accelerated_compositing_for_plugins_enabled = false;
- }
+void GpuDataManagerImpl::UpdateRendererWebPrefs(
+ WebPreferences* prefs) const {
+ base::AutoLock auto_lock(lock_);
+ private_->UpdateRendererWebPrefs(prefs);
}
GpuSwitchingOption GpuDataManagerImpl::GetGpuSwitchingOption() const {
- if (!ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus())
- return GPU_SWITCHING_OPTION_UNKNOWN;
- return gpu_switching_;
+ base::AutoLock auto_lock(lock_);
+ return private_->GetGpuSwitchingOption();
}
-void GpuDataManagerImpl::DisableHardwareAcceleration() {
- card_blacklisted_ = true;
-
- for (int i = 0; i < NUMBER_OF_GPU_FEATURE_TYPES; ++i)
- blacklisted_features_.insert(i);
+std::string GpuDataManagerImpl::GetBlacklistVersion() const {
+ base::AutoLock auto_lock(lock_);
+ return private_->GetBlacklistVersion();
+}
- EnableSwiftShaderIfNecessary();
- NotifyGpuInfoUpdate();
+base::ListValue* GpuDataManagerImpl::GetBlacklistReasons() const {
+ base::AutoLock auto_lock(lock_);
+ return private_->GetBlacklistReasons();
}
-std::string GpuDataManagerImpl::GetBlacklistVersion() const {
- if (gpu_blacklist_)
- return gpu_blacklist_->version();
- return "0";
+void GpuDataManagerImpl::AddLogMessage(int level,
+ const std::string& header,
+ const std::string& message) {
+ base::AutoLock auto_lock(lock_);
+ private_->AddLogMessage(level, header, message);
}
-base::ListValue* GpuDataManagerImpl::GetBlacklistReasons() const {
- ListValue* reasons = new ListValue();
- if (gpu_blacklist_)
- gpu_blacklist_->GetReasons(reasons);
- return reasons;
-}
-
-void GpuDataManagerImpl::AddLogMessage(
- int level, const std::string& header, const std::string& message) {
- base::AutoLock auto_lock(log_messages_lock_);
- DictionaryValue* dict = new DictionaryValue();
- dict->SetInteger("level", level);
- dict->SetString("header", header);
- dict->SetString("message", message);
- log_messages_.Append(dict);
-}
-
-void GpuDataManagerImpl::ProcessCrashed(base::TerminationStatus exit_code) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI,
- FROM_HERE,
- base::Bind(&GpuDataManagerImpl::ProcessCrashed,
- base::Unretained(this),
- exit_code));
- return;
- }
- observer_list_->Notify(&GpuDataManagerObserver::OnGpuProcessCrashed,
- exit_code);
+void GpuDataManagerImpl::ProcessCrashed(
+ base::TerminationStatus exit_code) {
+ base::AutoLock auto_lock(lock_);
+ private_->ProcessCrashed(exit_code);
}
base::ListValue* GpuDataManagerImpl::GetLogMessages() const {
- base::ListValue* value;
- {
- base::AutoLock auto_lock(log_messages_lock_);
- value = log_messages_.DeepCopy();
- }
- return value;
+ base::AutoLock auto_lock(lock_);
+ return private_->GetLogMessages();
}
void GpuDataManagerImpl::HandleGpuSwitch() {
- complete_gpu_info_already_requested_ = false;
- gpu_info_.finalized = false;
- for (size_t i = 0; i < gpu_switch_callbacks_.size(); ++i)
- gpu_switch_callbacks_[i].Run();
+ base::AutoLock auto_lock(lock_);
+ private_->HandleGpuSwitch();
}
#if defined(OS_WIN)
bool GpuDataManagerImpl::IsUsingAcceleratedSurface() const {
- if (base::win::GetVersion() < base::win::VERSION_VISTA)
- return false;
-
- if (gpu_info_.amd_switchable)
- return false;
- if (use_swiftshader_)
- return false;
- CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kDisableImageTransportSurface))
- return false;
- return !IsFeatureBlacklisted(GPU_FEATURE_TYPE_TEXTURE_SHARING);
+ base::AutoLock auto_lock(lock_);
+ return private_->IsUsingAcceleratedSurface();
}
#endif
void GpuDataManagerImpl::BlockDomainFrom3DAPIs(
const GURL& url, DomainGuilt guilt) {
- BlockDomainFrom3DAPIsAtTime(url, guilt, base::Time::Now());
+ base::AutoLock auto_lock(lock_);
+ private_->BlockDomainFrom3DAPIs(url, guilt);
}
bool GpuDataManagerImpl::Are3DAPIsBlocked(const GURL& url,
int render_process_id,
int render_view_id,
ThreeDAPIType requester) {
- bool blocked = Are3DAPIsBlockedAtTime(url, base::Time::Now()) !=
- GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
- if (blocked) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&GpuDataManagerImpl::Notify3DAPIBlocked,
- base::Unretained(this), url, render_process_id,
- render_view_id, requester));
- }
-
- return blocked;
+ base::AutoLock auto_lock(lock_);
+ return private_->Are3DAPIsBlocked(
+ url, render_process_id, render_view_id, requester);
}
void GpuDataManagerImpl::DisableDomainBlockingFor3DAPIsForTesting() {
- domain_blocking_enabled_ = false;
-}
-
-GpuDataManagerImpl::GpuDataManagerImpl()
- : complete_gpu_info_already_requested_(false),
- gpu_switching_(GPU_SWITCHING_OPTION_AUTOMATIC),
- observer_list_(new GpuDataManagerObserverList),
- use_swiftshader_(false),
- card_blacklisted_(false),
- update_histograms_(true),
- window_count_(0),
- domain_blocking_enabled_(true) {
- CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kDisableAcceleratedCompositing)) {
- command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
- command_line->AppendSwitch(switches::kDisableAcceleratedLayers);
- }
- if (command_line->HasSwitch(switches::kDisableGpu))
- DisableHardwareAcceleration();
- if (command_line->HasSwitch(switches::kGpuSwitching)) {
- std::string option_string = command_line->GetSwitchValueASCII(
- switches::kGpuSwitching);
- GpuSwitchingOption option = StringToGpuSwitchingOption(option_string);
- if (option != GPU_SWITCHING_OPTION_UNKNOWN)
- gpu_switching_ = option;
- }
-
-#if defined(OS_MACOSX)
- CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback, this);
-#endif // OS_MACOSX
+ base::AutoLock auto_lock(lock_);
+ private_->DisableDomainBlockingFor3DAPIsForTesting();
}
-GpuDataManagerImpl::~GpuDataManagerImpl() {
-#if defined(OS_MACOSX)
- CGDisplayRemoveReconfigurationCallback(DisplayReconfigCallback, this);
-#endif
-}
-
-void GpuDataManagerImpl::InitializeImpl(
- const std::string& gpu_blacklist_json,
- const std::string& gpu_switching_list_json,
- const std::string& gpu_driver_bug_list_json,
- const GPUInfo& gpu_info) {
- std::string browser_version_string = ProcessVersionString(
- GetContentClient()->GetProduct());
- CHECK(!browser_version_string.empty());
-
- if (!gpu_blacklist_json.empty()) {
- gpu_blacklist_.reset(GpuBlacklist::Create());
- gpu_blacklist_->LoadList(
- browser_version_string, gpu_blacklist_json,
- GpuControlList::kCurrentOsOnly);
- }
- if (!gpu_switching_list_json.empty()) {
- gpu_switching_list_.reset(GpuSwitchingList::Create());
- gpu_switching_list_->LoadList(
- browser_version_string, gpu_switching_list_json,
- GpuControlList::kCurrentOsOnly);
- }
- if (!gpu_driver_bug_list_json.empty()) {
- gpu_driver_bug_list_.reset(GpuDriverBugList::Create());
- gpu_driver_bug_list_->LoadList(
- browser_version_string, gpu_driver_bug_list_json,
- GpuControlList::kCurrentOsOnly);
- }
-
- {
- base::AutoLock auto_lock(gpu_info_lock_);
- gpu_info_ = gpu_info;
- }
- UpdateGpuInfo(gpu_info);
- UpdateGpuSwitchingManager(gpu_info);
- UpdatePreliminaryBlacklistedFeatures();
-}
-
-void GpuDataManagerImpl::UpdateBlacklistedFeatures(
- const std::set<int>& features) {
- CommandLine* command_line = CommandLine::ForCurrentProcess();
- blacklisted_features_ = features;
-
- // Force disable using the GPU for these features, even if they would
- // otherwise be allowed.
- if (card_blacklisted_ ||
- command_line->HasSwitch(switches::kBlacklistAcceleratedCompositing)) {
- blacklisted_features_.insert(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING);
- }
- if (card_blacklisted_ ||
- command_line->HasSwitch(switches::kBlacklistWebGL)) {
- blacklisted_features_.insert(GPU_FEATURE_TYPE_WEBGL);
- }
-
- EnableSwiftShaderIfNecessary();
-}
-
-void GpuDataManagerImpl::UpdatePreliminaryBlacklistedFeatures() {
- preliminary_blacklisted_features_ = blacklisted_features_;
-}
-
-void GpuDataManagerImpl::UpdateGpuSwitchingManager(const GPUInfo& gpu_info) {
- ui::GpuSwitchingManager::GetInstance()->SetGpuCount(
- gpu_info.secondary_gpus.size() + 1);
-
- if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
- switch (gpu_switching_) {
- case GPU_SWITCHING_OPTION_FORCE_DISCRETE:
- ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu();
- break;
- case GPU_SWITCHING_OPTION_FORCE_INTEGRATED:
- ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu();
- break;
- case GPU_SWITCHING_OPTION_AUTOMATIC:
- case GPU_SWITCHING_OPTION_UNKNOWN:
- break;
- }
- }
-}
-
-void GpuDataManagerImpl::NotifyGpuInfoUpdate() {
- observer_list_->Notify(&GpuDataManagerObserver::OnGpuInfoUpdate);
-}
-
-void GpuDataManagerImpl::EnableSwiftShaderIfNecessary() {
- if (!GpuAccessAllowed(NULL) ||
- blacklisted_features_.count(GPU_FEATURE_TYPE_WEBGL)) {
- if (!swiftshader_path_.empty() &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableSoftwareRasterizer))
- use_swiftshader_ = true;
- }
-}
-
-std::string GpuDataManagerImpl::GetDomainFromURL(const GURL& url) const {
- // For the moment, we just use the host, or its IP address, as the
- // entry in the set, rather than trying to figure out the top-level
- // domain. This does mean that a.foo.com and b.foo.com will be
- // treated independently in the blocking of a given domain, but it
- // would require a third-party library to reliably figure out the
- // top-level domain from a URL.
- if (!url.has_host()) {
- return std::string();
- }
-
- return url.host();
-}
-
-void GpuDataManagerImpl::BlockDomainFrom3DAPIsAtTime(
- const GURL& url, DomainGuilt guilt, base::Time at_time) {
- if (!domain_blocking_enabled_)
- return;
-
- std::string domain = GetDomainFromURL(url);
-
- base::AutoLock auto_lock(gpu_info_lock_);
- DomainBlockEntry& entry = blocked_domains_[domain];
- entry.last_guilt = guilt;
- timestamps_of_gpu_resets_.push_back(at_time);
-}
-
-GpuDataManagerImpl::DomainBlockStatus
-GpuDataManagerImpl::Are3DAPIsBlockedAtTime(
- const GURL& url, base::Time at_time) const {
- if (!domain_blocking_enabled_)
- return DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
-
- // Note: adjusting the policies in this code will almost certainly
- // require adjusting the associated unit tests.
- std::string domain = GetDomainFromURL(url);
-
- base::AutoLock auto_lock(gpu_info_lock_);
- {
- DomainBlockMap::const_iterator iter = blocked_domains_.find(domain);
- if (iter != blocked_domains_.end()) {
- // Err on the side of caution, and assume that if a particular
- // domain shows up in the block map, it's there for a good
- // reason and don't let its presence there automatically expire.
-
- UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
- BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
- BLOCK_STATUS_MAX);
-
- return DOMAIN_BLOCK_STATUS_BLOCKED;
- }
- }
-
- // Look at the timestamps of the recent GPU resets to see if there are
- // enough within the threshold which would cause us to blacklist all
- // domains. This doesn't need to be overly precise -- if time goes
- // backward due to a system clock adjustment, that's fine.
- //
- // TODO(kbr): make this pay attention to the TDR thresholds in the
- // Windows registry, but make sure it continues to be testable.
- std::list<base::Time>::iterator iter = timestamps_of_gpu_resets_.begin();
- int num_resets_within_timeframe = 0;
- while (iter != timestamps_of_gpu_resets_.end()) {
- base::Time time = *iter;
- base::TimeDelta delta_t = at_time - time;
-
- // If this entry has "expired", just remove it.
- if (delta_t.InMilliseconds() > kBlockAllDomainsMs) {
- iter = timestamps_of_gpu_resets_.erase(iter);
- continue;
- }
-
- ++num_resets_within_timeframe;
- ++iter;
- }
-
- if (num_resets_within_timeframe >= kNumResetsWithinDuration) {
- UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
- BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
- BLOCK_STATUS_MAX);
-
- return DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED;
- }
-
- UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
- BLOCK_STATUS_NOT_BLOCKED,
- BLOCK_STATUS_MAX);
-
- return DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
-}
-
-int64 GpuDataManagerImpl::GetBlockAllDomainsDurationInMs() const {
- return kBlockAllDomainsMs;
+size_t GpuDataManagerImpl::GetBlacklistedFeatureCount() const {
+ base::AutoLock auto_lock(lock_);
+ return private_->GetBlacklistedFeatureCount();
}
void GpuDataManagerImpl::Notify3DAPIBlocked(const GURL& url,
int render_process_id,
int render_view_id,
ThreeDAPIType requester) {
- observer_list_->Notify(&GpuDataManagerObserver::DidBlock3DAPIs,
- url, render_process_id, render_view_id, requester);
+ base::AutoLock auto_lock(lock_);
+ private_->Notify3DAPIBlocked(
+ url, render_process_id, render_view_id, requester);
+}
+
+GpuDataManagerImpl::GpuDataManagerImpl()
+ : private_(GpuDataManagerImplPrivate::Create(this)) {
+}
+
+GpuDataManagerImpl::~GpuDataManagerImpl() {
}
} // namespace content
diff --git a/content/browser/gpu/gpu_data_manager_impl.h b/content/browser/gpu/gpu_data_manager_impl.h
index 5fa8780..9e609b5 100644
--- a/content/browser/gpu/gpu_data_manager_impl.h
+++ b/content/browser/gpu/gpu_data_manager_impl.h
@@ -1,30 +1,21 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2013 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_DATA_MANAGER_IMPL_H_
#define CONTENT_BROWSER_GPU_GPU_DATA_MANAGER_IMPL_H_
-#include <list>
-#include <map>
-#include <set>
#include <string>
-#include <vector>
-#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#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/observer_list_threadsafe.h"
#include "base/process_util.h"
#include "base/synchronization/lock.h"
#include "base/time.h"
#include "base/values.h"
-#include "content/browser/gpu/gpu_blacklist.h"
-#include "content/browser/gpu/gpu_driver_bug_list.h"
-#include "content/browser/gpu/gpu_switching_list.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/common/gpu_info.h"
#include "content/public/common/gpu_memory_stats.h"
@@ -37,6 +28,8 @@ struct WebPreferences;
namespace content {
+class GpuDataManagerImplPrivate;
+
class CONTENT_EXPORT GpuDataManagerImpl
: public NON_EXPORTED_BASE(GpuDataManager) {
public:
@@ -163,133 +156,48 @@ class CONTENT_EXPORT GpuDataManagerImpl
// Disables domain blocking for 3D APIs. For use only in tests.
void DisableDomainBlockingFor3DAPIsForTesting();
+ void Notify3DAPIBlocked(const GURL& url,
+ int render_process_id,
+ int render_view_id,
+ ThreeDAPIType requester);
+
// Get number of features being blacklisted.
size_t GetBlacklistedFeatureCount() const;
- typedef base::Callback<void()> GpuSwitchCallback;
-
- // Add and remove gpu switch callback.
- void AddGpuSwitchCallback(const GpuSwitchCallback& callback);
- void RemoveGpuSwitchCallback(const GpuSwitchCallback& callback);
-
private:
- struct DomainBlockEntry {
- DomainGuilt last_guilt;
- };
-
- typedef std::map<std::string, DomainBlockEntry> DomainBlockMap;
-
- typedef ObserverListThreadSafe<GpuDataManagerObserver>
- GpuDataManagerObserverList;
-
- friend class GpuDataManagerImplTest;
+ friend class GpuDataManagerImplPrivate;
friend struct DefaultSingletonTraits<GpuDataManagerImpl>;
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest, GpuSideBlacklisting);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest, GpuSideExceptions);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest,
- DisableHardwareAcceleration);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest, SwiftShaderRendering);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest, SwiftShaderRendering2);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest, GpuInfoUpdate);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest,
- NoGpuInfoUpdateWithSwiftShader);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest,
- GPUVideoMemoryUsageStatsUpdate);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest,
- BlockAllDomainsFrom3DAPIs);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest,
- UnblockGuiltyDomainFrom3DAPIs);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest,
- UnblockDomainOfUnknownGuiltFrom3DAPIs);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest,
- UnblockOtherDomainFrom3DAPIs);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest,
- UnblockThisDomainFrom3DAPIs);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest, GpuDriverBugListSingle);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplTest, GpuDriverBugListMultiple);
+ // It's similar to AutoUnlock, but we want to make it a no-op
+ // if the owner GpuDataManagerImpl is null.
+ // This should only be used by GpuDataManagerImplPrivate where
+ // callbacks are called, during which re-entering
+ // GpuDataManagerImpl is possible.
+ class UnlockedSession {
+ public:
+ explicit UnlockedSession(GpuDataManagerImpl* owner)
+ : owner_(owner) {
+ if (owner_) {
+ owner_->lock_.AssertAcquired();
+ owner_->lock_.Release();
+ }
+ }
+
+ ~UnlockedSession() {
+ if (owner_)
+ owner_->lock_.Acquire();
+ }
+
+ private:
+ GpuDataManagerImpl* owner_;
+ DISALLOW_COPY_AND_ASSIGN(UnlockedSession);
+ };
GpuDataManagerImpl();
virtual ~GpuDataManagerImpl();
- void InitializeImpl(const std::string& gpu_blacklist_json,
- const std::string& gpu_switching_list_json,
- const std::string& gpu_driver_bug_list_json,
- const GPUInfo& gpu_info);
-
- void UpdateBlacklistedFeatures(const std::set<int>& features);
-
- // This should only be called once at initialization time, when preliminary
- // gpu info is collected.
- void UpdatePreliminaryBlacklistedFeatures();
-
- // Update the GPU switching status.
- // This should only be called once at initialization time.
- void UpdateGpuSwitchingManager(const GPUInfo& gpu_info);
-
- // Notify all observers whenever there is a GPU info update.
- void NotifyGpuInfoUpdate();
-
- // Try to switch to SwiftShader rendering, if possible and necessary.
- void EnableSwiftShaderIfNecessary();
-
- // Helper to extract the domain from a given URL.
- std::string GetDomainFromURL(const GURL& url) const;
-
- // Implementation functions for blocking of 3D graphics APIs, used
- // for unit testing.
- void BlockDomainFrom3DAPIsAtTime(
- const GURL& url, DomainGuilt guilt, base::Time at_time);
- DomainBlockStatus Are3DAPIsBlockedAtTime(
- const GURL& url, base::Time at_time) const;
- int64 GetBlockAllDomainsDurationInMs() const;
-
- void Notify3DAPIBlocked(const GURL& url,
- int render_process_id,
- int render_view_id,
- ThreeDAPIType requester);
-
- bool complete_gpu_info_already_requested_;
-
- std::set<int> blacklisted_features_;
- std::set<int> preliminary_blacklisted_features_;
-
- GpuSwitchingOption gpu_switching_;
-
- std::set<int> gpu_driver_bugs_;
-
- GPUInfo gpu_info_;
- mutable base::Lock gpu_info_lock_;
-
- scoped_ptr<GpuBlacklist> gpu_blacklist_;
- scoped_ptr<GpuSwitchingList> gpu_switching_list_;
- scoped_ptr<GpuDriverBugList> gpu_driver_bug_list_;
-
- const scoped_refptr<GpuDataManagerObserverList> observer_list_;
-
- ListValue log_messages_;
- mutable base::Lock log_messages_lock_;
-
- bool use_swiftshader_;
-
- base::FilePath swiftshader_path_;
-
- // Current card force-blacklisted due to GPU crashes, or disabled through
- // the --disable-gpu commandline switch.
- bool card_blacklisted_;
-
- // We disable histogram stuff in testing, especially in unit tests because
- // they cause random failures.
- bool update_histograms_;
-
- // Number of currently open windows, to be used in gpu memory allocation.
- int window_count_;
-
- DomainBlockMap blocked_domains_;
- mutable std::list<base::Time> timestamps_of_gpu_resets_;
- bool domain_blocking_enabled_;
-
- std::vector<GpuSwitchCallback> gpu_switch_callbacks_;
+ mutable base::Lock lock_;
+ scoped_ptr<GpuDataManagerImplPrivate> private_;
DISALLOW_COPY_AND_ASSIGN(GpuDataManagerImpl);
};
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
new file mode 100644
index 0000000..74fff17
--- /dev/null
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -0,0 +1,928 @@
+// Copyright (c) 2013 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_data_manager_impl_private.h"
+
+#if defined(OS_MACOSX)
+#include <ApplicationServices/ApplicationServices.h>
+#endif // OS_MACOSX
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "base/file_util.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
+#include "base/stringprintf.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/sys_info.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"
+#include "content/public/browser/gpu_data_manager_observer.h"
+#include "content/public/common/content_client.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/gpu_feature_type.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "grit/content_resources.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_switches.h"
+#include "ui/gl/gpu_switching_manager.h"
+#include "webkit/glue/webpreferences.h"
+#include "webkit/plugins/plugin_switches.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+namespace content {
+namespace {
+
+// Strip out the non-digital info; if after that, we get an empty string,
+// return "0".
+std::string ProcessVersionString(const std::string& raw_string) {
+ const std::string valid_set = "0123456789.";
+ size_t start_pos = raw_string.find_first_of(valid_set);
+ if (start_pos == std::string::npos)
+ return "0";
+ size_t end_pos = raw_string.find_first_not_of(raw_string, start_pos);
+ std::string version_string = raw_string.substr(
+ start_pos, end_pos - start_pos);
+ if (version_string.empty())
+ return "0";
+ return version_string;
+}
+
+// Combine the integers into a string, seperated by ','.
+std::string IntSetToString(const std::set<int>& list) {
+ std::string rt;
+ for (std::set<int>::const_iterator it = list.begin();
+ it != list.end(); ++it) {
+ if (!rt.empty())
+ rt += ",";
+ rt += base::IntToString(*it);
+ }
+ return rt;
+}
+
+#if defined(OS_MACOSX)
+void DisplayReconfigCallback(CGDirectDisplayID display,
+ CGDisplayChangeSummaryFlags flags,
+ void* gpu_data_manager) {
+ if (flags & kCGDisplayAddFlag) {
+ GpuDataManagerImpl* manager =
+ reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager);
+ DCHECK(manager);
+ manager->HandleGpuSwitch();
+ }
+}
+#endif // OS_MACOSX
+
+// Block all domains' use of 3D APIs for this many milliseconds if
+// approaching a threshold where system stability might be compromised.
+const int64 kBlockAllDomainsMs = 10000;
+const int kNumResetsWithinDuration = 1;
+
+// Enums for UMA histograms.
+enum BlockStatusHistogram {
+ BLOCK_STATUS_NOT_BLOCKED,
+ BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
+ BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
+ BLOCK_STATUS_MAX
+};
+
+} // namespace anonymous
+
+void GpuDataManagerImplPrivate::InitializeForTesting(
+ const std::string& gpu_blacklist_json,
+ const GPUInfo& gpu_info) {
+ // This function is for testing only, so disable histograms.
+ update_histograms_ = false;
+
+ InitializeImpl(gpu_blacklist_json, std::string(), std::string(), gpu_info);
+}
+
+bool GpuDataManagerImplPrivate::IsFeatureBlacklisted(int feature) const {
+ if (use_swiftshader_) {
+ // Skia's software rendering is probably more efficient than going through
+ // software emulation of the GPU, so use that.
+ if (feature == GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)
+ return true;
+ return false;
+ }
+
+ return (blacklisted_features_.count(feature) == 1);
+}
+
+size_t GpuDataManagerImplPrivate::GetBlacklistedFeatureCount() const {
+ if (use_swiftshader_)
+ return 1;
+ return blacklisted_features_.size();
+}
+
+GPUInfo GpuDataManagerImplPrivate::GetGPUInfo() const {
+ return gpu_info_;
+}
+
+void GpuDataManagerImplPrivate::GetGpuProcessHandles(
+ const GpuDataManager::GetGpuProcessHandlesCallback& callback) const {
+ GpuProcessHost::GetProcessHandles(callback);
+}
+
+bool GpuDataManagerImplPrivate::GpuAccessAllowed(
+ std::string* reason) const {
+ if (use_swiftshader_)
+ return true;
+
+ if (!gpu_info_.gpu_accessible) {
+ if (reason) {
+ *reason = "GPU process launch failed.";
+ }
+ return false;
+ }
+
+ if (card_blacklisted_) {
+ if (reason) {
+ *reason = "GPU access is disabled ";
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kDisableGpu))
+ *reason += "through commandline switch --disable-gpu.";
+ else
+ *reason += "in chrome://settings.";
+ }
+ return false;
+ }
+
+ // We only need to block GPU process if more features are disallowed other
+ // than those in the preliminary gpu feature flags because the latter work
+ // through renderer commandline switches.
+ std::set<int> features = preliminary_blacklisted_features_;
+ MergeFeatureSets(&features, blacklisted_features_);
+ if (features.size() > preliminary_blacklisted_features_.size()) {
+ if (reason) {
+ *reason = "Features are disabled upon full but not preliminary GPU info.";
+ }
+ return false;
+ }
+
+ if (blacklisted_features_.size() == NUMBER_OF_GPU_FEATURE_TYPES) {
+ // On Linux, we use cached GL strings to make blacklist decsions at browser
+ // startup time. We need to launch the GPU process to validate these
+ // strings even if all features are blacklisted. If all GPU features are
+ // disabled, the GPU process will only initialize GL bindings, create a GL
+ // context, and collect full GPU info.
+#if !defined(OS_LINUX)
+ if (reason) {
+ *reason = "All GPU features are blacklisted.";
+ }
+ return false;
+#endif
+ }
+
+ return true;
+}
+
+void GpuDataManagerImplPrivate::RequestCompleteGpuInfoIfNeeded() {
+ if (complete_gpu_info_already_requested_ || gpu_info_.finalized)
+ return;
+ complete_gpu_info_already_requested_ = true;
+
+ GpuProcessHost::SendOnIO(
+#if defined(OS_WIN)
+ GpuProcessHost::GPU_PROCESS_KIND_UNSANDBOXED,
+#else
+ GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+#endif
+ CAUSE_FOR_GPU_LAUNCH_GPUDATAMANAGER_REQUESTCOMPLETEGPUINFOIFNEEDED,
+ new GpuMsg_CollectGraphicsInfo());
+}
+
+bool GpuDataManagerImplPrivate::IsCompleteGpuInfoAvailable() const {
+ return gpu_info_.finalized;
+}
+
+void GpuDataManagerImplPrivate::RequestVideoMemoryUsageStatsUpdate() const {
+ GpuProcessHost::SendOnIO(
+ GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+ CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
+ new GpuMsg_GetVideoMemoryUsageStats());
+}
+
+bool GpuDataManagerImplPrivate::ShouldUseSwiftShader() const {
+ return use_swiftshader_;
+}
+
+void GpuDataManagerImplPrivate::RegisterSwiftShaderPath(
+ const base::FilePath& path) {
+ swiftshader_path_ = path;
+ EnableSwiftShaderIfNecessary();
+}
+
+void GpuDataManagerImplPrivate::AddObserver(GpuDataManagerObserver* observer) {
+ GpuDataManagerImpl::UnlockedSession session(owner_);
+ observer_list_->AddObserver(observer);
+}
+
+void GpuDataManagerImplPrivate::RemoveObserver(
+ GpuDataManagerObserver* observer) {
+ GpuDataManagerImpl::UnlockedSession session(owner_);
+ observer_list_->RemoveObserver(observer);
+}
+
+void GpuDataManagerImplPrivate::UnblockDomainFrom3DAPIs(const GURL& url) {
+ // This method must do two things:
+ //
+ // 1. If the specific domain is blocked, then unblock it.
+ //
+ // 2. Reset our notion of how many GPU resets have occurred recently.
+ // This is necessary even if the specific domain was blocked.
+ // Otherwise, if we call Are3DAPIsBlocked with the same domain right
+ // after unblocking it, it will probably still be blocked because of
+ // the recent GPU reset caused by that domain.
+ //
+ // These policies could be refined, but at a certain point the behavior
+ // will become difficult to explain.
+ std::string domain = GetDomainFromURL(url);
+
+ blocked_domains_.erase(domain);
+ timestamps_of_gpu_resets_.clear();
+}
+
+void GpuDataManagerImplPrivate::DisableGpuWatchdog() {
+ GpuProcessHost::SendOnIO(
+ GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+ CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
+ new GpuMsg_DisableWatchdog);
+}
+
+void GpuDataManagerImplPrivate::SetGLStrings(const std::string& gl_vendor,
+ const std::string& gl_renderer,
+ const std::string& gl_version) {
+ if (gl_vendor.empty() && gl_renderer.empty() && gl_version.empty())
+ return;
+
+ // If GPUInfo already got GL strings, do nothing. This is for the rare
+ // situation where GPU process collected GL strings before this call.
+ if (!gpu_info_.gl_vendor.empty() ||
+ !gpu_info_.gl_renderer.empty() ||
+ !gpu_info_.gl_version_string.empty())
+ return;
+
+ GPUInfo gpu_info = gpu_info_;
+
+ gpu_info.gl_vendor = gl_vendor;
+ gpu_info.gl_renderer = gl_renderer;
+ gpu_info.gl_version_string = gl_version;
+
+ gpu_info_collector::CollectDriverInfoGL(&gpu_info);
+
+ UpdateGpuInfo(gpu_info);
+ UpdateGpuSwitchingManager(gpu_info);
+ UpdatePreliminaryBlacklistedFeatures();
+}
+
+void GpuDataManagerImplPrivate::GetGLStrings(std::string* gl_vendor,
+ std::string* gl_renderer,
+ std::string* gl_version) {
+ DCHECK(gl_vendor && gl_renderer && gl_version);
+
+ *gl_vendor = gpu_info_.gl_vendor;
+ *gl_renderer = gpu_info_.gl_renderer;
+ *gl_version = gpu_info_.gl_version_string;
+}
+
+void GpuDataManagerImplPrivate::Initialize() {
+ TRACE_EVENT0("startup", "GpuDataManagerImpl::Initialize");
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kSkipGpuDataLoading))
+ return;
+
+ GPUInfo gpu_info;
+ {
+ TRACE_EVENT0("startup",
+ "GpuDataManagerImpl::Initialize:CollectBasicGraphicsInfo");
+ gpu_info_collector::CollectBasicGraphicsInfo(&gpu_info);
+ }
+#if defined(ARCH_CPU_X86_FAMILY)
+ if (!gpu_info.gpu.vendor_id || !gpu_info.gpu.device_id)
+ gpu_info.finalized = true;
+#endif
+
+ std::string gpu_blacklist_string;
+ std::string gpu_switching_list_string;
+ std::string gpu_driver_bug_list_string;
+ if (!command_line->HasSwitch(switches::kIgnoreGpuBlacklist)) {
+ const base::StringPiece gpu_blacklist_json =
+ GetContentClient()->GetDataResource(
+ IDR_GPU_BLACKLIST, ui::SCALE_FACTOR_NONE);
+ gpu_blacklist_string = gpu_blacklist_json.as_string();
+ const base::StringPiece gpu_switching_list_json =
+ GetContentClient()->GetDataResource(
+ IDR_GPU_SWITCHING_LIST, ui::SCALE_FACTOR_NONE);
+ gpu_switching_list_string = gpu_switching_list_json.as_string();
+ }
+ if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
+ const base::StringPiece gpu_driver_bug_list_json =
+ GetContentClient()->GetDataResource(
+ IDR_GPU_DRIVER_BUG_LIST, ui::SCALE_FACTOR_NONE);
+ gpu_driver_bug_list_string = gpu_driver_bug_list_json.as_string();
+ }
+ InitializeImpl(gpu_blacklist_string,
+ gpu_switching_list_string,
+ gpu_driver_bug_list_string,
+ gpu_info);
+ // We pass down the list to GPU command buffer through commandline
+ // switches at GPU process launch. However, in situations where we don't
+ // have a GPU process, we append the browser process commandline.
+ if (command_line->HasSwitch(switches::kSingleProcess) ||
+ command_line->HasSwitch(switches::kInProcessGPU)) {
+ if (!gpu_driver_bugs_.empty()) {
+ command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
+ IntSetToString(gpu_driver_bugs_));
+ }
+ }
+}
+
+void GpuDataManagerImplPrivate::UpdateGpuInfo(const GPUInfo& gpu_info) {
+ // No further update of gpu_info if falling back to SwiftShader.
+ if (use_swiftshader_)
+ return;
+
+ gpu_info_collector::MergeGPUInfo(&gpu_info_, gpu_info);
+ complete_gpu_info_already_requested_ =
+ complete_gpu_info_already_requested_ || gpu_info_.finalized;
+
+ GetContentClient()->SetGpuInfo(gpu_info_);
+
+ if (gpu_blacklist_) {
+ std::set<int> features = gpu_blacklist_->MakeDecision(
+ GpuControlList::kOsAny, std::string(), gpu_info_);
+ if (update_histograms_)
+ UpdateStats(gpu_blacklist_.get(), features);
+
+ UpdateBlacklistedFeatures(features);
+ }
+ if (gpu_switching_list_) {
+ std::set<int> option = gpu_switching_list_->MakeDecision(
+ GpuControlList::kOsAny, std::string(), gpu_info_);
+ if (option.size() == 1) {
+ // Blacklist decision should not overwrite commandline switch from users.
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (!command_line->HasSwitch(switches::kGpuSwitching))
+ gpu_switching_ = static_cast<GpuSwitchingOption>(*(option.begin()));
+ }
+ }
+ if (gpu_driver_bug_list_)
+ gpu_driver_bugs_ = gpu_driver_bug_list_->MakeDecision(
+ GpuControlList::kOsAny, std::string(), gpu_info_);
+
+ // We have to update GpuFeatureType before notify all the observers.
+ NotifyGpuInfoUpdate();
+}
+
+void GpuDataManagerImplPrivate::UpdateVideoMemoryUsageStats(
+ const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
+ GpuDataManagerImpl::UnlockedSession session(owner_);
+ observer_list_->Notify(&GpuDataManagerObserver::OnVideoMemoryUsageStatsUpdate,
+ video_memory_usage_stats);
+}
+
+void GpuDataManagerImplPrivate::AppendRendererCommandLine(
+ CommandLine* command_line) const {
+ DCHECK(command_line);
+
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL)) {
+#if !defined(OS_ANDROID)
+ if (!command_line->HasSwitch(switches::kDisableExperimentalWebGL))
+ command_line->AppendSwitch(switches::kDisableExperimentalWebGL);
+#endif
+ if (!command_line->HasSwitch(switches::kDisablePepper3d))
+ command_line->AppendSwitch(switches::kDisablePepper3d);
+ }
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_MULTISAMPLING) &&
+ !command_line->HasSwitch(switches::kDisableGLMultisampling))
+ command_line->AppendSwitch(switches::kDisableGLMultisampling);
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) &&
+ !command_line->HasSwitch(switches::kDisableAcceleratedCompositing))
+ command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS) &&
+ !command_line->HasSwitch(switches::kDisableAccelerated2dCanvas))
+ command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
+ !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
+ command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
+ if (ShouldUseSwiftShader())
+ command_line->AppendSwitch(switches::kDisableFlashFullscreen3d);
+}
+
+void GpuDataManagerImplPrivate::AppendGpuCommandLine(
+ CommandLine* command_line) const {
+ DCHECK(command_line);
+
+ std::string use_gl =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL);
+ base::FilePath swiftshader_path =
+ CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kSwiftShaderPath);
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_MULTISAMPLING) &&
+ !command_line->HasSwitch(switches::kDisableGLMultisampling))
+ command_line->AppendSwitch(switches::kDisableGLMultisampling);
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_TEXTURE_SHARING))
+ command_line->AppendSwitch(switches::kDisableImageTransportSurface);
+
+ if (use_swiftshader_) {
+ command_line->AppendSwitchASCII(switches::kUseGL, "swiftshader");
+ if (swiftshader_path.empty())
+ swiftshader_path = swiftshader_path_;
+ } else if ((IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL) ||
+ IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
+ IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)) &&
+ (use_gl == "any")) {
+ command_line->AppendSwitchASCII(
+ switches::kUseGL, gfx::kGLImplementationOSMesaName);
+ } else if (!use_gl.empty()) {
+ command_line->AppendSwitchASCII(switches::kUseGL, use_gl);
+ }
+ if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
+ command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "true");
+ switch (gpu_switching_) {
+ case GPU_SWITCHING_OPTION_FORCE_DISCRETE:
+ command_line->AppendSwitchASCII(switches::kGpuSwitching,
+ switches::kGpuSwitchingOptionNameForceDiscrete);
+ break;
+ case GPU_SWITCHING_OPTION_FORCE_INTEGRATED:
+ command_line->AppendSwitchASCII(switches::kGpuSwitching,
+ switches::kGpuSwitchingOptionNameForceIntegrated);
+ break;
+ case GPU_SWITCHING_OPTION_AUTOMATIC:
+ case GPU_SWITCHING_OPTION_UNKNOWN:
+ break;
+ }
+ } else {
+ command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "false");
+ }
+
+ if (!swiftshader_path.empty())
+ command_line->AppendSwitchPath(switches::kSwiftShaderPath,
+ swiftshader_path);
+
+ if (!gpu_driver_bugs_.empty()) {
+ command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
+ IntSetToString(gpu_driver_bugs_));
+ }
+
+#if defined(OS_WIN)
+ // DisplayLink 7.1 and earlier can cause the GPU process to crash on startup.
+ // http://crbug.com/177611
+ // Thinkpad USB Port Replicator driver causes GPU process to crash when the
+ // sandbox is enabled. http://crbug.com/181665.
+ if ((gpu_info_.display_link_version.IsValid()
+ && gpu_info_.display_link_version.IsOlderThan("7.2")) ||
+ gpu_info_.lenovo_dcute) {
+ command_line->AppendSwitch(switches::kReduceGpuSandbox);
+ }
+#endif
+
+ if (gpu_info_.optimus)
+ command_line->AppendSwitch(switches::kReduceGpuSandbox);
+ if (gpu_info_.amd_switchable) {
+ // The image transport surface currently doesn't work with AMD Dynamic
+ // Switchable graphics.
+ command_line->AppendSwitch(switches::kReduceGpuSandbox);
+ command_line->AppendSwitch(switches::kDisableImageTransportSurface);
+ }
+ // Pass GPU and driver information to GPU process. We try to avoid full GPU
+ // info collection at GPU process startup, but we need gpu vendor_id,
+ // device_id, driver_vendor, driver_version for deciding whether we need to
+ // collect full info (on Linux) and for crash reporting purpose.
+ command_line->AppendSwitchASCII(switches::kGpuVendorID,
+ base::StringPrintf("0x%04x", gpu_info_.gpu.vendor_id));
+ command_line->AppendSwitchASCII(switches::kGpuDeviceID,
+ base::StringPrintf("0x%04x", gpu_info_.gpu.device_id));
+ command_line->AppendSwitchASCII(switches::kGpuDriverVendor,
+ gpu_info_.driver_vendor);
+ command_line->AppendSwitchASCII(switches::kGpuDriverVersion,
+ gpu_info_.driver_version);
+}
+
+void GpuDataManagerImplPrivate::AppendPluginCommandLine(
+ CommandLine* command_line) const {
+ DCHECK(command_line);
+
+#if defined(OS_MACOSX)
+ // TODO(jbauman): Add proper blacklist support for core animation plugins so
+ // special-casing this video card won't be necessary. See
+ // http://crbug.com/134015
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableAcceleratedCompositing)) {
+ if (!command_line->HasSwitch(
+ switches::kDisableCoreAnimationPlugins))
+ command_line->AppendSwitch(
+ switches::kDisableCoreAnimationPlugins);
+ }
+#endif
+}
+
+void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
+ WebPreferences* prefs) const {
+ DCHECK(prefs);
+
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING))
+ prefs->accelerated_compositing_enabled = false;
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL))
+ prefs->experimental_webgl_enabled = false;
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_FLASH3D))
+ prefs->flash_3d_enabled = false;
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_FLASH_STAGE3D)) {
+ prefs->flash_stage3d_enabled = false;
+ prefs->flash_stage3d_baseline_enabled = false;
+ }
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE))
+ prefs->flash_stage3d_baseline_enabled = false;
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS))
+ prefs->accelerated_2d_canvas_enabled = false;
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_MULTISAMPLING))
+ prefs->gl_multisampling_enabled = false;
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_3D_CSS)) {
+ prefs->accelerated_compositing_for_3d_transforms_enabled = false;
+ prefs->accelerated_compositing_for_animation_enabled = false;
+ }
+ if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_VIDEO))
+ prefs->accelerated_compositing_for_video_enabled = false;
+
+ // Accelerated video and animation are slower than regular when using
+ // SwiftShader. 3D CSS may also be too slow to be worthwhile.
+ if (ShouldUseSwiftShader()) {
+ prefs->accelerated_compositing_for_video_enabled = false;
+ prefs->accelerated_compositing_for_animation_enabled = false;
+ prefs->accelerated_compositing_for_3d_transforms_enabled = false;
+ prefs->accelerated_compositing_for_plugins_enabled = false;
+ }
+}
+
+GpuSwitchingOption GpuDataManagerImplPrivate::GetGpuSwitchingOption() const {
+ if (!ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus())
+ return GPU_SWITCHING_OPTION_UNKNOWN;
+ return gpu_switching_;
+}
+
+void GpuDataManagerImplPrivate::DisableHardwareAcceleration() {
+ card_blacklisted_ = true;
+
+ for (int i = 0; i < NUMBER_OF_GPU_FEATURE_TYPES; ++i)
+ blacklisted_features_.insert(i);
+
+ EnableSwiftShaderIfNecessary();
+ NotifyGpuInfoUpdate();
+}
+
+std::string GpuDataManagerImplPrivate::GetBlacklistVersion() const {
+ if (gpu_blacklist_)
+ return gpu_blacklist_->version();
+ return "0";
+}
+
+base::ListValue* GpuDataManagerImplPrivate::GetBlacklistReasons() const {
+ ListValue* reasons = new ListValue();
+ if (gpu_blacklist_)
+ gpu_blacklist_->GetReasons(reasons);
+ return reasons;
+}
+
+void GpuDataManagerImplPrivate::AddLogMessage(
+ int level, const std::string& header, const std::string& message) {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetInteger("level", level);
+ dict->SetString("header", header);
+ dict->SetString("message", message);
+ log_messages_.Append(dict);
+}
+
+void GpuDataManagerImplPrivate::ProcessCrashed(
+ base::TerminationStatus exit_code) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ if (owner_) {
+ // Unretained is ok, because it's posted to UI thread, the thread
+ // where the singleton GpuDataManagerImpl lives until the end.
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&GpuDataManagerImpl::ProcessCrashed,
+ base::Unretained(owner_),
+ exit_code));
+ }
+ return;
+ }
+ {
+ GpuDataManagerImpl::UnlockedSession session(owner_);
+ observer_list_->Notify(
+ &GpuDataManagerObserver::OnGpuProcessCrashed, exit_code);
+ }
+}
+
+base::ListValue* GpuDataManagerImplPrivate::GetLogMessages() const {
+ base::ListValue* value;
+ value = log_messages_.DeepCopy();
+ return value;
+}
+
+void GpuDataManagerImplPrivate::HandleGpuSwitch() {
+ GpuDataManagerImpl::UnlockedSession session(owner_);
+ observer_list_->Notify(&GpuDataManagerObserver::OnGpuSwitching);
+}
+
+#if defined(OS_WIN)
+bool GpuDataManagerImplPrivate::IsUsingAcceleratedSurface() const {
+ if (base::win::GetVersion() < base::win::VERSION_VISTA)
+ return false;
+
+ if (gpu_info_.amd_switchable)
+ return false;
+ if (use_swiftshader_)
+ return false;
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kDisableImageTransportSurface))
+ return false;
+ return !IsFeatureBlacklisted(GPU_FEATURE_TYPE_TEXTURE_SHARING);
+}
+#endif
+
+void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIs(
+ const GURL& url, GpuDataManagerImpl::DomainGuilt guilt) {
+ BlockDomainFrom3DAPIsAtTime(url, guilt, base::Time::Now());
+}
+
+bool GpuDataManagerImplPrivate::Are3DAPIsBlocked(const GURL& url,
+ int render_process_id,
+ int render_view_id,
+ ThreeDAPIType requester) {
+ bool blocked = Are3DAPIsBlockedAtTime(url, base::Time::Now()) !=
+ GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
+ if (blocked && owner_) {
+ // Unretained is ok, because it's posted to UI thread, the thread
+ // where the singleton GpuDataManagerImpl lives until the end.
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&GpuDataManagerImpl::Notify3DAPIBlocked,
+ base::Unretained(owner_), url, render_process_id,
+ render_view_id, requester));
+ }
+
+ return blocked;
+}
+
+void GpuDataManagerImplPrivate::DisableDomainBlockingFor3DAPIsForTesting() {
+ domain_blocking_enabled_ = false;
+}
+
+// static
+GpuDataManagerImplPrivate* GpuDataManagerImplPrivate::Create(
+ GpuDataManagerImpl* owner) {
+ GpuDataManagerImplPrivate* rt = new GpuDataManagerImplPrivate();
+ rt->owner_ = owner;
+ return rt;
+}
+
+GpuDataManagerImplPrivate::GpuDataManagerImplPrivate()
+ : complete_gpu_info_already_requested_(false),
+ gpu_switching_(GPU_SWITCHING_OPTION_AUTOMATIC),
+ observer_list_(new GpuDataManagerObserverList),
+ use_swiftshader_(false),
+ card_blacklisted_(false),
+ update_histograms_(true),
+ window_count_(0),
+ domain_blocking_enabled_(true),
+ owner_(NULL) {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kDisableAcceleratedCompositing)) {
+ command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
+ command_line->AppendSwitch(switches::kDisableAcceleratedLayers);
+ }
+ if (command_line->HasSwitch(switches::kDisableGpu))
+ DisableHardwareAcceleration();
+ if (command_line->HasSwitch(switches::kGpuSwitching)) {
+ std::string option_string = command_line->GetSwitchValueASCII(
+ switches::kGpuSwitching);
+ GpuSwitchingOption option = StringToGpuSwitchingOption(option_string);
+ if (option != GPU_SWITCHING_OPTION_UNKNOWN)
+ gpu_switching_ = option;
+ }
+
+#if defined(OS_MACOSX)
+ CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback, this);
+#endif // OS_MACOSX
+}
+
+GpuDataManagerImplPrivate::~GpuDataManagerImplPrivate() {
+#if defined(OS_MACOSX)
+ CGDisplayRemoveReconfigurationCallback(DisplayReconfigCallback, this);
+#endif
+}
+
+void GpuDataManagerImplPrivate::InitializeImpl(
+ const std::string& gpu_blacklist_json,
+ const std::string& gpu_switching_list_json,
+ const std::string& gpu_driver_bug_list_json,
+ const GPUInfo& gpu_info) {
+ std::string browser_version_string = ProcessVersionString(
+ GetContentClient()->GetProduct());
+ CHECK(!browser_version_string.empty());
+
+ if (!gpu_blacklist_json.empty()) {
+ gpu_blacklist_.reset(GpuBlacklist::Create());
+ gpu_blacklist_->LoadList(
+ browser_version_string, gpu_blacklist_json,
+ GpuControlList::kCurrentOsOnly);
+ }
+ if (!gpu_switching_list_json.empty()) {
+ gpu_switching_list_.reset(GpuSwitchingList::Create());
+ gpu_switching_list_->LoadList(
+ browser_version_string, gpu_switching_list_json,
+ GpuControlList::kCurrentOsOnly);
+ }
+ if (!gpu_driver_bug_list_json.empty()) {
+ gpu_driver_bug_list_.reset(GpuDriverBugList::Create());
+ gpu_driver_bug_list_->LoadList(
+ browser_version_string, gpu_driver_bug_list_json,
+ GpuControlList::kCurrentOsOnly);
+ }
+
+ gpu_info_ = gpu_info;
+ UpdateGpuInfo(gpu_info);
+ UpdateGpuSwitchingManager(gpu_info);
+ UpdatePreliminaryBlacklistedFeatures();
+}
+
+void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures(
+ const std::set<int>& features) {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ blacklisted_features_ = features;
+
+ // Force disable using the GPU for these features, even if they would
+ // otherwise be allowed.
+ if (card_blacklisted_ ||
+ command_line->HasSwitch(switches::kBlacklistAcceleratedCompositing)) {
+ blacklisted_features_.insert(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING);
+ }
+ if (card_blacklisted_ ||
+ command_line->HasSwitch(switches::kBlacklistWebGL)) {
+ blacklisted_features_.insert(GPU_FEATURE_TYPE_WEBGL);
+ }
+
+ EnableSwiftShaderIfNecessary();
+}
+
+void GpuDataManagerImplPrivate::UpdatePreliminaryBlacklistedFeatures() {
+ preliminary_blacklisted_features_ = blacklisted_features_;
+}
+
+void GpuDataManagerImplPrivate::UpdateGpuSwitchingManager(
+ const GPUInfo& gpu_info) {
+ ui::GpuSwitchingManager::GetInstance()->SetGpuCount(
+ gpu_info.secondary_gpus.size() + 1);
+
+ if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
+ switch (gpu_switching_) {
+ case GPU_SWITCHING_OPTION_FORCE_DISCRETE:
+ ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu();
+ break;
+ case GPU_SWITCHING_OPTION_FORCE_INTEGRATED:
+ ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu();
+ break;
+ case GPU_SWITCHING_OPTION_AUTOMATIC:
+ case GPU_SWITCHING_OPTION_UNKNOWN:
+ break;
+ }
+ }
+}
+
+void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() {
+ observer_list_->Notify(&GpuDataManagerObserver::OnGpuInfoUpdate);
+}
+
+void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() {
+ if (!GpuAccessAllowed(NULL) ||
+ blacklisted_features_.count(GPU_FEATURE_TYPE_WEBGL)) {
+ if (!swiftshader_path_.empty() &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableSoftwareRasterizer))
+ use_swiftshader_ = true;
+ }
+}
+
+std::string GpuDataManagerImplPrivate::GetDomainFromURL(
+ const GURL& url) const {
+ // For the moment, we just use the host, or its IP address, as the
+ // entry in the set, rather than trying to figure out the top-level
+ // domain. This does mean that a.foo.com and b.foo.com will be
+ // treated independently in the blocking of a given domain, but it
+ // would require a third-party library to reliably figure out the
+ // top-level domain from a URL.
+ if (!url.has_host()) {
+ return std::string();
+ }
+
+ return url.host();
+}
+
+void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIsAtTime(
+ const GURL& url,
+ GpuDataManagerImpl::DomainGuilt guilt,
+ base::Time at_time) {
+ if (!domain_blocking_enabled_)
+ return;
+
+ std::string domain = GetDomainFromURL(url);
+
+ DomainBlockEntry& entry = blocked_domains_[domain];
+ entry.last_guilt = guilt;
+ timestamps_of_gpu_resets_.push_back(at_time);
+}
+
+GpuDataManagerImpl::DomainBlockStatus
+GpuDataManagerImplPrivate::Are3DAPIsBlockedAtTime(
+ const GURL& url, base::Time at_time) const {
+ if (!domain_blocking_enabled_)
+ return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
+
+ // Note: adjusting the policies in this code will almost certainly
+ // require adjusting the associated unit tests.
+ std::string domain = GetDomainFromURL(url);
+
+ DomainBlockMap::const_iterator iter = blocked_domains_.find(domain);
+ if (iter != blocked_domains_.end()) {
+ // Err on the side of caution, and assume that if a particular
+ // domain shows up in the block map, it's there for a good
+ // reason and don't let its presence there automatically expire.
+
+ UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
+ BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
+ BLOCK_STATUS_MAX);
+
+ return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED;
+ }
+
+ // Look at the timestamps of the recent GPU resets to see if there are
+ // enough within the threshold which would cause us to blacklist all
+ // domains. This doesn't need to be overly precise -- if time goes
+ // backward due to a system clock adjustment, that's fine.
+ //
+ // TODO(kbr): make this pay attention to the TDR thresholds in the
+ // Windows registry, but make sure it continues to be testable.
+ {
+ std::list<base::Time>::iterator iter = timestamps_of_gpu_resets_.begin();
+ int num_resets_within_timeframe = 0;
+ while (iter != timestamps_of_gpu_resets_.end()) {
+ base::Time time = *iter;
+ base::TimeDelta delta_t = at_time - time;
+
+ // If this entry has "expired", just remove it.
+ if (delta_t.InMilliseconds() > kBlockAllDomainsMs) {
+ iter = timestamps_of_gpu_resets_.erase(iter);
+ continue;
+ }
+
+ ++num_resets_within_timeframe;
+ ++iter;
+ }
+
+ if (num_resets_within_timeframe >= kNumResetsWithinDuration) {
+ UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
+ BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
+ BLOCK_STATUS_MAX);
+
+ return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED;
+ }
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
+ BLOCK_STATUS_NOT_BLOCKED,
+ BLOCK_STATUS_MAX);
+
+ return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
+}
+
+int64 GpuDataManagerImplPrivate::GetBlockAllDomainsDurationInMs() const {
+ return kBlockAllDomainsMs;
+}
+
+void GpuDataManagerImplPrivate::Notify3DAPIBlocked(const GURL& url,
+ int render_process_id,
+ int render_view_id,
+ ThreeDAPIType requester) {
+ GpuDataManagerImpl::UnlockedSession session(owner_);
+ observer_list_->Notify(&GpuDataManagerObserver::DidBlock3DAPIs,
+ url, render_process_id, render_view_id, requester);
+}
+
+} // namespace content
+
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.h b/content/browser/gpu/gpu_data_manager_impl_private.h
new file mode 100644
index 0000000..d8fc042
--- /dev/null
+++ b/content/browser/gpu/gpu_data_manager_impl_private.h
@@ -0,0 +1,239 @@
+// Copyright (c) 2013 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_DATA_MANAGER_IMPL_PRIVATE_H_
+#define CONTENT_BROWSER_GPU_GPU_DATA_MANAGER_IMPL_PRIVATE_H_
+
+#include <list>
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/singleton.h"
+#include "base/observer_list_threadsafe.h"
+#include "content/browser/gpu/gpu_blacklist.h"
+#include "content/browser/gpu/gpu_data_manager_impl.h"
+#include "content/browser/gpu/gpu_driver_bug_list.h"
+#include "content/browser/gpu/gpu_switching_list.h"
+
+namespace content {
+
+class CONTENT_EXPORT GpuDataManagerImplPrivate {
+ public:
+ static GpuDataManagerImplPrivate* Create(GpuDataManagerImpl* owner);
+
+ void InitializeForTesting(
+ const std::string& gpu_blacklist_json,
+ const GPUInfo& gpu_info);
+ bool IsFeatureBlacklisted(int feature) const;
+ GPUInfo GetGPUInfo() const;
+ void GetGpuProcessHandles(
+ const GpuDataManager::GetGpuProcessHandlesCallback& callback) const;
+ bool GpuAccessAllowed(std::string* reason) const;
+ void RequestCompleteGpuInfoIfNeeded();
+ bool IsCompleteGpuInfoAvailable() const;
+ void RequestVideoMemoryUsageStatsUpdate() const;
+ bool ShouldUseSwiftShader() const;
+ void RegisterSwiftShaderPath(const base::FilePath& path);
+ void AddObserver(GpuDataManagerObserver* observer);
+ void RemoveObserver(GpuDataManagerObserver* observer);
+ void UnblockDomainFrom3DAPIs(const GURL& url);
+ void DisableGpuWatchdog();
+ void SetGLStrings(const std::string& gl_vendor,
+ const std::string& gl_renderer,
+ const std::string& gl_version);
+ void GetGLStrings(std::string* gl_vendor,
+ std::string* gl_renderer,
+ std::string* gl_version);
+ void DisableHardwareAcceleration();
+
+ void Initialize();
+
+ void UpdateGpuInfo(const GPUInfo& gpu_info);
+
+ void UpdateVideoMemoryUsageStats(
+ const GPUVideoMemoryUsageStats& video_memory_usage_stats);
+
+ void AppendRendererCommandLine(CommandLine* command_line) const;
+
+ void AppendGpuCommandLine(CommandLine* command_line) const;
+
+ void AppendPluginCommandLine(CommandLine* command_line) const;
+
+ void UpdateRendererWebPrefs(WebPreferences* prefs) const;
+
+ GpuSwitchingOption GetGpuSwitchingOption() const;
+
+ std::string GetBlacklistVersion() const;
+
+ base::ListValue* GetBlacklistReasons() const;
+
+ void AddLogMessage(int level,
+ const std::string& header,
+ const std::string& message);
+
+ void ProcessCrashed(base::TerminationStatus exit_code);
+
+ base::ListValue* GetLogMessages() const;
+
+ void HandleGpuSwitch();
+
+#if defined(OS_WIN)
+ // Is the GPU process using the accelerated surface to present, instead of
+ // presenting by itself.
+ bool IsUsingAcceleratedSurface() const;
+#endif
+
+ void BlockDomainFrom3DAPIs(
+ const GURL& url, GpuDataManagerImpl::DomainGuilt guilt);
+ bool Are3DAPIsBlocked(const GURL& url,
+ int render_process_id,
+ int render_view_id,
+ ThreeDAPIType requester);
+
+ void DisableDomainBlockingFor3DAPIsForTesting();
+
+ void Notify3DAPIBlocked(const GURL& url,
+ int render_process_id,
+ int render_view_id,
+ ThreeDAPIType requester);
+
+ size_t GetBlacklistedFeatureCount() const;
+
+ virtual ~GpuDataManagerImplPrivate();
+
+ private:
+ friend class GpuDataManagerImplPrivateTest;
+
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ GpuSideBlacklisting);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ GpuSideExceptions);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ DisableHardwareAcceleration);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ SwiftShaderRendering);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ SwiftShaderRendering2);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ GpuInfoUpdate);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ NoGpuInfoUpdateWithSwiftShader);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ GPUVideoMemoryUsageStatsUpdate);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ BlockAllDomainsFrom3DAPIs);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ UnblockGuiltyDomainFrom3DAPIs);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ UnblockDomainOfUnknownGuiltFrom3DAPIs);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ UnblockOtherDomainFrom3DAPIs);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ UnblockThisDomainFrom3DAPIs);
+#if defined(OS_LINUX)
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ SetGLStrings);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ SetGLStringsNoEffects);
+#endif
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ GpuDriverBugListSingle);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ GpuDriverBugListMultiple);
+ FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
+ BlacklistAllFeatures);
+
+ struct DomainBlockEntry {
+ GpuDataManagerImpl::DomainGuilt last_guilt;
+ };
+
+ typedef std::map<std::string, DomainBlockEntry> DomainBlockMap;
+
+ typedef ObserverListThreadSafe<GpuDataManagerObserver>
+ GpuDataManagerObserverList;
+
+ GpuDataManagerImplPrivate();
+
+ void InitializeImpl(const std::string& gpu_blacklist_json,
+ const std::string& gpu_switching_list_json,
+ const std::string& gpu_driver_bug_list_json,
+ const GPUInfo& gpu_info);
+
+ void UpdateBlacklistedFeatures(const std::set<int>& features);
+
+ // This should only be called once at initialization time, when preliminary
+ // gpu info is collected.
+ void UpdatePreliminaryBlacklistedFeatures();
+
+ // Update the GPU switching status.
+ // This should only be called once at initialization time.
+ void UpdateGpuSwitchingManager(const GPUInfo& gpu_info);
+
+ // Notify all observers whenever there is a GPU info update.
+ void NotifyGpuInfoUpdate();
+
+ // Try to switch to SwiftShader rendering, if possible and necessary.
+ void EnableSwiftShaderIfNecessary();
+
+ // Helper to extract the domain from a given URL.
+ std::string GetDomainFromURL(const GURL& url) const;
+
+ // Implementation functions for blocking of 3D graphics APIs, used
+ // for unit testing.
+ void BlockDomainFrom3DAPIsAtTime(const GURL& url,
+ GpuDataManagerImpl::DomainGuilt guilt,
+ base::Time at_time);
+ GpuDataManagerImpl::DomainBlockStatus Are3DAPIsBlockedAtTime(
+ const GURL& url, base::Time at_time) const;
+ int64 GetBlockAllDomainsDurationInMs() const;
+
+ bool complete_gpu_info_already_requested_;
+
+ std::set<int> blacklisted_features_;
+ std::set<int> preliminary_blacklisted_features_;
+
+ GpuSwitchingOption gpu_switching_;
+
+ std::set<int> gpu_driver_bugs_;
+
+ GPUInfo gpu_info_;
+
+ scoped_ptr<GpuBlacklist> gpu_blacklist_;
+ scoped_ptr<GpuSwitchingList> gpu_switching_list_;
+ scoped_ptr<GpuDriverBugList> gpu_driver_bug_list_;
+
+ const scoped_refptr<GpuDataManagerObserverList> observer_list_;
+
+ ListValue log_messages_;
+
+ bool use_swiftshader_;
+
+ base::FilePath swiftshader_path_;
+
+ // Current card force-blacklisted due to GPU crashes, or disabled through
+ // the --disable-gpu commandline switch.
+ bool card_blacklisted_;
+
+ // We disable histogram stuff in testing, especially in unit tests because
+ // they cause random failures.
+ bool update_histograms_;
+
+ // Number of currently open windows, to be used in gpu memory allocation.
+ int window_count_;
+
+ DomainBlockMap blocked_domains_;
+ mutable std::list<base::Time> timestamps_of_gpu_resets_;
+ bool domain_blocking_enabled_;
+
+ GpuDataManagerImpl* owner_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuDataManagerImplPrivate);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GPU_GPU_DATA_MANAGER_IMPL_PRIVATE_H_
+
diff --git a/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc b/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
new file mode 100644
index 0000000..ab4fedd
--- /dev/null
+++ b/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
@@ -0,0 +1,619 @@
+// Copyright (c) 2013 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/command_line.h"
+#include "base/message_loop.h"
+#include "base/run_loop.h"
+#include "base/time.h"
+#include "content/browser/gpu/gpu_data_manager_impl_private.h"
+#include "content/public/browser/gpu_data_manager_observer.h"
+#include "content/public/common/gpu_feature_type.h"
+#include "content/public/common/gpu_info.h"
+#include "googleurl/src/gurl.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define LONG_STRING_CONST(...) #__VA_ARGS__
+
+namespace content {
+namespace {
+
+class TestObserver : public GpuDataManagerObserver {
+ public:
+ TestObserver()
+ : gpu_info_updated_(false),
+ video_memory_usage_stats_updated_(false) {
+ }
+ virtual ~TestObserver() { }
+
+ bool gpu_info_updated() const { return gpu_info_updated_; }
+ bool video_memory_usage_stats_updated() const {
+ return video_memory_usage_stats_updated_;
+ }
+
+ virtual void OnGpuInfoUpdate() OVERRIDE {
+ gpu_info_updated_ = true;
+ }
+
+ virtual void OnVideoMemoryUsageStatsUpdate(
+ const GPUVideoMemoryUsageStats& stats) OVERRIDE {
+ video_memory_usage_stats_updated_ = true;
+ }
+
+ private:
+ bool gpu_info_updated_;
+ bool video_memory_usage_stats_updated_;
+};
+
+static base::Time GetTimeForTesting() {
+ return base::Time::FromDoubleT(1000);
+}
+
+static GURL GetDomain1ForTesting() {
+ return GURL("http://foo.com/");
+}
+
+static GURL GetDomain2ForTesting() {
+ return GURL("http://bar.com/");
+}
+
+} // namespace anonymous
+
+class GpuDataManagerImplPrivateTest : public testing::Test {
+ public:
+ GpuDataManagerImplPrivateTest() { }
+
+ virtual ~GpuDataManagerImplPrivateTest() { }
+
+ protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+
+ base::Time JustBeforeExpiration(const GpuDataManagerImplPrivate& manager);
+ base::Time JustAfterExpiration(const GpuDataManagerImplPrivate& manager);
+ void TestBlockingDomainFrom3DAPIs(
+ GpuDataManagerImpl::DomainGuilt guilt_level);
+ void TestUnblockingDomainFrom3DAPIs(
+ GpuDataManagerImpl::DomainGuilt guilt_level);
+
+ base::MessageLoop message_loop_;
+};
+
+// We use new method instead of GetInstance() method because we want
+// each test to be independent of each other.
+
+TEST_F(GpuDataManagerImplPrivateTest, GpuSideBlacklisting) {
+ // If a feature is allowed in preliminary step (browser side), but
+ // disabled when GPU process launches and collects full GPU info,
+ // it's too late to let renderer know, so we basically block all GPU
+ // access, to be on the safe side.
+ GpuDataManagerImplPrivate manager;
+ EXPECT_EQ(0u, manager.GetBlacklistedFeatureCount());
+ std::string reason;
+ EXPECT_TRUE(manager.GpuAccessAllowed(&reason));
+ EXPECT_TRUE(reason.empty());
+
+ const std::string blacklist_json = LONG_STRING_CONST(
+ {
+ "name": "gpu blacklist",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "features": [
+ "webgl"
+ ]
+ },
+ {
+ "id": 2,
+ "gl_renderer": {
+ "op": "contains",
+ "value": "GeForce"
+ },
+ "features": [
+ "accelerated_2d_canvas"
+ ]
+ }
+ ]
+ }
+ );
+
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = 0x10de;
+ gpu_info.gpu.device_id = 0x0640;
+ manager.InitializeForTesting(blacklist_json, gpu_info);
+
+ EXPECT_TRUE(manager.GpuAccessAllowed(&reason));
+ EXPECT_TRUE(reason.empty());
+ EXPECT_EQ(1u, manager.GetBlacklistedFeatureCount());
+ EXPECT_TRUE(manager.IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL));
+
+ gpu_info.gl_vendor = "NVIDIA";
+ gpu_info.gl_renderer = "NVIDIA GeForce GT 120";
+ manager.UpdateGpuInfo(gpu_info);
+ EXPECT_FALSE(manager.GpuAccessAllowed(&reason));
+ EXPECT_FALSE(reason.empty());
+ EXPECT_EQ(2u, manager.GetBlacklistedFeatureCount());
+ EXPECT_TRUE(manager.IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL));
+ EXPECT_TRUE(manager.IsFeatureBlacklisted(
+ GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS));
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, GpuSideExceptions) {
+ GpuDataManagerImplPrivate manager;
+ EXPECT_EQ(0u, manager.GetBlacklistedFeatureCount());
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+
+ const std::string blacklist_json = LONG_STRING_CONST(
+ {
+ "name": "gpu blacklist",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "exceptions": [
+ {
+ "gl_renderer": {
+ "op": "contains",
+ "value": "GeForce"
+ }
+ }
+ ],
+ "features": [
+ "webgl"
+ ]
+ }
+ ]
+ }
+ );
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = 0x10de;
+ gpu_info.gpu.device_id = 0x0640;
+ manager.InitializeForTesting(blacklist_json, gpu_info);
+
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+ EXPECT_EQ(0u, manager.GetBlacklistedFeatureCount());
+
+ // Now assume gpu process launches and full GPU info is collected.
+ gpu_info.gl_renderer = "NVIDIA GeForce GT 120";
+ manager.UpdateGpuInfo(gpu_info);
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+ EXPECT_EQ(0u, manager.GetBlacklistedFeatureCount());
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, DisableHardwareAcceleration) {
+ GpuDataManagerImplPrivate manager;
+ EXPECT_EQ(0u, manager.GetBlacklistedFeatureCount());
+ std::string reason;
+ EXPECT_TRUE(manager.GpuAccessAllowed(&reason));
+ EXPECT_TRUE(reason.empty());
+
+ manager.DisableHardwareAcceleration();
+ EXPECT_FALSE(manager.GpuAccessAllowed(&reason));
+ EXPECT_FALSE(reason.empty());
+ EXPECT_EQ(static_cast<size_t>(NUMBER_OF_GPU_FEATURE_TYPES),
+ manager.GetBlacklistedFeatureCount());
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, SwiftShaderRendering) {
+ // Blacklist, then register SwiftShader.
+ GpuDataManagerImplPrivate manager;
+ EXPECT_EQ(0u, manager.GetBlacklistedFeatureCount());
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+ EXPECT_FALSE(manager.ShouldUseSwiftShader());
+
+ manager.DisableHardwareAcceleration();
+ EXPECT_FALSE(manager.GpuAccessAllowed(NULL));
+ EXPECT_FALSE(manager.ShouldUseSwiftShader());
+
+ // If SwiftShader is enabled, even if we blacklist GPU,
+ // GPU process is still allowed.
+ const base::FilePath test_path(FILE_PATH_LITERAL("AnyPath"));
+ manager.RegisterSwiftShaderPath(test_path);
+ EXPECT_TRUE(manager.ShouldUseSwiftShader());
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+ EXPECT_EQ(1u, manager.GetBlacklistedFeatureCount());
+ EXPECT_TRUE(
+ manager.IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS));
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, SwiftShaderRendering2) {
+ // Register SwiftShader, then blacklist.
+ GpuDataManagerImplPrivate manager;
+ EXPECT_EQ(0u, manager.GetBlacklistedFeatureCount());
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+ EXPECT_FALSE(manager.ShouldUseSwiftShader());
+
+ const base::FilePath test_path(FILE_PATH_LITERAL("AnyPath"));
+ manager.RegisterSwiftShaderPath(test_path);
+ EXPECT_EQ(0u, manager.GetBlacklistedFeatureCount());
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+ EXPECT_FALSE(manager.ShouldUseSwiftShader());
+
+ manager.DisableHardwareAcceleration();
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+ EXPECT_TRUE(manager.ShouldUseSwiftShader());
+ EXPECT_EQ(1u, manager.GetBlacklistedFeatureCount());
+ EXPECT_TRUE(
+ manager.IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS));
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, GpuInfoUpdate) {
+ GpuDataManagerImplPrivate manager;
+
+ TestObserver observer;
+ manager.AddObserver(&observer);
+
+ {
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+ }
+ EXPECT_FALSE(observer.gpu_info_updated());
+
+ GPUInfo gpu_info;
+ manager.UpdateGpuInfo(gpu_info);
+ {
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+ }
+ EXPECT_TRUE(observer.gpu_info_updated());
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, NoGpuInfoUpdateWithSwiftShader) {
+ GpuDataManagerImplPrivate manager;
+
+ manager.DisableHardwareAcceleration();
+ const base::FilePath test_path(FILE_PATH_LITERAL("AnyPath"));
+ manager.RegisterSwiftShaderPath(test_path);
+ EXPECT_TRUE(manager.ShouldUseSwiftShader());
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+
+ {
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+ }
+
+ TestObserver observer;
+ manager.AddObserver(&observer);
+ {
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+ }
+ EXPECT_FALSE(observer.gpu_info_updated());
+
+ GPUInfo gpu_info;
+ manager.UpdateGpuInfo(gpu_info);
+ {
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+ }
+ EXPECT_FALSE(observer.gpu_info_updated());
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, GPUVideoMemoryUsageStatsUpdate) {
+ GpuDataManagerImplPrivate manager;
+
+ TestObserver observer;
+ manager.AddObserver(&observer);
+
+ {
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+ }
+ EXPECT_FALSE(observer.video_memory_usage_stats_updated());
+
+ GPUVideoMemoryUsageStats vram_stats;
+ manager.UpdateVideoMemoryUsageStats(vram_stats);
+ {
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+ }
+ EXPECT_TRUE(observer.video_memory_usage_stats_updated());
+}
+
+base::Time GpuDataManagerImplPrivateTest::JustBeforeExpiration(
+ const GpuDataManagerImplPrivate& manager) {
+ return GetTimeForTesting() + base::TimeDelta::FromMilliseconds(
+ manager.GetBlockAllDomainsDurationInMs()) -
+ base::TimeDelta::FromMilliseconds(3);
+}
+
+base::Time GpuDataManagerImplPrivateTest::JustAfterExpiration(
+ const GpuDataManagerImplPrivate& manager) {
+ return GetTimeForTesting() + base::TimeDelta::FromMilliseconds(
+ manager.GetBlockAllDomainsDurationInMs()) +
+ base::TimeDelta::FromMilliseconds(3);
+}
+
+void GpuDataManagerImplPrivateTest::TestBlockingDomainFrom3DAPIs(
+ GpuDataManagerImpl::DomainGuilt guilt_level) {
+ GpuDataManagerImplPrivate manager;
+
+ manager.BlockDomainFrom3DAPIsAtTime(GetDomain1ForTesting(),
+ guilt_level,
+ GetTimeForTesting());
+
+ // This domain should be blocked no matter what.
+ EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED,
+ manager.Are3DAPIsBlockedAtTime(GetDomain1ForTesting(),
+ GetTimeForTesting()));
+ EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED,
+ manager.Are3DAPIsBlockedAtTime(
+ GetDomain1ForTesting(), JustBeforeExpiration(manager)));
+ EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED,
+ manager.Are3DAPIsBlockedAtTime(
+ GetDomain1ForTesting(), JustAfterExpiration(manager)));
+}
+
+void GpuDataManagerImplPrivateTest::TestUnblockingDomainFrom3DAPIs(
+ GpuDataManagerImpl::DomainGuilt guilt_level) {
+ GpuDataManagerImplPrivate manager;
+
+ manager.BlockDomainFrom3DAPIsAtTime(GetDomain1ForTesting(),
+ guilt_level,
+ GetTimeForTesting());
+
+ // Unblocking the domain should work.
+ manager.UnblockDomainFrom3DAPIs(GetDomain1ForTesting());
+ EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED,
+ manager.Are3DAPIsBlockedAtTime(GetDomain1ForTesting(),
+ GetTimeForTesting()));
+ EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED,
+ manager.Are3DAPIsBlockedAtTime(
+ GetDomain1ForTesting(), JustBeforeExpiration(manager)));
+ EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED,
+ manager.Are3DAPIsBlockedAtTime(
+ GetDomain1ForTesting(), JustAfterExpiration(manager)));
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, BlockGuiltyDomainFrom3DAPIs) {
+ TestBlockingDomainFrom3DAPIs(GpuDataManagerImpl::DOMAIN_GUILT_KNOWN);
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, BlockDomainOfUnknownGuiltFrom3DAPIs) {
+ TestBlockingDomainFrom3DAPIs(GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN);
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, BlockAllDomainsFrom3DAPIs) {
+ GpuDataManagerImplPrivate manager;
+
+ manager.BlockDomainFrom3DAPIsAtTime(GetDomain1ForTesting(),
+ GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN,
+ GetTimeForTesting());
+
+ // Blocking of other domains should expire.
+ EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
+ manager.Are3DAPIsBlockedAtTime(
+ GetDomain2ForTesting(), JustBeforeExpiration(manager)));
+ EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED,
+ manager.Are3DAPIsBlockedAtTime(
+ GetDomain2ForTesting(), JustAfterExpiration(manager)));
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, UnblockGuiltyDomainFrom3DAPIs) {
+ TestUnblockingDomainFrom3DAPIs(GpuDataManagerImpl::DOMAIN_GUILT_KNOWN);
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, UnblockDomainOfUnknownGuiltFrom3DAPIs) {
+ TestUnblockingDomainFrom3DAPIs(GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN);
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, UnblockOtherDomainFrom3DAPIs) {
+ GpuDataManagerImplPrivate manager;
+
+ manager.BlockDomainFrom3DAPIsAtTime(GetDomain1ForTesting(),
+ GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN,
+ GetTimeForTesting());
+
+ manager.UnblockDomainFrom3DAPIs(GetDomain2ForTesting());
+
+ EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED,
+ manager.Are3DAPIsBlockedAtTime(
+ GetDomain2ForTesting(), JustBeforeExpiration(manager)));
+
+ // The original domain should still be blocked.
+ EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED,
+ manager.Are3DAPIsBlockedAtTime(
+ GetDomain1ForTesting(), JustBeforeExpiration(manager)));
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, UnblockThisDomainFrom3DAPIs) {
+ GpuDataManagerImplPrivate manager;
+
+ manager.BlockDomainFrom3DAPIsAtTime(GetDomain1ForTesting(),
+ GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN,
+ GetTimeForTesting());
+
+ manager.UnblockDomainFrom3DAPIs(GetDomain1ForTesting());
+
+ // This behavior is debatable. Perhaps the GPU reset caused by
+ // domain 1 should still cause other domains to be blocked.
+ EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED,
+ manager.Are3DAPIsBlockedAtTime(
+ GetDomain2ForTesting(), JustBeforeExpiration(manager)));
+}
+
+#if defined(OS_LINUX)
+TEST_F(GpuDataManagerImplPrivateTest, SetGLStrings) {
+ const char* kGLVendorMesa = "Tungsten Graphics, Inc";
+ const char* kGLRendererMesa = "Mesa DRI Intel(R) G41";
+ const char* kGLVersionMesa801 = "2.1 Mesa 8.0.1-DEVEL";
+
+ GpuDataManagerImplPrivate manager;
+ EXPECT_EQ(0u, manager.GetBlacklistedFeatureCount());
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+
+ const std::string blacklist_json = LONG_STRING_CONST(
+ {
+ "name": "gpu blacklist",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "vendor_id": "0x8086",
+ "exceptions": [
+ {
+ "device_id": ["0x0042"],
+ "driver_version": {
+ "op": ">=",
+ "number": "8.0.2"
+ }
+ }
+ ],
+ "features": [
+ "webgl"
+ ]
+ }
+ ]
+ }
+ );
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = 0x8086;
+ gpu_info.gpu.device_id = 0x0042;
+ manager.InitializeForTesting(blacklist_json, gpu_info);
+
+ // Not enough GPUInfo.
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+ EXPECT_EQ(0u, manager.GetBlacklistedFeatureCount());
+
+ // Now assume browser gets GL strings from local state.
+ // The entry applies, blacklist more features than from the preliminary step.
+ // However, GPU process is not blocked because this is all browser side and
+ // happens before renderer launching.
+ manager.SetGLStrings(kGLVendorMesa, kGLRendererMesa, kGLVersionMesa801);
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+ EXPECT_EQ(1u, manager.GetBlacklistedFeatureCount());
+ EXPECT_TRUE(manager.IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL));
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, SetGLStringsNoEffects) {
+ const char* kGLVendorMesa = "Tungsten Graphics, Inc";
+ const char* kGLRendererMesa = "Mesa DRI Intel(R) G41";
+ const char* kGLVersionMesa801 = "2.1 Mesa 8.0.1-DEVEL";
+ const char* kGLVersionMesa802 = "2.1 Mesa 8.0.2-DEVEL";
+
+ GpuDataManagerImplPrivate manager;
+ EXPECT_EQ(0u, manager.GetBlacklistedFeatureCount());
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+
+ const std::string blacklist_json = LONG_STRING_CONST(
+ {
+ "name": "gpu blacklist",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "vendor_id": "0x8086",
+ "exceptions": [
+ {
+ "device_id": ["0x0042"],
+ "driver_version": {
+ "op": ">=",
+ "number": "8.0.2"
+ }
+ }
+ ],
+ "features": [
+ "webgl"
+ ]
+ }
+ ]
+ }
+ );
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = 0x8086;
+ gpu_info.gpu.device_id = 0x0042;
+ gpu_info.gl_vendor = kGLVendorMesa;
+ gpu_info.gl_renderer = kGLRendererMesa;
+ gpu_info.gl_version = kGLVersionMesa801;
+ gpu_info.driver_vendor = "Mesa";
+ gpu_info.driver_version = "8.0.1";
+ manager.InitializeForTesting(blacklist_json, gpu_info);
+
+ // Full GPUInfo, the entry applies.
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+ EXPECT_EQ(1u, manager.GetBlacklistedFeatureCount());
+ EXPECT_TRUE(manager.IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL));
+
+ // Now assume browser gets GL strings from local state.
+ // SetGLStrings() has no effects because GPUInfo already got these strings.
+ // (Otherwise the entry should not apply.)
+ manager.SetGLStrings(kGLVendorMesa, kGLRendererMesa, kGLVersionMesa802);
+ EXPECT_TRUE(manager.GpuAccessAllowed(NULL));
+ EXPECT_EQ(1u, manager.GetBlacklistedFeatureCount());
+ EXPECT_TRUE(manager.IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL));
+}
+#endif // OS_LINUX
+
+TEST_F(GpuDataManagerImplPrivateTest, GpuDriverBugListSingle) {
+ GpuDataManagerImplPrivate manager;
+ manager.gpu_driver_bugs_.insert(5);
+
+ CommandLine command_line(0, NULL);
+ manager.AppendGpuCommandLine(&command_line);
+
+ EXPECT_TRUE(command_line.HasSwitch(switches::kGpuDriverBugWorkarounds));
+ std::string args = command_line.GetSwitchValueASCII(
+ switches::kGpuDriverBugWorkarounds);
+ EXPECT_STREQ("5", args.c_str());
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, GpuDriverBugListMultiple) {
+ GpuDataManagerImplPrivate manager;
+ manager.gpu_driver_bugs_.insert(5);
+ manager.gpu_driver_bugs_.insert(7);
+
+ CommandLine command_line(0, NULL);
+ manager.AppendGpuCommandLine(&command_line);
+
+ EXPECT_TRUE(command_line.HasSwitch(switches::kGpuDriverBugWorkarounds));
+ std::string args = command_line.GetSwitchValueASCII(
+ switches::kGpuDriverBugWorkarounds);
+ EXPECT_STREQ("5,7", args.c_str());
+}
+
+TEST_F(GpuDataManagerImplPrivateTest, BlacklistAllFeatures) {
+ GpuDataManagerImplPrivate manager;
+ EXPECT_EQ(0u, manager.GetBlacklistedFeatureCount());
+ std::string reason;
+ EXPECT_TRUE(manager.GpuAccessAllowed(&reason));
+ EXPECT_TRUE(reason.empty());
+
+ const std::string blacklist_json = LONG_STRING_CONST(
+ {
+ "name": "gpu blacklist",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "features": [
+ "all"
+ ]
+ }
+ ]
+ }
+ );
+
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = 0x10de;
+ gpu_info.gpu.device_id = 0x0640;
+ manager.InitializeForTesting(blacklist_json, gpu_info);
+
+ EXPECT_EQ(static_cast<size_t>(NUMBER_OF_GPU_FEATURE_TYPES),
+ manager.GetBlacklistedFeatureCount());
+ // TODO(zmo): remove the Linux specific behavior once we fix
+ // crbug.com/238466.
+#if defined(OS_LINUX)
+ EXPECT_TRUE(manager.GpuAccessAllowed(&reason));
+ EXPECT_TRUE(reason.empty());
+#else
+ EXPECT_FALSE(manager.GpuAccessAllowed(&reason));
+ EXPECT_FALSE(reason.empty());
+#endif
+}
+
+} // namespace content
diff --git a/content/browser/gpu/gpu_data_manager_impl_unittest.cc b/content/browser/gpu/gpu_data_manager_impl_unittest.cc
deleted file mode 100644
index 7d15bba..0000000
--- a/content/browser/gpu/gpu_data_manager_impl_unittest.cc
+++ /dev/null
@@ -1,656 +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 "base/command_line.h"
-#include "base/message_loop.h"
-#include "base/run_loop.h"
-#include "base/time.h"
-#include "content/browser/gpu/gpu_data_manager_impl.h"
-#include "content/public/browser/gpu_data_manager_observer.h"
-#include "content/public/common/gpu_feature_type.h"
-#include "content/public/common/gpu_info.h"
-#include "googleurl/src/gurl.h"
-#include "gpu/command_buffer/service/gpu_switches.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#define LONG_STRING_CONST(...) #__VA_ARGS__
-
-namespace content {
-namespace {
-
-class TestObserver : public GpuDataManagerObserver {
- public:
- TestObserver()
- : gpu_info_updated_(false),
- video_memory_usage_stats_updated_(false) {
- }
- virtual ~TestObserver() { }
-
- bool gpu_info_updated() const { return gpu_info_updated_; }
- bool video_memory_usage_stats_updated() const {
- return video_memory_usage_stats_updated_;
- }
-
- virtual void OnGpuInfoUpdate() OVERRIDE {
- gpu_info_updated_ = true;
- }
-
- virtual void OnVideoMemoryUsageStatsUpdate(
- const GPUVideoMemoryUsageStats& stats) OVERRIDE {
- video_memory_usage_stats_updated_ = true;
- }
-
- private:
- bool gpu_info_updated_;
- bool video_memory_usage_stats_updated_;
-};
-
-static base::Time GetTimeForTesting() {
- return base::Time::FromDoubleT(1000);
-}
-
-static GURL GetDomain1ForTesting() {
- return GURL("http://foo.com/");
-}
-
-static GURL GetDomain2ForTesting() {
- return GURL("http://bar.com/");
-}
-
-} // namespace anonymous
-
-class GpuDataManagerImplTest : public testing::Test {
- public:
- GpuDataManagerImplTest() { }
-
- virtual ~GpuDataManagerImplTest() { }
-
- protected:
- // scoped_ptr doesn't work with GpuDataManagerImpl because its
- // destructor is private. GpuDataManagerImplTest is however a friend
- // so we can make a little helper class here.
- class ScopedGpuDataManagerImpl {
- public:
- ScopedGpuDataManagerImpl() : impl_(new GpuDataManagerImpl()) {}
- ~ScopedGpuDataManagerImpl() { delete impl_; }
-
- GpuDataManagerImpl* get() const { return impl_; }
- GpuDataManagerImpl* operator->() const { return impl_; }
- // Small violation of C++ style guide to avoid polluting several
- // tests with get() calls.
- operator GpuDataManagerImpl*() { return impl_; }
-
- private:
- GpuDataManagerImpl* impl_;
- DISALLOW_COPY_AND_ASSIGN(ScopedGpuDataManagerImpl);
- };
-
- virtual void SetUp() {
- }
-
- virtual void TearDown() {
- }
-
- base::Time JustBeforeExpiration(GpuDataManagerImpl* manager);
- base::Time JustAfterExpiration(GpuDataManagerImpl* manager);
- void TestBlockingDomainFrom3DAPIs(
- GpuDataManagerImpl::DomainGuilt guilt_level);
- void TestUnblockingDomainFrom3DAPIs(
- GpuDataManagerImpl::DomainGuilt guilt_level);
-
- base::MessageLoop message_loop_;
-};
-
-// We use new method instead of GetInstance() method because we want
-// each test to be independent of each other.
-
-TEST_F(GpuDataManagerImplTest, GpuSideBlacklisting) {
- // If a feature is allowed in preliminary step (browser side), but
- // disabled when GPU process launches and collects full GPU info,
- // it's too late to let renderer know, so we basically block all GPU
- // access, to be on the safe side.
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
- EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
- std::string reason;
- EXPECT_TRUE(manager->GpuAccessAllowed(&reason));
- EXPECT_TRUE(reason.empty());
-
- const std::string blacklist_json = LONG_STRING_CONST(
- {
- "name": "gpu blacklist",
- "version": "0.1",
- "entries": [
- {
- "id": 1,
- "features": [
- "webgl"
- ]
- },
- {
- "id": 2,
- "gl_renderer": {
- "op": "contains",
- "value": "GeForce"
- },
- "features": [
- "accelerated_2d_canvas"
- ]
- }
- ]
- }
- );
-
- GPUInfo gpu_info;
- gpu_info.gpu.vendor_id = 0x10de;
- gpu_info.gpu.device_id = 0x0640;
- manager->InitializeForTesting(blacklist_json, gpu_info);
-
- EXPECT_TRUE(manager->GpuAccessAllowed(&reason));
- EXPECT_TRUE(reason.empty());
- EXPECT_EQ(1u, manager->GetBlacklistedFeatureCount());
- EXPECT_TRUE(manager->IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL));
-
- gpu_info.gl_vendor = "NVIDIA";
- gpu_info.gl_renderer = "NVIDIA GeForce GT 120";
- manager->UpdateGpuInfo(gpu_info);
- EXPECT_FALSE(manager->GpuAccessAllowed(&reason));
- EXPECT_FALSE(reason.empty());
- EXPECT_EQ(2u, manager->GetBlacklistedFeatureCount());
- EXPECT_TRUE(manager->IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL));
- EXPECT_TRUE(manager->IsFeatureBlacklisted(
- GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS));
-}
-
-TEST_F(GpuDataManagerImplTest, GpuSideExceptions) {
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
- EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
-
- const std::string blacklist_json = LONG_STRING_CONST(
- {
- "name": "gpu blacklist",
- "version": "0.1",
- "entries": [
- {
- "id": 1,
- "exceptions": [
- {
- "gl_renderer": {
- "op": "contains",
- "value": "GeForce"
- }
- }
- ],
- "features": [
- "webgl"
- ]
- }
- ]
- }
- );
- GPUInfo gpu_info;
- gpu_info.gpu.vendor_id = 0x10de;
- gpu_info.gpu.device_id = 0x0640;
- manager->InitializeForTesting(blacklist_json, gpu_info);
-
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
- EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
-
- // Now assume gpu process launches and full GPU info is collected.
- gpu_info.gl_renderer = "NVIDIA GeForce GT 120";
- manager->UpdateGpuInfo(gpu_info);
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
- EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
-}
-
-TEST_F(GpuDataManagerImplTest, DisableHardwareAcceleration) {
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
- EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
- std::string reason;
- EXPECT_TRUE(manager->GpuAccessAllowed(&reason));
- EXPECT_TRUE(reason.empty());
-
- manager->DisableHardwareAcceleration();
- EXPECT_FALSE(manager->GpuAccessAllowed(&reason));
- EXPECT_FALSE(reason.empty());
- EXPECT_EQ(static_cast<size_t>(NUMBER_OF_GPU_FEATURE_TYPES),
- manager->GetBlacklistedFeatureCount());
-}
-
-TEST_F(GpuDataManagerImplTest, SwiftShaderRendering) {
- // Blacklist, then register SwiftShader.
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
- EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
- EXPECT_FALSE(manager->ShouldUseSwiftShader());
-
- manager->DisableHardwareAcceleration();
- EXPECT_FALSE(manager->GpuAccessAllowed(NULL));
- EXPECT_FALSE(manager->ShouldUseSwiftShader());
-
- // If SwiftShader is enabled, even if we blacklist GPU,
- // GPU process is still allowed.
- const base::FilePath test_path(FILE_PATH_LITERAL("AnyPath"));
- manager->RegisterSwiftShaderPath(test_path);
- EXPECT_TRUE(manager->ShouldUseSwiftShader());
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
- EXPECT_EQ(1u, manager->GetBlacklistedFeatureCount());
- EXPECT_TRUE(
- manager->IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS));
-}
-
-TEST_F(GpuDataManagerImplTest, SwiftShaderRendering2) {
- // Register SwiftShader, then blacklist.
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
- EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
- EXPECT_FALSE(manager->ShouldUseSwiftShader());
-
- const base::FilePath test_path(FILE_PATH_LITERAL("AnyPath"));
- manager->RegisterSwiftShaderPath(test_path);
- EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
- EXPECT_FALSE(manager->ShouldUseSwiftShader());
-
- manager->DisableHardwareAcceleration();
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
- EXPECT_TRUE(manager->ShouldUseSwiftShader());
- EXPECT_EQ(1u, manager->GetBlacklistedFeatureCount());
- EXPECT_TRUE(
- manager->IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS));
-}
-
-TEST_F(GpuDataManagerImplTest, GpuInfoUpdate) {
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
-
- TestObserver observer;
- manager->AddObserver(&observer);
-
- {
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
- EXPECT_FALSE(observer.gpu_info_updated());
-
- GPUInfo gpu_info;
- manager->UpdateGpuInfo(gpu_info);
- {
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
- EXPECT_TRUE(observer.gpu_info_updated());
-}
-
-TEST_F(GpuDataManagerImplTest, NoGpuInfoUpdateWithSwiftShader) {
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
-
- manager->DisableHardwareAcceleration();
- const base::FilePath test_path(FILE_PATH_LITERAL("AnyPath"));
- manager->RegisterSwiftShaderPath(test_path);
- EXPECT_TRUE(manager->ShouldUseSwiftShader());
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
-
- {
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
-
- TestObserver observer;
- manager->AddObserver(&observer);
- {
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
- EXPECT_FALSE(observer.gpu_info_updated());
-
- GPUInfo gpu_info;
- manager->UpdateGpuInfo(gpu_info);
- {
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
- EXPECT_FALSE(observer.gpu_info_updated());
-}
-
-TEST_F(GpuDataManagerImplTest, GPUVideoMemoryUsageStatsUpdate) {
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
-
- TestObserver observer;
- manager->AddObserver(&observer);
-
- {
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
- EXPECT_FALSE(observer.video_memory_usage_stats_updated());
-
- GPUVideoMemoryUsageStats vram_stats;
- manager->UpdateVideoMemoryUsageStats(vram_stats);
- {
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
- EXPECT_TRUE(observer.video_memory_usage_stats_updated());
-}
-
-base::Time GpuDataManagerImplTest::JustBeforeExpiration(
- GpuDataManagerImpl* manager) {
- return GetTimeForTesting() + base::TimeDelta::FromMilliseconds(
- manager->GetBlockAllDomainsDurationInMs()) -
- base::TimeDelta::FromMilliseconds(3);
-}
-
-base::Time GpuDataManagerImplTest::JustAfterExpiration(
- GpuDataManagerImpl* manager) {
- return GetTimeForTesting() + base::TimeDelta::FromMilliseconds(
- manager->GetBlockAllDomainsDurationInMs()) +
- base::TimeDelta::FromMilliseconds(3);
-}
-
-void GpuDataManagerImplTest::TestBlockingDomainFrom3DAPIs(
- GpuDataManagerImpl::DomainGuilt guilt_level) {
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
-
- manager->BlockDomainFrom3DAPIsAtTime(GetDomain1ForTesting(),
- guilt_level,
- GetTimeForTesting());
-
- // This domain should be blocked no matter what.
- EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED,
- manager->Are3DAPIsBlockedAtTime(GetDomain1ForTesting(),
- GetTimeForTesting()));
- EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED,
- manager->Are3DAPIsBlockedAtTime(GetDomain1ForTesting(),
- JustBeforeExpiration(manager)));
- EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED,
- manager->Are3DAPIsBlockedAtTime(GetDomain1ForTesting(),
- JustAfterExpiration(manager)));
-}
-
-void GpuDataManagerImplTest::TestUnblockingDomainFrom3DAPIs(
- GpuDataManagerImpl::DomainGuilt guilt_level) {
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
-
- manager->BlockDomainFrom3DAPIsAtTime(GetDomain1ForTesting(),
- guilt_level,
- GetTimeForTesting());
-
- // Unblocking the domain should work.
- manager->UnblockDomainFrom3DAPIs(GetDomain1ForTesting());
- EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED,
- manager->Are3DAPIsBlockedAtTime(GetDomain1ForTesting(),
- GetTimeForTesting()));
- EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED,
- manager->Are3DAPIsBlockedAtTime(GetDomain1ForTesting(),
- JustBeforeExpiration(manager)));
- EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED,
- manager->Are3DAPIsBlockedAtTime(GetDomain1ForTesting(),
- JustAfterExpiration(manager)));
-}
-
-TEST_F(GpuDataManagerImplTest, BlockGuiltyDomainFrom3DAPIs) {
- TestBlockingDomainFrom3DAPIs(GpuDataManagerImpl::DOMAIN_GUILT_KNOWN);
-}
-
-TEST_F(GpuDataManagerImplTest, BlockDomainOfUnknownGuiltFrom3DAPIs) {
- TestBlockingDomainFrom3DAPIs(GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN);
-}
-
-TEST_F(GpuDataManagerImplTest, BlockAllDomainsFrom3DAPIs) {
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
-
- manager->BlockDomainFrom3DAPIsAtTime(GetDomain1ForTesting(),
- GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN,
- GetTimeForTesting());
-
- // Blocking of other domains should expire.
- EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
- manager->Are3DAPIsBlockedAtTime(GetDomain2ForTesting(),
- JustBeforeExpiration(manager)));
- EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED,
- manager->Are3DAPIsBlockedAtTime(GetDomain2ForTesting(),
- JustAfterExpiration(manager)));
-}
-
-TEST_F(GpuDataManagerImplTest, UnblockGuiltyDomainFrom3DAPIs) {
- TestUnblockingDomainFrom3DAPIs(GpuDataManagerImpl::DOMAIN_GUILT_KNOWN);
-}
-
-TEST_F(GpuDataManagerImplTest, UnblockDomainOfUnknownGuiltFrom3DAPIs) {
- TestUnblockingDomainFrom3DAPIs(GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN);
-}
-
-TEST_F(GpuDataManagerImplTest, UnblockOtherDomainFrom3DAPIs) {
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
-
- manager->BlockDomainFrom3DAPIsAtTime(GetDomain1ForTesting(),
- GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN,
- GetTimeForTesting());
-
- manager->UnblockDomainFrom3DAPIs(GetDomain2ForTesting());
-
- EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED,
- manager->Are3DAPIsBlockedAtTime(GetDomain2ForTesting(),
- JustBeforeExpiration(manager)));
-
- // The original domain should still be blocked.
- EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED,
- manager->Are3DAPIsBlockedAtTime(GetDomain1ForTesting(),
- JustBeforeExpiration(manager)));
-}
-
-TEST_F(GpuDataManagerImplTest, UnblockThisDomainFrom3DAPIs) {
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
-
- manager->BlockDomainFrom3DAPIsAtTime(GetDomain1ForTesting(),
- GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN,
- GetTimeForTesting());
-
- manager->UnblockDomainFrom3DAPIs(GetDomain1ForTesting());
-
- // This behavior is debatable. Perhaps the GPU reset caused by
- // domain 1 should still cause other domains to be blocked.
- EXPECT_EQ(GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED,
- manager->Are3DAPIsBlockedAtTime(GetDomain2ForTesting(),
- JustBeforeExpiration(manager)));
-}
-
-#if defined(OS_LINUX)
-TEST_F(GpuDataManagerImplTest, SetGLStrings) {
- const char* kGLVendorMesa = "Tungsten Graphics, Inc";
- const char* kGLRendererMesa = "Mesa DRI Intel(R) G41";
- const char* kGLVersionMesa801 = "2.1 Mesa 8.0.1-DEVEL";
-
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
- EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
-
- const std::string blacklist_json = LONG_STRING_CONST(
- {
- "name": "gpu blacklist",
- "version": "0.1",
- "entries": [
- {
- "id": 1,
- "vendor_id": "0x8086",
- "exceptions": [
- {
- "device_id": ["0x0042"],
- "driver_version": {
- "op": ">=",
- "number": "8.0.2"
- }
- }
- ],
- "features": [
- "webgl"
- ]
- }
- ]
- }
- );
- GPUInfo gpu_info;
- gpu_info.gpu.vendor_id = 0x8086;
- gpu_info.gpu.device_id = 0x0042;
- manager->InitializeForTesting(blacklist_json, gpu_info);
-
- // Not enough GPUInfo.
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
- EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
-
- // Now assume browser gets GL strings from local state.
- // The entry applies, blacklist more features than from the preliminary step.
- // However, GPU process is not blocked because this is all browser side and
- // happens before renderer launching.
- manager->SetGLStrings(kGLVendorMesa, kGLRendererMesa, kGLVersionMesa801);
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
- EXPECT_EQ(1u, manager->GetBlacklistedFeatureCount());
- EXPECT_TRUE(manager->IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL));
-}
-
-TEST_F(GpuDataManagerImplTest, SetGLStringsNoEffects) {
- const char* kGLVendorMesa = "Tungsten Graphics, Inc";
- const char* kGLRendererMesa = "Mesa DRI Intel(R) G41";
- const char* kGLVersionMesa801 = "2.1 Mesa 8.0.1-DEVEL";
- const char* kGLVersionMesa802 = "2.1 Mesa 8.0.2-DEVEL";
-
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
- EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
-
- const std::string blacklist_json = LONG_STRING_CONST(
- {
- "name": "gpu blacklist",
- "version": "0.1",
- "entries": [
- {
- "id": 1,
- "vendor_id": "0x8086",
- "exceptions": [
- {
- "device_id": ["0x0042"],
- "driver_version": {
- "op": ">=",
- "number": "8.0.2"
- }
- }
- ],
- "features": [
- "webgl"
- ]
- }
- ]
- }
- );
- GPUInfo gpu_info;
- gpu_info.gpu.vendor_id = 0x8086;
- gpu_info.gpu.device_id = 0x0042;
- gpu_info.gl_vendor = kGLVendorMesa;
- gpu_info.gl_renderer = kGLRendererMesa;
- gpu_info.gl_version = kGLVersionMesa801;
- gpu_info.driver_vendor = "Mesa";
- gpu_info.driver_version = "8.0.1";
- manager->InitializeForTesting(blacklist_json, gpu_info);
-
- // Full GPUInfo, the entry applies.
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
- EXPECT_EQ(1u, manager->GetBlacklistedFeatureCount());
- EXPECT_TRUE(manager->IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL));
-
- // Now assume browser gets GL strings from local state.
- // SetGLStrings() has no effects because GPUInfo already got these strings.
- // (Otherwise the entry should not apply.)
- manager->SetGLStrings(kGLVendorMesa, kGLRendererMesa, kGLVersionMesa802);
- EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
- EXPECT_EQ(1u, manager->GetBlacklistedFeatureCount());
- EXPECT_TRUE(manager->IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL));
-}
-#endif // OS_LINUX
-
-TEST_F(GpuDataManagerImplTest, GpuDriverBugListSingle) {
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
- manager->gpu_driver_bugs_.insert(5);
-
- CommandLine command_line(0, NULL);
- manager->AppendGpuCommandLine(&command_line);
-
- EXPECT_TRUE(command_line.HasSwitch(switches::kGpuDriverBugWorkarounds));
- std::string args = command_line.GetSwitchValueASCII(
- switches::kGpuDriverBugWorkarounds);
- EXPECT_STREQ("5", args.c_str());
-}
-
-TEST_F(GpuDataManagerImplTest, GpuDriverBugListMultiple) {
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
- manager->gpu_driver_bugs_.insert(5);
- manager->gpu_driver_bugs_.insert(7);
-
- CommandLine command_line(0, NULL);
- manager->AppendGpuCommandLine(&command_line);
-
- EXPECT_TRUE(command_line.HasSwitch(switches::kGpuDriverBugWorkarounds));
- std::string args = command_line.GetSwitchValueASCII(
- switches::kGpuDriverBugWorkarounds);
- EXPECT_STREQ("5,7", args.c_str());
-}
-
-TEST_F(GpuDataManagerImplTest, BlacklistAllFeatures) {
- ScopedGpuDataManagerImpl manager;
- ASSERT_TRUE(manager.get());
- EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
- std::string reason;
- EXPECT_TRUE(manager->GpuAccessAllowed(&reason));
- EXPECT_TRUE(reason.empty());
-
- const std::string blacklist_json = LONG_STRING_CONST(
- {
- "name": "gpu blacklist",
- "version": "0.1",
- "entries": [
- {
- "id": 1,
- "features": [
- "all"
- ]
- }
- ]
- }
- );
-
- GPUInfo gpu_info;
- gpu_info.gpu.vendor_id = 0x10de;
- gpu_info.gpu.device_id = 0x0640;
- manager->InitializeForTesting(blacklist_json, gpu_info);
-
- EXPECT_EQ(static_cast<size_t>(NUMBER_OF_GPU_FEATURE_TYPES),
- manager->GetBlacklistedFeatureCount());
- // TODO(zmo): remove the Linux specific behavior once we fix
- // crbug.com/238466.
-#if defined(OS_LINUX)
- EXPECT_TRUE(manager->GpuAccessAllowed(&reason));
- EXPECT_TRUE(reason.empty());
-#else
- EXPECT_FALSE(manager->GpuAccessAllowed(&reason));
- EXPECT_FALSE(reason.empty());
-#endif
-}
-
-} // namespace content
diff --git a/content/browser/gpu/gpu_internals_ui.cc b/content/browser/gpu/gpu_internals_ui.cc
index eb7646c..6419ba8 100644
--- a/content/browser/gpu/gpu_internals_ui.cc
+++ b/content/browser/gpu/gpu_internals_ui.cc
@@ -479,9 +479,7 @@ class GpuMessageHandler
// GpuDataManagerObserver implementation.
virtual void OnGpuInfoUpdate() OVERRIDE;
-
- // Gpu switch handler.
- void OnGpuSwitch();
+ virtual void OnGpuSwitching() OVERRIDE;
// Messages
void OnBrowserBridgeInitialized(const base::ListValue* list);
@@ -496,8 +494,6 @@ class GpuMessageHandler
// DCHECK).
bool observing_;
- GpuDataManagerImpl::GpuSwitchCallback gpu_switch_callback_;
-
DISALLOW_COPY_AND_ASSIGN(GpuMessageHandler);
};
@@ -508,15 +504,11 @@ class GpuMessageHandler
////////////////////////////////////////////////////////////////////////////////
GpuMessageHandler::GpuMessageHandler()
- : observing_(false),
- gpu_switch_callback_(base::Bind(&GpuMessageHandler::OnGpuSwitch,
- base::Unretained(this))) {
+ : observing_(false) {
}
GpuMessageHandler::~GpuMessageHandler() {
GpuDataManagerImpl::GetInstance()->RemoveObserver(this);
- GpuDataManagerImpl::GetInstance()->RemoveGpuSwitchCallback(
- gpu_switch_callback_);
}
/* BrowserBridge.callAsync prepends a requestID to these messages. */
@@ -583,11 +575,8 @@ void GpuMessageHandler::OnBrowserBridgeInitialized(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Watch for changes in GPUInfo
- if (!observing_) {
+ if (!observing_)
GpuDataManagerImpl::GetInstance()->AddObserver(this);
- GpuDataManagerImpl::GetInstance()->AddGpuSwitchCallback(
- gpu_switch_callback_);
- }
observing_ = true;
// Tell GpuDataManager it should have full GpuInfo. If the
@@ -639,7 +628,7 @@ void GpuMessageHandler::OnGpuInfoUpdate() {
*(gpu_info_val.get()));
}
-void GpuMessageHandler::OnGpuSwitch() {
+void GpuMessageHandler::OnGpuSwitching() {
GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded();
}