summaryrefslogtreecommitdiff
path: root/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/gpu/gpu_data_manager_impl_private.cc')
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl_private.cc1254
1 files changed, 1254 insertions, 0 deletions
diff --git a/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc b/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc
new file mode 100644
index 00000000000..8491508667d
--- /dev/null
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -0,0 +1,1254 @@
+// 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"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_info.h"
+#include "base/version.h"
+#include "cc/base/switches.h"
+#include "content/browser/gpu/gpu_process_host.h"
+#include "content/common/gpu/gpu_messages.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 "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/config/gpu_control_list_jsons.h"
+#include "gpu/config/gpu_driver_bug_workaround_type.h"
+#include "gpu/config/gpu_feature_type.h"
+#include "gpu/config/gpu_info_collector.h"
+#include "gpu/config/gpu_util.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/common/webpreferences.h"
+
+#if defined(OS_MACOSX)
+#include <ApplicationServices/ApplicationServices.h>
+#endif // OS_MACOSX
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif // OS_WIN
+#if defined(OS_ANDROID)
+#include "ui/gfx/android/device_display_info.h"
+#endif // OS_ANDROID
+
+namespace content {
+
+namespace {
+
+enum GpuFeatureStatus {
+ kGpuFeatureEnabled = 0,
+ kGpuFeatureBlacklisted = 1,
+ kGpuFeatureDisabled = 2, // disabled by user but not blacklisted
+ kGpuFeatureNumStatus
+};
+
+#if defined(OS_WIN)
+
+enum WinSubVersion {
+ kWinOthers = 0,
+ kWinXP,
+ kWinVista,
+ kWin7,
+ kWin8,
+ kNumWinSubVersions
+};
+
+int GetGpuBlacklistHistogramValueWin(GpuFeatureStatus status) {
+ static WinSubVersion sub_version = kNumWinSubVersions;
+ if (sub_version == kNumWinSubVersions) {
+ sub_version = kWinOthers;
+ std::string version_str = base::SysInfo::OperatingSystemVersion();
+ size_t pos = version_str.find_first_not_of("0123456789.");
+ if (pos != std::string::npos)
+ version_str = version_str.substr(0, pos);
+ Version os_version(version_str);
+ if (os_version.IsValid() && os_version.components().size() >= 2) {
+ const std::vector<uint16>& version_numbers = os_version.components();
+ if (version_numbers[0] == 5)
+ sub_version = kWinXP;
+ else if (version_numbers[0] == 6 && version_numbers[1] == 0)
+ sub_version = kWinVista;
+ else if (version_numbers[0] == 6 && version_numbers[1] == 1)
+ sub_version = kWin7;
+ else if (version_numbers[0] == 6 && version_numbers[1] == 2)
+ sub_version = kWin8;
+ }
+ }
+ int entry_index = static_cast<int>(sub_version) * kGpuFeatureNumStatus;
+ switch (status) {
+ case kGpuFeatureEnabled:
+ break;
+ case kGpuFeatureBlacklisted:
+ entry_index++;
+ break;
+ case kGpuFeatureDisabled:
+ entry_index += 2;
+ break;
+ }
+ return entry_index;
+}
+#endif // OS_WIN
+
+// Send UMA histograms about the enabled features and GPU properties.
+void UpdateStats(const gpu::GPUInfo& gpu_info,
+ const gpu::GpuBlacklist* blacklist,
+ const std::set<int>& blacklisted_features) {
+ uint32 max_entry_id = blacklist->max_entry_id();
+ if (max_entry_id == 0) {
+ // GPU Blacklist was not loaded. No need to go further.
+ return;
+ }
+
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ bool disabled = false;
+
+ // Use entry 0 to capture the total number of times that data
+ // was recorded in this histogram in order to have a convenient
+ // denominator to compute blacklist percentages for the rest of the
+ // entries.
+ UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
+ 0, max_entry_id + 1);
+
+ if (blacklisted_features.size() != 0) {
+ std::vector<uint32> flag_entries;
+ blacklist->GetDecisionEntries(&flag_entries, disabled);
+ DCHECK_GT(flag_entries.size(), 0u);
+ for (size_t i = 0; i < flag_entries.size(); ++i) {
+ UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
+ flag_entries[i], max_entry_id + 1);
+ }
+ }
+
+ // This counts how many users are affected by a disabled entry - this allows
+ // us to understand the impact of an entry before enable it.
+ std::vector<uint32> flag_disabled_entries;
+ disabled = true;
+ blacklist->GetDecisionEntries(&flag_disabled_entries, disabled);
+ for (size_t i = 0; i < flag_disabled_entries.size(); ++i) {
+ UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerDisabledEntry",
+ flag_disabled_entries[i], max_entry_id + 1);
+ }
+
+ const gpu::GpuFeatureType kGpuFeatures[] = {
+ gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS,
+ gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING,
+ gpu::GPU_FEATURE_TYPE_WEBGL,
+ gpu::GPU_FEATURE_TYPE_TEXTURE_SHARING
+ };
+ const std::string kGpuBlacklistFeatureHistogramNames[] = {
+ "GPU.BlacklistFeatureTestResults.Accelerated2dCanvas",
+ "GPU.BlacklistFeatureTestResults.AcceleratedCompositing",
+ "GPU.BlacklistFeatureTestResults.Webgl",
+ "GPU.BlacklistFeatureTestResults.TextureSharing"
+ };
+ const bool kGpuFeatureUserFlags[] = {
+ command_line.HasSwitch(switches::kDisableAccelerated2dCanvas),
+ command_line.HasSwitch(switches::kDisableAcceleratedCompositing),
+ command_line.HasSwitch(switches::kDisableExperimentalWebGL),
+ command_line.HasSwitch(switches::kDisableImageTransportSurface)
+ };
+#if defined(OS_WIN)
+ const std::string kGpuBlacklistFeatureHistogramNamesWin[] = {
+ "GPU.BlacklistFeatureTestResultsWindows.Accelerated2dCanvas",
+ "GPU.BlacklistFeatureTestResultsWindows.AcceleratedCompositing",
+ "GPU.BlacklistFeatureTestResultsWindows.Webgl",
+ "GPU.BlacklistFeatureTestResultsWindows.TextureSharing"
+ };
+#endif
+ const size_t kNumFeatures =
+ sizeof(kGpuFeatures) / sizeof(gpu::GpuFeatureType);
+ for (size_t i = 0; i < kNumFeatures; ++i) {
+ // We can't use UMA_HISTOGRAM_ENUMERATION here because the same name is
+ // expected if the macro is used within a loop.
+ GpuFeatureStatus value = kGpuFeatureEnabled;
+ if (blacklisted_features.count(kGpuFeatures[i]))
+ value = kGpuFeatureBlacklisted;
+ else if (kGpuFeatureUserFlags[i])
+ value = kGpuFeatureDisabled;
+ base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
+ kGpuBlacklistFeatureHistogramNames[i],
+ 1, kGpuFeatureNumStatus, kGpuFeatureNumStatus + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram_pointer->Add(value);
+#if defined(OS_WIN)
+ histogram_pointer = base::LinearHistogram::FactoryGet(
+ kGpuBlacklistFeatureHistogramNamesWin[i],
+ 1, kNumWinSubVersions * kGpuFeatureNumStatus,
+ kNumWinSubVersions * kGpuFeatureNumStatus + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram_pointer->Add(GetGpuBlacklistHistogramValueWin(value));
+#endif
+ }
+
+ UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.GLResetNotificationStrategy",
+ gpu_info.gl_reset_notification_strategy);
+}
+
+// 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 == kCGDisplayBeginConfigurationFlag)
+ return; // This call contains no information about the display change
+
+ GpuDataManagerImpl* manager =
+ reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager);
+ DCHECK(manager);
+
+ uint32_t displayCount;
+ CGGetActiveDisplayList(0, NULL, &displayCount);
+
+ bool fireGpuSwitch = flags & kCGDisplayAddFlag;
+
+ if (displayCount != manager->GetDisplayCount()) {
+ manager->SetDisplayCount(displayCount);
+ fireGpuSwitch = true;
+ }
+
+ if (fireGpuSwitch)
+ manager->HandleGpuSwitch();
+}
+#endif // OS_MACOSX
+
+#if defined(OS_ANDROID)
+void ApplyAndroidWorkarounds(const gpu::GPUInfo& gpu_info,
+ CommandLine* command_line) {
+ std::string vendor(StringToLowerASCII(gpu_info.gl_vendor));
+ std::string renderer(StringToLowerASCII(gpu_info.gl_renderer));
+ bool is_img =
+ gpu_info.gl_vendor.find("Imagination") != std::string::npos;
+ bool is_arm =
+ gpu_info.gl_vendor.find("ARM") != std::string::npos;
+ bool is_qualcomm =
+ gpu_info.gl_vendor.find("Qualcomm") != std::string::npos;
+ bool is_broadcom =
+ gpu_info.gl_vendor.find("Broadcom") != std::string::npos;
+ bool is_mali_t604 = is_arm &&
+ gpu_info.gl_renderer.find("Mali-T604") != std::string::npos;
+ bool is_nvidia =
+ gpu_info.gl_vendor.find("NVIDIA") != std::string::npos;
+
+ bool is_vivante =
+ gpu_info.gl_extensions.find("GL_VIV_shader_binary") !=
+ std::string::npos;
+
+ bool is_nexus7 =
+ gpu_info.machine_model.find("Nexus 7") != std::string::npos;
+ bool is_nexus10 =
+ gpu_info.machine_model.find("Nexus 10") != std::string::npos;
+
+ // IMG: avoid context switching perf problems, crashes with share groups
+ // Mali-T604: http://crbug.com/154715
+ // QualComm, NVIDIA: Crashes with share groups
+ if (is_vivante || is_img || is_mali_t604 || is_nvidia || is_qualcomm ||
+ is_broadcom)
+ command_line->AppendSwitch(switches::kEnableVirtualGLContexts);
+
+ gfx::DeviceDisplayInfo info;
+ int default_tile_size = 256;
+
+ // For very high resolution displays (eg. Nexus 10), set the default
+ // tile size to be 512. This should be removed in favour of a generic
+ // hueristic that works across all platforms and devices, once that
+ // exists: http://crbug.com/159524. This switches to 512 for screens
+ // containing 40 or more 256x256 tiles, such that 1080p devices do
+ // not use 512x512 tiles (eg. 1920x1280 requires 37.5 tiles)
+ int numTiles = (info.GetDisplayWidth() *
+ info.GetDisplayHeight()) / (256 * 256);
+ if (numTiles >= 40)
+ default_tile_size = 512;
+
+ // IMG: Fast async texture uploads only work with non-power-of-two,
+ // but still multiple-of-eight sizes.
+ // http://crbug.com/168099
+ if (is_img)
+ default_tile_size -= 8;
+
+ // If we are using the MapImage API double the tile size to reduce
+ // the number of zero-copy buffers being used.
+ if (command_line->HasSwitch(cc::switches::kUseMapImage))
+ default_tile_size *= 2;
+
+ // Set the command line if it isn't already set and we changed
+ // the default tile size.
+ if (default_tile_size != 256 &&
+ !command_line->HasSwitch(switches::kDefaultTileWidth) &&
+ !command_line->HasSwitch(switches::kDefaultTileHeight)) {
+ std::stringstream size;
+ size << default_tile_size;
+ command_line->AppendSwitchASCII(
+ switches::kDefaultTileWidth, size.str());
+ command_line->AppendSwitchASCII(
+ switches::kDefaultTileHeight, size.str());
+ }
+
+ // Increase the resolution of low resolution tiles for Nexus tablets.
+ if ((is_nexus7 || is_nexus10) &&
+ !command_line->HasSwitch(
+ cc::switches::kLowResolutionContentsScaleFactor)) {
+ command_line->AppendSwitchASCII(
+ cc::switches::kLowResolutionContentsScaleFactor, "0.25");
+ }
+}
+#endif // OS_ANDROID
+
+// 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 gpu::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::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();
+}
+
+void GpuDataManagerImplPrivate::SetDisplayCount(unsigned int display_count) {
+ display_count_ = display_count;
+}
+
+unsigned int GpuDataManagerImplPrivate::GetDisplayCount() const {
+ return display_count_;
+}
+
+gpu::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_process_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_;
+ gpu::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() == gpu::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;
+
+ gpu::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::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) &&
+ !command_line->HasSwitch(switches::kUseGpuInTests))
+ return;
+
+ gpu::GPUInfo gpu_info;
+ {
+ TRACE_EVENT0("startup",
+ "GpuDataManagerImpl::Initialize:CollectBasicGraphicsInfo");
+ gpu::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) &&
+ !command_line->HasSwitch(switches::kUseGpuInTests)) {
+ gpu_blacklist_string = gpu::kSoftwareRenderingListJson;
+ gpu_switching_list_string = gpu::kGpuSwitchingListJson;
+ }
+ if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
+ gpu_driver_bug_list_string = gpu::kGpuDriverBugListJson;
+ }
+ InitializeImpl(gpu_blacklist_string,
+ gpu_switching_list_string,
+ gpu_driver_bug_list_string,
+ gpu_info);
+}
+
+void GpuDataManagerImplPrivate::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) {
+ // No further update of gpu_info if falling back to SwiftShader.
+ if (use_swiftshader_)
+ return;
+
+ gpu::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(
+ gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
+ if (update_histograms_)
+ UpdateStats(gpu_info_, gpu_blacklist_.get(), features);
+
+ UpdateBlacklistedFeatures(features);
+ }
+ if (gpu_switching_list_) {
+ std::set<int> option = gpu_switching_list_->MakeDecision(
+ gpu::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<gpu::GpuSwitchingOption>(
+ *(option.begin()));
+ }
+ }
+ }
+ if (gpu_driver_bug_list_) {
+ gpu_driver_bugs_ = gpu_driver_bug_list_->MakeDecision(
+ gpu::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::GPU_FEATURE_TYPE_WEBGL)) {
+ if (!command_line->HasSwitch(switches::kDisableExperimentalWebGL))
+ command_line->AppendSwitch(switches::kDisableExperimentalWebGL);
+ if (!command_line->HasSwitch(switches::kDisablePepper3d))
+ command_line->AppendSwitch(switches::kDisablePepper3d);
+ }
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_MULTISAMPLING) &&
+ !command_line->HasSwitch(switches::kDisableGLMultisampling))
+ command_line->AppendSwitch(switches::kDisableGLMultisampling);
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) &&
+ !command_line->HasSwitch(switches::kDisableAcceleratedCompositing))
+ command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS) &&
+ !command_line->HasSwitch(switches::kDisableAccelerated2dCanvas))
+ command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
+ !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
+ command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
+
+ if (use_software_compositor_ &&
+ !command_line->HasSwitch(switches::kEnableSoftwareCompositing))
+ command_line->AppendSwitch(switches::kEnableSoftwareCompositing);
+
+#if defined(USE_AURA)
+ if (!CanUseGpuBrowserCompositor()) {
+ command_line->AppendSwitch(switches::kDisableGpuCompositing);
+ command_line->AppendSwitch(switches::kDisablePepper3d);
+ }
+#endif
+}
+
+void GpuDataManagerImplPrivate::AppendGpuCommandLine(
+ CommandLine* command_line) const {
+ DCHECK(command_line);
+
+ bool reduce_sandbox = false;
+
+ std::string use_gl =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL);
+ base::FilePath swiftshader_path =
+ CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kSwiftShaderPath);
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_MULTISAMPLING) &&
+ !command_line->HasSwitch(switches::kDisableGLMultisampling)) {
+ command_line->AppendSwitch(switches::kDisableGLMultisampling);
+ }
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_TEXTURE_SHARING)) {
+ command_line->AppendSwitch(switches::kDisableImageTransportSurface);
+ reduce_sandbox = true;
+ }
+ if (gpu_driver_bugs_.find(gpu::DISABLE_D3D11) != gpu_driver_bugs_.end())
+ command_line->AppendSwitch(switches::kDisableD3D11);
+ if (use_swiftshader_) {
+ command_line->AppendSwitchASCII(switches::kUseGL, "swiftshader");
+ if (swiftshader_path.empty())
+ swiftshader_path = swiftshader_path_;
+ } else if ((IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL) ||
+ IsFeatureBlacklisted(
+ gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
+ IsFeatureBlacklisted(
+ gpu::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::GPU_SWITCHING_OPTION_FORCE_DISCRETE:
+ command_line->AppendSwitchASCII(switches::kGpuSwitching,
+ switches::kGpuSwitchingOptionNameForceDiscrete);
+ break;
+ case gpu::GPU_SWITCHING_OPTION_FORCE_INTEGRATED:
+ command_line->AppendSwitchASCII(switches::kGpuSwitching,
+ switches::kGpuSwitchingOptionNameForceIntegrated);
+ break;
+ case gpu::GPU_SWITCHING_OPTION_AUTOMATIC:
+ case gpu::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 (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
+ !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) {
+ command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
+ }
+
+#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) {
+ reduce_sandbox = true;
+ }
+#endif
+
+ if (gpu_info_.optimus)
+ reduce_sandbox = true;
+
+ if (reduce_sandbox)
+ command_line->AppendSwitch(switches::kReduceGpuSandbox);
+
+ // 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::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::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING))
+ prefs->accelerated_compositing_enabled = false;
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL))
+ prefs->experimental_webgl_enabled = false;
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH3D))
+ prefs->flash_3d_enabled = false;
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D)) {
+ prefs->flash_stage3d_enabled = false;
+ prefs->flash_stage3d_baseline_enabled = false;
+ }
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE))
+ prefs->flash_stage3d_baseline_enabled = false;
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS))
+ prefs->accelerated_2d_canvas_enabled = false;
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_MULTISAMPLING)
+ || display_count_ > 1)
+ prefs->gl_multisampling_enabled = false;
+ if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_3D_CSS)) {
+ prefs->accelerated_compositing_for_3d_transforms_enabled = false;
+ prefs->accelerated_compositing_for_animation_enabled = false;
+ }
+ if (IsFeatureBlacklisted(gpu::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;
+ }
+
+ if (use_software_compositor_) {
+ prefs->force_compositing_mode = true;
+ prefs->accelerated_compositing_enabled = true;
+ prefs->accelerated_compositing_for_3d_transforms_enabled = true;
+ prefs->accelerated_compositing_for_plugins_enabled = true;
+ }
+
+#if defined(USE_AURA)
+ if (!CanUseGpuBrowserCompositor())
+ prefs->accelerated_2d_canvas_enabled = false;
+#endif
+}
+
+gpu::GpuSwitchingOption
+GpuDataManagerImplPrivate::GetGpuSwitchingOption() const {
+ if (!ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus())
+ return gpu::GPU_SWITCHING_OPTION_UNKNOWN;
+ return gpu_switching_;
+}
+
+void GpuDataManagerImplPrivate::DisableHardwareAcceleration() {
+ card_blacklisted_ = true;
+
+ for (int i = 0; i < gpu::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";
+}
+
+std::string GpuDataManagerImplPrivate::GetDriverBugListVersion() const {
+ if (gpu_driver_bug_list_)
+ return gpu_driver_bug_list_->version();
+ return "0";
+}
+
+void GpuDataManagerImplPrivate::GetBlacklistReasons(
+ base::ListValue* reasons) const {
+ if (gpu_blacklist_)
+ gpu_blacklist_->GetReasons(reasons);
+}
+
+void GpuDataManagerImplPrivate::GetDriverBugWorkarounds(
+ base::ListValue* workarounds) const {
+ for (std::set<int>::const_iterator it = gpu_driver_bugs_.begin();
+ it != gpu_driver_bugs_.end(); ++it) {
+ workarounds->AppendString(
+ gpu::GpuDriverBugWorkaroundTypeToString(
+ static_cast<gpu::GpuDriverBugWorkaroundType>(*it)));
+ }
+}
+
+void GpuDataManagerImplPrivate::AddLogMessage(
+ int level, const std::string& header, const std::string& message) {
+ base::DictionaryValue* dict = new base::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)) {
+ // 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 (use_swiftshader_)
+ return false;
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kDisableImageTransportSurface))
+ return false;
+ return !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_TEXTURE_SHARING);
+}
+#endif
+
+bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const {
+ return !ShouldUseSwiftShader() &&
+ !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) &&
+ !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FORCE_COMPOSITING_MODE);
+}
+
+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) {
+ // 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) {
+ return new GpuDataManagerImplPrivate(owner);
+}
+
+GpuDataManagerImplPrivate::GpuDataManagerImplPrivate(
+ GpuDataManagerImpl* owner)
+ : complete_gpu_info_already_requested_(false),
+ gpu_switching_(gpu::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_(owner),
+ display_count_(0),
+ gpu_process_accessible_(true),
+ use_software_compositor_(false) {
+ DCHECK(owner_);
+ 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::kEnableSoftwareCompositing))
+ use_software_compositor_ = true;
+ //TODO(jbauman): enable for Chrome OS and Linux
+#if defined(USE_AURA) && defined(OS_WIN)
+ use_software_compositor_ = true;
+#endif
+ if (command_line->HasSwitch(switches::kGpuSwitching)) {
+ std::string option_string = command_line->GetSwitchValueASCII(
+ switches::kGpuSwitching);
+ gpu::GpuSwitchingOption option =
+ gpu::StringToGpuSwitchingOption(option_string);
+ if (option != gpu::GPU_SWITCHING_OPTION_UNKNOWN)
+ gpu_switching_ = option;
+ }
+
+#if defined(OS_MACOSX)
+ CGGetActiveDisplayList (0, NULL, &display_count_);
+ CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback, owner_);
+#endif // OS_MACOSX
+}
+
+GpuDataManagerImplPrivate::~GpuDataManagerImplPrivate() {
+#if defined(OS_MACOSX)
+ CGDisplayRemoveReconfigurationCallback(DisplayReconfigCallback, owner_);
+#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 gpu::GPUInfo& gpu_info) {
+ std::string browser_version_string = ProcessVersionString(
+ GetContentClient()->GetProduct());
+ CHECK(!browser_version_string.empty());
+
+ if (!gpu_blacklist_json.empty()) {
+ gpu_blacklist_.reset(gpu::GpuBlacklist::Create());
+ gpu_blacklist_->LoadList(
+ browser_version_string, gpu_blacklist_json,
+ gpu::GpuControlList::kCurrentOsOnly);
+ }
+ if (!gpu_switching_list_json.empty()) {
+ gpu_switching_list_.reset(gpu::GpuSwitchingList::Create());
+ gpu_switching_list_->LoadList(
+ browser_version_string, gpu_switching_list_json,
+ gpu::GpuControlList::kCurrentOsOnly);
+ }
+ if (!gpu_driver_bug_list_json.empty()) {
+ gpu_driver_bug_list_.reset(gpu::GpuDriverBugList::Create());
+ gpu_driver_bug_list_->LoadList(
+ browser_version_string, gpu_driver_bug_list_json,
+ gpu::GpuControlList::kCurrentOsOnly);
+ }
+
+ gpu_info_ = gpu_info;
+ UpdateGpuInfo(gpu_info);
+ UpdateGpuSwitchingManager(gpu_info);
+ UpdatePreliminaryBlacklistedFeatures();
+
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ // 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_));
+ }
+ }
+#if defined(OS_ANDROID)
+ ApplyAndroidWorkarounds(gpu_info, command_line);
+#endif // OS_ANDROID
+}
+
+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::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING);
+ }
+ if (card_blacklisted_ ||
+ command_line->HasSwitch(switches::kBlacklistWebGL)) {
+ blacklisted_features_.insert(gpu::GPU_FEATURE_TYPE_WEBGL);
+ }
+
+ EnableSwiftShaderIfNecessary();
+}
+
+void GpuDataManagerImplPrivate::UpdatePreliminaryBlacklistedFeatures() {
+ preliminary_blacklisted_features_ = blacklisted_features_;
+}
+
+void GpuDataManagerImplPrivate::UpdateGpuSwitchingManager(
+ const gpu::GPUInfo& gpu_info) {
+ ui::GpuSwitchingManager::GetInstance()->SetGpuCount(
+ gpu_info.secondary_gpus.size() + 1);
+
+ if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
+ switch (gpu_switching_) {
+ case gpu::GPU_SWITCHING_OPTION_FORCE_DISCRETE:
+ ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu();
+ break;
+ case gpu::GPU_SWITCHING_OPTION_FORCE_INTEGRATED:
+ ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu();
+ break;
+ case gpu::GPU_SWITCHING_OPTION_AUTOMATIC:
+ case gpu::GPU_SWITCHING_OPTION_UNKNOWN:
+ break;
+ }
+ }
+}
+
+void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() {
+ observer_list_->Notify(&GpuDataManagerObserver::OnGpuInfoUpdate);
+}
+
+void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() {
+ if (!GpuAccessAllowed(NULL) ||
+ blacklisted_features_.count(gpu::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);
+}
+
+void GpuDataManagerImplPrivate::OnGpuProcessInitFailure() {
+ gpu_process_accessible_ = false;
+ gpu_info_.finalized = true;
+ complete_gpu_info_already_requested_ = true;
+ // Some observers might be waiting.
+ NotifyGpuInfoUpdate();
+}
+
+} // namespace content
+