Home | History | Annotate | Download | only in gpu
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/gpu/gpu_data_manager_impl_private.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/command_line.h"
     10 #include "base/debug/trace_event.h"
     11 #include "base/metrics/field_trial.h"
     12 #include "base/metrics/histogram.h"
     13 #include "base/metrics/sparse_histogram.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "base/strings/stringprintf.h"
     16 #include "base/sys_info.h"
     17 #include "base/version.h"
     18 #include "cc/base/switches.h"
     19 #include "content/browser/gpu/gpu_process_host.h"
     20 #include "content/common/gpu/gpu_messages.h"
     21 #include "content/public/browser/browser_thread.h"
     22 #include "content/public/browser/gpu_data_manager_observer.h"
     23 #include "content/public/common/content_client.h"
     24 #include "content/public/common/content_constants.h"
     25 #include "content/public/common/content_switches.h"
     26 #include "gpu/command_buffer/service/gpu_switches.h"
     27 #include "gpu/config/gpu_control_list_jsons.h"
     28 #include "gpu/config/gpu_driver_bug_workaround_type.h"
     29 #include "gpu/config/gpu_feature_type.h"
     30 #include "gpu/config/gpu_info_collector.h"
     31 #include "gpu/config/gpu_util.h"
     32 #include "ui/base/ui_base_switches.h"
     33 #include "ui/gl/gl_implementation.h"
     34 #include "ui/gl/gl_switches.h"
     35 #include "ui/gl/gpu_switching_manager.h"
     36 #include "webkit/common/webpreferences.h"
     37 
     38 #if defined(OS_MACOSX)
     39 #include <ApplicationServices/ApplicationServices.h>
     40 #endif  // OS_MACOSX
     41 #if defined(OS_WIN)
     42 #include "base/win/windows_version.h"
     43 #endif  // OS_WIN
     44 #if defined(OS_ANDROID)
     45 #include "base/android/build_info.h"
     46 #include "ui/gfx/android/device_display_info.h"
     47 #endif  // OS_ANDROID
     48 
     49 namespace content {
     50 
     51 namespace {
     52 
     53 enum GpuFeatureStatus {
     54     kGpuFeatureEnabled = 0,
     55     kGpuFeatureBlacklisted = 1,
     56     kGpuFeatureDisabled = 2,  // disabled by user but not blacklisted
     57     kGpuFeatureNumStatus
     58 };
     59 
     60 #if defined(OS_WIN)
     61 
     62 enum WinSubVersion {
     63   kWinOthers = 0,
     64   kWinXP,
     65   kWinVista,
     66   kWin7,
     67   kWin8,
     68   kNumWinSubVersions
     69 };
     70 
     71 int GetGpuBlacklistHistogramValueWin(GpuFeatureStatus status) {
     72   static WinSubVersion sub_version = kNumWinSubVersions;
     73   if (sub_version == kNumWinSubVersions) {
     74     sub_version = kWinOthers;
     75     std::string version_str = base::SysInfo::OperatingSystemVersion();
     76     size_t pos = version_str.find_first_not_of("0123456789.");
     77     if (pos != std::string::npos)
     78       version_str = version_str.substr(0, pos);
     79     Version os_version(version_str);
     80     if (os_version.IsValid() && os_version.components().size() >= 2) {
     81       const std::vector<uint16>& version_numbers = os_version.components();
     82       if (version_numbers[0] == 5)
     83         sub_version = kWinXP;
     84       else if (version_numbers[0] == 6 && version_numbers[1] == 0)
     85         sub_version = kWinVista;
     86       else if (version_numbers[0] == 6 && version_numbers[1] == 1)
     87         sub_version = kWin7;
     88       else if (version_numbers[0] == 6 && version_numbers[1] == 2)
     89         sub_version = kWin8;
     90     }
     91   }
     92   int entry_index = static_cast<int>(sub_version) * kGpuFeatureNumStatus;
     93   switch (status) {
     94     case kGpuFeatureEnabled:
     95       break;
     96     case kGpuFeatureBlacklisted:
     97       entry_index++;
     98       break;
     99     case kGpuFeatureDisabled:
    100       entry_index += 2;
    101       break;
    102   }
    103   return entry_index;
    104 }
    105 #endif  // OS_WIN
    106 
    107 // Send UMA histograms about the enabled features and GPU properties.
    108 void UpdateStats(const gpu::GPUInfo& gpu_info,
    109                  const gpu::GpuBlacklist* blacklist,
    110                  const std::set<int>& blacklisted_features) {
    111   uint32 max_entry_id = blacklist->max_entry_id();
    112   if (max_entry_id == 0) {
    113     // GPU Blacklist was not loaded.  No need to go further.
    114     return;
    115   }
    116 
    117   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    118   bool disabled = false;
    119 
    120   // Use entry 0 to capture the total number of times that data
    121   // was recorded in this histogram in order to have a convenient
    122   // denominator to compute blacklist percentages for the rest of the
    123   // entries.
    124   UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
    125       0, max_entry_id + 1);
    126 
    127   if (blacklisted_features.size() != 0) {
    128     std::vector<uint32> flag_entries;
    129     blacklist->GetDecisionEntries(&flag_entries, disabled);
    130     DCHECK_GT(flag_entries.size(), 0u);
    131     for (size_t i = 0; i < flag_entries.size(); ++i) {
    132       UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
    133           flag_entries[i], max_entry_id + 1);
    134     }
    135   }
    136 
    137   // This counts how many users are affected by a disabled entry - this allows
    138   // us to understand the impact of an entry before enable it.
    139   std::vector<uint32> flag_disabled_entries;
    140   disabled = true;
    141   blacklist->GetDecisionEntries(&flag_disabled_entries, disabled);
    142   for (size_t i = 0; i < flag_disabled_entries.size(); ++i) {
    143     UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerDisabledEntry",
    144         flag_disabled_entries[i], max_entry_id + 1);
    145   }
    146 
    147   const gpu::GpuFeatureType kGpuFeatures[] = {
    148       gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS,
    149       gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING,
    150       gpu::GPU_FEATURE_TYPE_WEBGL,
    151       gpu::GPU_FEATURE_TYPE_TEXTURE_SHARING
    152   };
    153   const std::string kGpuBlacklistFeatureHistogramNames[] = {
    154       "GPU.BlacklistFeatureTestResults.Accelerated2dCanvas",
    155       "GPU.BlacklistFeatureTestResults.AcceleratedCompositing",
    156       "GPU.BlacklistFeatureTestResults.Webgl",
    157       "GPU.BlacklistFeatureTestResults.TextureSharing"
    158   };
    159   const bool kGpuFeatureUserFlags[] = {
    160       command_line.HasSwitch(switches::kDisableAccelerated2dCanvas),
    161       command_line.HasSwitch(switches::kDisableAcceleratedCompositing),
    162       command_line.HasSwitch(switches::kDisableExperimentalWebGL),
    163       command_line.HasSwitch(switches::kDisableImageTransportSurface)
    164   };
    165 #if defined(OS_WIN)
    166   const std::string kGpuBlacklistFeatureHistogramNamesWin[] = {
    167       "GPU.BlacklistFeatureTestResultsWindows.Accelerated2dCanvas",
    168       "GPU.BlacklistFeatureTestResultsWindows.AcceleratedCompositing",
    169       "GPU.BlacklistFeatureTestResultsWindows.Webgl",
    170       "GPU.BlacklistFeatureTestResultsWindows.TextureSharing"
    171   };
    172 #endif
    173   const size_t kNumFeatures =
    174       sizeof(kGpuFeatures) / sizeof(gpu::GpuFeatureType);
    175   for (size_t i = 0; i < kNumFeatures; ++i) {
    176     // We can't use UMA_HISTOGRAM_ENUMERATION here because the same name is
    177     // expected if the macro is used within a loop.
    178     GpuFeatureStatus value = kGpuFeatureEnabled;
    179     if (blacklisted_features.count(kGpuFeatures[i]))
    180       value = kGpuFeatureBlacklisted;
    181     else if (kGpuFeatureUserFlags[i])
    182       value = kGpuFeatureDisabled;
    183     base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
    184         kGpuBlacklistFeatureHistogramNames[i],
    185         1, kGpuFeatureNumStatus, kGpuFeatureNumStatus + 1,
    186         base::HistogramBase::kUmaTargetedHistogramFlag);
    187     histogram_pointer->Add(value);
    188 #if defined(OS_WIN)
    189     histogram_pointer = base::LinearHistogram::FactoryGet(
    190         kGpuBlacklistFeatureHistogramNamesWin[i],
    191         1, kNumWinSubVersions * kGpuFeatureNumStatus,
    192         kNumWinSubVersions * kGpuFeatureNumStatus + 1,
    193         base::HistogramBase::kUmaTargetedHistogramFlag);
    194     histogram_pointer->Add(GetGpuBlacklistHistogramValueWin(value));
    195 #endif
    196   }
    197 
    198   UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.GLResetNotificationStrategy",
    199       gpu_info.gl_reset_notification_strategy);
    200 }
    201 
    202 // Strip out the non-digital info; if after that, we get an empty string,
    203 // return "0".
    204 std::string ProcessVersionString(const std::string& raw_string) {
    205   const std::string valid_set = "0123456789.";
    206   size_t start_pos = raw_string.find_first_of(valid_set);
    207   if (start_pos == std::string::npos)
    208     return "0";
    209   size_t end_pos = raw_string.find_first_not_of(raw_string, start_pos);
    210   std::string version_string = raw_string.substr(
    211       start_pos, end_pos - start_pos);
    212   if (version_string.empty())
    213     return "0";
    214   return version_string;
    215 }
    216 
    217 // Combine the integers into a string, seperated by ','.
    218 std::string IntSetToString(const std::set<int>& list) {
    219   std::string rt;
    220   for (std::set<int>::const_iterator it = list.begin();
    221        it != list.end(); ++it) {
    222     if (!rt.empty())
    223       rt += ",";
    224     rt += base::IntToString(*it);
    225   }
    226   return rt;
    227 }
    228 
    229 #if defined(OS_MACOSX)
    230 void DisplayReconfigCallback(CGDirectDisplayID display,
    231                              CGDisplayChangeSummaryFlags flags,
    232                              void* gpu_data_manager) {
    233   if(flags == kCGDisplayBeginConfigurationFlag)
    234     return; // This call contains no information about the display change
    235 
    236   GpuDataManagerImpl* manager =
    237       reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager);
    238   DCHECK(manager);
    239 
    240   uint32_t displayCount;
    241   CGGetActiveDisplayList(0, NULL, &displayCount);
    242 
    243   bool fireGpuSwitch = flags & kCGDisplayAddFlag;
    244 
    245   if (displayCount != manager->GetDisplayCount()) {
    246     manager->SetDisplayCount(displayCount);
    247     fireGpuSwitch = true;
    248   }
    249 
    250   if (fireGpuSwitch)
    251     manager->HandleGpuSwitch();
    252 }
    253 #endif  // OS_MACOSX
    254 
    255 #if defined(OS_ANDROID)
    256 void ApplyAndroidWorkarounds(const gpu::GPUInfo& gpu_info,
    257                              CommandLine* command_line) {
    258   std::string vendor(StringToLowerASCII(gpu_info.gl_vendor));
    259   std::string renderer(StringToLowerASCII(gpu_info.gl_renderer));
    260   bool is_img =
    261       gpu_info.gl_vendor.find("Imagination") != std::string::npos;
    262   bool is_arm =
    263       gpu_info.gl_vendor.find("ARM") != std::string::npos;
    264   bool is_qualcomm =
    265       gpu_info.gl_vendor.find("Qualcomm") != std::string::npos;
    266   bool is_broadcom =
    267       gpu_info.gl_vendor.find("Broadcom") != std::string::npos;
    268   bool is_mali_t604 = is_arm &&
    269       gpu_info.gl_renderer.find("Mali-T604") != std::string::npos;
    270   bool is_nvidia =
    271       gpu_info.gl_vendor.find("NVIDIA") != std::string::npos;
    272 
    273   bool is_vivante =
    274       gpu_info.gl_extensions.find("GL_VIV_shader_binary") !=
    275       std::string::npos;
    276 
    277   bool is_nexus7 =
    278       gpu_info.machine_model.find("Nexus 7") != std::string::npos;
    279   bool is_nexus10 =
    280       gpu_info.machine_model.find("Nexus 10") != std::string::npos;
    281 
    282   int sdk_int = base::android::BuildInfo::GetInstance()->sdk_int();
    283 
    284   // IMG: avoid context switching perf problems, crashes with share groups
    285   // Mali-T604: http://crbug.com/154715
    286   // QualComm, NVIDIA: Crashes with share groups
    287   if (is_vivante || is_img || is_mali_t604 || (is_nvidia && (sdk_int < 18)) ||
    288       is_qualcomm || is_broadcom) {
    289     command_line->AppendSwitch(switches::kEnableVirtualGLContexts);
    290   }
    291 
    292   gfx::DeviceDisplayInfo info;
    293   int default_tile_size = 256;
    294 
    295   // For very high resolution displays (eg. Nexus 10), set the default
    296   // tile size to be 512. This should be removed in favour of a generic
    297   // hueristic that works across all platforms and devices, once that
    298   // exists: http://crbug.com/159524. This switches to 512 for screens
    299   // containing 40 or more 256x256 tiles, such that 1080p devices do
    300   // not use 512x512 tiles (eg. 1920x1280 requires 37.5 tiles)
    301   int numTiles = (info.GetDisplayWidth() *
    302                   info.GetDisplayHeight()) / (256 * 256);
    303   if (numTiles >= 40)
    304     default_tile_size = 512;
    305 
    306   // IMG: Fast async texture uploads only work with non-power-of-two,
    307   // but still multiple-of-eight sizes.
    308   // http://crbug.com/168099
    309   if (is_img)
    310     default_tile_size -= 8;
    311 
    312   // If we are using the MapImage API double the tile size to reduce
    313   // the number of zero-copy buffers being used.
    314   if (command_line->HasSwitch(cc::switches::kUseMapImage))
    315     default_tile_size *= 2;
    316 
    317   // Set the command line if it isn't already set and we changed
    318   // the default tile size.
    319   if (default_tile_size != 256 &&
    320       !command_line->HasSwitch(switches::kDefaultTileWidth) &&
    321       !command_line->HasSwitch(switches::kDefaultTileHeight)) {
    322     std::stringstream size;
    323     size << default_tile_size;
    324     command_line->AppendSwitchASCII(
    325         switches::kDefaultTileWidth, size.str());
    326     command_line->AppendSwitchASCII(
    327         switches::kDefaultTileHeight, size.str());
    328   }
    329 
    330   // Increase the resolution of low resolution tiles for Nexus tablets.
    331   if ((is_nexus7 || is_nexus10) &&
    332       !command_line->HasSwitch(
    333           cc::switches::kLowResolutionContentsScaleFactor)) {
    334     command_line->AppendSwitchASCII(
    335         cc::switches::kLowResolutionContentsScaleFactor, "0.25");
    336   }
    337 }
    338 #endif  // OS_ANDROID
    339 
    340 // Block all domains' use of 3D APIs for this many milliseconds if
    341 // approaching a threshold where system stability might be compromised.
    342 const int64 kBlockAllDomainsMs = 10000;
    343 const int kNumResetsWithinDuration = 1;
    344 
    345 // Enums for UMA histograms.
    346 enum BlockStatusHistogram {
    347   BLOCK_STATUS_NOT_BLOCKED,
    348   BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
    349   BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
    350   BLOCK_STATUS_MAX
    351 };
    352 
    353 }  // namespace anonymous
    354 
    355 void GpuDataManagerImplPrivate::InitializeForTesting(
    356     const std::string& gpu_blacklist_json,
    357     const gpu::GPUInfo& gpu_info) {
    358   // This function is for testing only, so disable histograms.
    359   update_histograms_ = false;
    360 
    361   InitializeImpl(gpu_blacklist_json, std::string(), std::string(), gpu_info);
    362 }
    363 
    364 bool GpuDataManagerImplPrivate::IsFeatureBlacklisted(int feature) const {
    365   if (use_swiftshader_) {
    366     // Skia's software rendering is probably more efficient than going through
    367     // software emulation of the GPU, so use that.
    368     if (feature == gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)
    369       return true;
    370     return false;
    371   }
    372 
    373   return (blacklisted_features_.count(feature) == 1);
    374 }
    375 
    376 size_t GpuDataManagerImplPrivate::GetBlacklistedFeatureCount() const {
    377   if (use_swiftshader_)
    378     return 1;
    379   return blacklisted_features_.size();
    380 }
    381 
    382 void GpuDataManagerImplPrivate::SetDisplayCount(unsigned int display_count) {
    383   display_count_ = display_count;
    384 }
    385 
    386 unsigned int GpuDataManagerImplPrivate::GetDisplayCount() const {
    387   return display_count_;
    388 }
    389 
    390 gpu::GPUInfo GpuDataManagerImplPrivate::GetGPUInfo() const {
    391   return gpu_info_;
    392 }
    393 
    394 void GpuDataManagerImplPrivate::GetGpuProcessHandles(
    395     const GpuDataManager::GetGpuProcessHandlesCallback& callback) const {
    396   GpuProcessHost::GetProcessHandles(callback);
    397 }
    398 
    399 bool GpuDataManagerImplPrivate::GpuAccessAllowed(
    400     std::string* reason) const {
    401   if (use_swiftshader_)
    402     return true;
    403 
    404   if (!gpu_process_accessible_) {
    405     if (reason) {
    406       *reason = "GPU process launch failed.";
    407     }
    408     return false;
    409   }
    410 
    411   if (card_blacklisted_) {
    412     if (reason) {
    413       *reason = "GPU access is disabled ";
    414       CommandLine* command_line = CommandLine::ForCurrentProcess();
    415       if (command_line->HasSwitch(switches::kDisableGpu))
    416         *reason += "through commandline switch --disable-gpu.";
    417       else
    418         *reason += "in chrome://settings.";
    419     }
    420     return false;
    421   }
    422 
    423   // We only need to block GPU process if more features are disallowed other
    424   // than those in the preliminary gpu feature flags because the latter work
    425   // through renderer commandline switches.
    426   std::set<int> features = preliminary_blacklisted_features_;
    427   gpu::MergeFeatureSets(&features, blacklisted_features_);
    428   if (features.size() > preliminary_blacklisted_features_.size()) {
    429     if (reason) {
    430       *reason = "Features are disabled upon full but not preliminary GPU info.";
    431     }
    432     return false;
    433   }
    434 
    435   if (blacklisted_features_.size() == gpu::NUMBER_OF_GPU_FEATURE_TYPES) {
    436     // On Linux, we use cached GL strings to make blacklist decsions at browser
    437     // startup time. We need to launch the GPU process to validate these
    438     // strings even if all features are blacklisted. If all GPU features are
    439     // disabled, the GPU process will only initialize GL bindings, create a GL
    440     // context, and collect full GPU info.
    441 #if !defined(OS_LINUX)
    442     if (reason) {
    443       *reason = "All GPU features are blacklisted.";
    444     }
    445     return false;
    446 #endif
    447   }
    448 
    449   return true;
    450 }
    451 
    452 void GpuDataManagerImplPrivate::RequestCompleteGpuInfoIfNeeded() {
    453   if (complete_gpu_info_already_requested_ || gpu_info_.finalized)
    454     return;
    455   complete_gpu_info_already_requested_ = true;
    456 
    457   GpuProcessHost::SendOnIO(
    458 #if defined(OS_WIN)
    459       GpuProcessHost::GPU_PROCESS_KIND_UNSANDBOXED,
    460 #else
    461       GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
    462 #endif
    463       CAUSE_FOR_GPU_LAUNCH_GPUDATAMANAGER_REQUESTCOMPLETEGPUINFOIFNEEDED,
    464       new GpuMsg_CollectGraphicsInfo());
    465 }
    466 
    467 bool GpuDataManagerImplPrivate::IsCompleteGpuInfoAvailable() const {
    468   return gpu_info_.finalized;
    469 }
    470 
    471 void GpuDataManagerImplPrivate::RequestVideoMemoryUsageStatsUpdate() const {
    472   GpuProcessHost::SendOnIO(
    473       GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
    474       CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
    475       new GpuMsg_GetVideoMemoryUsageStats());
    476 }
    477 
    478 bool GpuDataManagerImplPrivate::ShouldUseSwiftShader() const {
    479   return use_swiftshader_;
    480 }
    481 
    482 void GpuDataManagerImplPrivate::RegisterSwiftShaderPath(
    483     const base::FilePath& path) {
    484   swiftshader_path_ = path;
    485   EnableSwiftShaderIfNecessary();
    486 }
    487 
    488 void GpuDataManagerImplPrivate::AddObserver(GpuDataManagerObserver* observer) {
    489   GpuDataManagerImpl::UnlockedSession session(owner_);
    490   observer_list_->AddObserver(observer);
    491 }
    492 
    493 void GpuDataManagerImplPrivate::RemoveObserver(
    494     GpuDataManagerObserver* observer) {
    495   GpuDataManagerImpl::UnlockedSession session(owner_);
    496   observer_list_->RemoveObserver(observer);
    497 }
    498 
    499 void GpuDataManagerImplPrivate::UnblockDomainFrom3DAPIs(const GURL& url) {
    500   // This method must do two things:
    501   //
    502   //  1. If the specific domain is blocked, then unblock it.
    503   //
    504   //  2. Reset our notion of how many GPU resets have occurred recently.
    505   //     This is necessary even if the specific domain was blocked.
    506   //     Otherwise, if we call Are3DAPIsBlocked with the same domain right
    507   //     after unblocking it, it will probably still be blocked because of
    508   //     the recent GPU reset caused by that domain.
    509   //
    510   // These policies could be refined, but at a certain point the behavior
    511   // will become difficult to explain.
    512   std::string domain = GetDomainFromURL(url);
    513 
    514   blocked_domains_.erase(domain);
    515   timestamps_of_gpu_resets_.clear();
    516 }
    517 
    518 void GpuDataManagerImplPrivate::DisableGpuWatchdog() {
    519   GpuProcessHost::SendOnIO(
    520       GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
    521       CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
    522       new GpuMsg_DisableWatchdog);
    523 }
    524 
    525 void GpuDataManagerImplPrivate::SetGLStrings(const std::string& gl_vendor,
    526                                              const std::string& gl_renderer,
    527                                              const std::string& gl_version) {
    528   if (gl_vendor.empty() && gl_renderer.empty() && gl_version.empty())
    529     return;
    530 
    531   // If GPUInfo already got GL strings, do nothing.  This is for the rare
    532   // situation where GPU process collected GL strings before this call.
    533   if (!gpu_info_.gl_vendor.empty() ||
    534       !gpu_info_.gl_renderer.empty() ||
    535       !gpu_info_.gl_version_string.empty())
    536     return;
    537 
    538   gpu::GPUInfo gpu_info = gpu_info_;
    539 
    540   gpu_info.gl_vendor = gl_vendor;
    541   gpu_info.gl_renderer = gl_renderer;
    542   gpu_info.gl_version_string = gl_version;
    543 
    544   gpu::CollectDriverInfoGL(&gpu_info);
    545 
    546   UpdateGpuInfo(gpu_info);
    547   UpdateGpuSwitchingManager(gpu_info);
    548   UpdatePreliminaryBlacklistedFeatures();
    549 }
    550 
    551 void GpuDataManagerImplPrivate::GetGLStrings(std::string* gl_vendor,
    552                                              std::string* gl_renderer,
    553                                              std::string* gl_version) {
    554   DCHECK(gl_vendor && gl_renderer && gl_version);
    555 
    556   *gl_vendor = gpu_info_.gl_vendor;
    557   *gl_renderer = gpu_info_.gl_renderer;
    558   *gl_version = gpu_info_.gl_version_string;
    559 }
    560 
    561 void GpuDataManagerImplPrivate::Initialize() {
    562   TRACE_EVENT0("startup", "GpuDataManagerImpl::Initialize");
    563   CommandLine* command_line = CommandLine::ForCurrentProcess();
    564   if (command_line->HasSwitch(switches::kSkipGpuDataLoading) &&
    565       !command_line->HasSwitch(switches::kUseGpuInTests))
    566     return;
    567 
    568   gpu::GPUInfo gpu_info;
    569   {
    570     TRACE_EVENT0("startup",
    571       "GpuDataManagerImpl::Initialize:CollectBasicGraphicsInfo");
    572     gpu::CollectBasicGraphicsInfo(&gpu_info);
    573   }
    574 #if defined(ARCH_CPU_X86_FAMILY)
    575   if (!gpu_info.gpu.vendor_id || !gpu_info.gpu.device_id)
    576     gpu_info.finalized = true;
    577 #endif
    578 
    579   std::string gpu_blacklist_string;
    580   std::string gpu_switching_list_string;
    581   std::string gpu_driver_bug_list_string;
    582   if (!command_line->HasSwitch(switches::kIgnoreGpuBlacklist) &&
    583       !command_line->HasSwitch(switches::kUseGpuInTests)) {
    584     gpu_blacklist_string = gpu::kSoftwareRenderingListJson;
    585     gpu_switching_list_string = gpu::kGpuSwitchingListJson;
    586   }
    587   if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
    588     gpu_driver_bug_list_string = gpu::kGpuDriverBugListJson;
    589   }
    590   InitializeImpl(gpu_blacklist_string,
    591                  gpu_switching_list_string,
    592                  gpu_driver_bug_list_string,
    593                  gpu_info);
    594 }
    595 
    596 void GpuDataManagerImplPrivate::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) {
    597   // No further update of gpu_info if falling back to SwiftShader.
    598   if (use_swiftshader_)
    599     return;
    600 
    601   gpu::MergeGPUInfo(&gpu_info_, gpu_info);
    602   complete_gpu_info_already_requested_ =
    603       complete_gpu_info_already_requested_ || gpu_info_.finalized;
    604 
    605   GetContentClient()->SetGpuInfo(gpu_info_);
    606 
    607   if (gpu_blacklist_) {
    608     std::set<int> features = gpu_blacklist_->MakeDecision(
    609         gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
    610     if (update_histograms_)
    611       UpdateStats(gpu_info_, gpu_blacklist_.get(), features);
    612 
    613     UpdateBlacklistedFeatures(features);
    614   }
    615   if (gpu_switching_list_) {
    616     std::set<int> option = gpu_switching_list_->MakeDecision(
    617         gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
    618     if (option.size() == 1) {
    619       // Blacklist decision should not overwrite commandline switch from users.
    620       CommandLine* command_line = CommandLine::ForCurrentProcess();
    621       if (!command_line->HasSwitch(switches::kGpuSwitching)) {
    622         gpu_switching_ = static_cast<gpu::GpuSwitchingOption>(
    623             *(option.begin()));
    624       }
    625     }
    626   }
    627   if (gpu_driver_bug_list_) {
    628     gpu_driver_bugs_ = gpu_driver_bug_list_->MakeDecision(
    629         gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
    630   }
    631 
    632   // We have to update GpuFeatureType before notify all the observers.
    633   NotifyGpuInfoUpdate();
    634 }
    635 
    636 void GpuDataManagerImplPrivate::UpdateVideoMemoryUsageStats(
    637     const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
    638   GpuDataManagerImpl::UnlockedSession session(owner_);
    639   observer_list_->Notify(&GpuDataManagerObserver::OnVideoMemoryUsageStatsUpdate,
    640                          video_memory_usage_stats);
    641 }
    642 
    643 void GpuDataManagerImplPrivate::AppendRendererCommandLine(
    644     CommandLine* command_line) const {
    645   DCHECK(command_line);
    646 
    647   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL)) {
    648     if (!command_line->HasSwitch(switches::kDisableExperimentalWebGL))
    649       command_line->AppendSwitch(switches::kDisableExperimentalWebGL);
    650     if (!command_line->HasSwitch(switches::kDisablePepper3d))
    651       command_line->AppendSwitch(switches::kDisablePepper3d);
    652   }
    653   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_MULTISAMPLING) &&
    654       !command_line->HasSwitch(switches::kDisableGLMultisampling))
    655     command_line->AppendSwitch(switches::kDisableGLMultisampling);
    656   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) &&
    657       !command_line->HasSwitch(switches::kDisableAcceleratedCompositing))
    658     command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
    659   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS) &&
    660       !command_line->HasSwitch(switches::kDisableAccelerated2dCanvas))
    661     command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
    662   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
    663       !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
    664     command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
    665 
    666   if (use_software_compositor_ &&
    667       !command_line->HasSwitch(switches::kEnableSoftwareCompositing))
    668     command_line->AppendSwitch(switches::kEnableSoftwareCompositing);
    669 
    670 #if defined(USE_AURA)
    671   if (!CanUseGpuBrowserCompositor()) {
    672     command_line->AppendSwitch(switches::kDisableGpuCompositing);
    673     command_line->AppendSwitch(switches::kDisablePepper3d);
    674   }
    675 #endif
    676 }
    677 
    678 void GpuDataManagerImplPrivate::AppendGpuCommandLine(
    679     CommandLine* command_line) const {
    680   DCHECK(command_line);
    681 
    682   bool reduce_sandbox = false;
    683 
    684   std::string use_gl =
    685       CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL);
    686   base::FilePath swiftshader_path =
    687       CommandLine::ForCurrentProcess()->GetSwitchValuePath(
    688           switches::kSwiftShaderPath);
    689   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_MULTISAMPLING) &&
    690       !command_line->HasSwitch(switches::kDisableGLMultisampling)) {
    691     command_line->AppendSwitch(switches::kDisableGLMultisampling);
    692   }
    693   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_TEXTURE_SHARING)) {
    694     command_line->AppendSwitch(switches::kDisableImageTransportSurface);
    695     reduce_sandbox = true;
    696   }
    697   if (gpu_driver_bugs_.find(gpu::DISABLE_D3D11) != gpu_driver_bugs_.end())
    698     command_line->AppendSwitch(switches::kDisableD3D11);
    699   if (use_swiftshader_) {
    700     command_line->AppendSwitchASCII(switches::kUseGL, "swiftshader");
    701     if (swiftshader_path.empty())
    702       swiftshader_path = swiftshader_path_;
    703   } else if ((IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL) ||
    704               IsFeatureBlacklisted(
    705                   gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
    706               IsFeatureBlacklisted(
    707                   gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)) &&
    708       (use_gl == "any")) {
    709     command_line->AppendSwitchASCII(
    710         switches::kUseGL, gfx::kGLImplementationOSMesaName);
    711   } else if (!use_gl.empty()) {
    712     command_line->AppendSwitchASCII(switches::kUseGL, use_gl);
    713   }
    714   if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
    715     command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "true");
    716     switch (gpu_switching_) {
    717       case gpu::GPU_SWITCHING_OPTION_FORCE_DISCRETE:
    718         command_line->AppendSwitchASCII(switches::kGpuSwitching,
    719             switches::kGpuSwitchingOptionNameForceDiscrete);
    720         break;
    721       case gpu::GPU_SWITCHING_OPTION_FORCE_INTEGRATED:
    722         command_line->AppendSwitchASCII(switches::kGpuSwitching,
    723             switches::kGpuSwitchingOptionNameForceIntegrated);
    724         break;
    725       case gpu::GPU_SWITCHING_OPTION_AUTOMATIC:
    726       case gpu::GPU_SWITCHING_OPTION_UNKNOWN:
    727         break;
    728     }
    729   } else {
    730     command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "false");
    731   }
    732 
    733   if (!swiftshader_path.empty()) {
    734     command_line->AppendSwitchPath(switches::kSwiftShaderPath,
    735                                    swiftshader_path);
    736   }
    737 
    738   if (!gpu_driver_bugs_.empty()) {
    739     command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
    740                                     IntSetToString(gpu_driver_bugs_));
    741   }
    742 
    743 #if defined(OS_WIN)
    744   // DisplayLink 7.1 and earlier can cause the GPU process to crash on startup.
    745   // http://crbug.com/177611
    746   // Thinkpad USB Port Replicator driver causes GPU process to crash when the
    747   // sandbox is enabled. http://crbug.com/181665.
    748   if ((gpu_info_.display_link_version.IsValid()
    749       && gpu_info_.display_link_version.IsOlderThan("7.2")) ||
    750       gpu_info_.lenovo_dcute) {
    751     reduce_sandbox = true;
    752   }
    753 #endif
    754 
    755   if (gpu_info_.optimus)
    756     reduce_sandbox = true;
    757 
    758   if (reduce_sandbox)
    759     command_line->AppendSwitch(switches::kReduceGpuSandbox);
    760 
    761   // Pass GPU and driver information to GPU process. We try to avoid full GPU
    762   // info collection at GPU process startup, but we need gpu vendor_id,
    763   // device_id, driver_vendor, driver_version for deciding whether we need to
    764   // collect full info (on Linux) and for crash reporting purpose.
    765   command_line->AppendSwitchASCII(switches::kGpuVendorID,
    766       base::StringPrintf("0x%04x", gpu_info_.gpu.vendor_id));
    767   command_line->AppendSwitchASCII(switches::kGpuDeviceID,
    768       base::StringPrintf("0x%04x", gpu_info_.gpu.device_id));
    769   command_line->AppendSwitchASCII(switches::kGpuDriverVendor,
    770       gpu_info_.driver_vendor);
    771   command_line->AppendSwitchASCII(switches::kGpuDriverVersion,
    772       gpu_info_.driver_version);
    773 }
    774 
    775 void GpuDataManagerImplPrivate::AppendPluginCommandLine(
    776     CommandLine* command_line) const {
    777   DCHECK(command_line);
    778 
    779 #if defined(OS_MACOSX)
    780   // TODO(jbauman): Add proper blacklist support for core animation plugins so
    781   // special-casing this video card won't be necessary. See
    782   // http://crbug.com/134015
    783   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
    784       CommandLine::ForCurrentProcess()->HasSwitch(
    785           switches::kDisableAcceleratedCompositing)) {
    786     if (!command_line->HasSwitch(
    787            switches::kDisableCoreAnimationPlugins))
    788       command_line->AppendSwitch(
    789           switches::kDisableCoreAnimationPlugins);
    790   }
    791 #endif
    792 }
    793 
    794 void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
    795     WebPreferences* prefs) const {
    796   DCHECK(prefs);
    797 
    798   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING))
    799     prefs->accelerated_compositing_enabled = false;
    800   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL))
    801     prefs->experimental_webgl_enabled = false;
    802   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH3D))
    803     prefs->flash_3d_enabled = false;
    804   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D)) {
    805     prefs->flash_stage3d_enabled = false;
    806     prefs->flash_stage3d_baseline_enabled = false;
    807   }
    808   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE))
    809     prefs->flash_stage3d_baseline_enabled = false;
    810   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS))
    811     prefs->accelerated_2d_canvas_enabled = false;
    812   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_MULTISAMPLING)
    813       || display_count_ > 1)
    814     prefs->gl_multisampling_enabled = false;
    815   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_3D_CSS)) {
    816     prefs->accelerated_compositing_for_3d_transforms_enabled = false;
    817     prefs->accelerated_compositing_for_animation_enabled = false;
    818   }
    819   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO))
    820     prefs->accelerated_compositing_for_video_enabled = false;
    821 
    822   // Accelerated video and animation are slower than regular when using
    823   // SwiftShader. 3D CSS may also be too slow to be worthwhile.
    824   if (ShouldUseSwiftShader()) {
    825     prefs->accelerated_compositing_for_video_enabled = false;
    826     prefs->accelerated_compositing_for_animation_enabled = false;
    827     prefs->accelerated_compositing_for_3d_transforms_enabled = false;
    828     prefs->accelerated_compositing_for_plugins_enabled = false;
    829   }
    830 
    831   if (use_software_compositor_) {
    832     prefs->force_compositing_mode = true;
    833     prefs->accelerated_compositing_enabled = true;
    834     prefs->accelerated_compositing_for_3d_transforms_enabled = true;
    835     prefs->accelerated_compositing_for_plugins_enabled = true;
    836   }
    837 
    838 #if defined(USE_AURA)
    839   if (!CanUseGpuBrowserCompositor())
    840     prefs->accelerated_2d_canvas_enabled = false;
    841 #endif
    842 }
    843 
    844 gpu::GpuSwitchingOption
    845 GpuDataManagerImplPrivate::GetGpuSwitchingOption() const {
    846   if (!ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus())
    847     return gpu::GPU_SWITCHING_OPTION_UNKNOWN;
    848   return gpu_switching_;
    849 }
    850 
    851 void GpuDataManagerImplPrivate::DisableHardwareAcceleration() {
    852   card_blacklisted_ = true;
    853 
    854   for (int i = 0; i < gpu::NUMBER_OF_GPU_FEATURE_TYPES; ++i)
    855     blacklisted_features_.insert(i);
    856 
    857   EnableSwiftShaderIfNecessary();
    858   NotifyGpuInfoUpdate();
    859 }
    860 
    861 std::string GpuDataManagerImplPrivate::GetBlacklistVersion() const {
    862   if (gpu_blacklist_)
    863     return gpu_blacklist_->version();
    864   return "0";
    865 }
    866 
    867 std::string GpuDataManagerImplPrivate::GetDriverBugListVersion() const {
    868   if (gpu_driver_bug_list_)
    869     return gpu_driver_bug_list_->version();
    870   return "0";
    871 }
    872 
    873 void GpuDataManagerImplPrivate::GetBlacklistReasons(
    874     base::ListValue* reasons) const {
    875   if (gpu_blacklist_)
    876     gpu_blacklist_->GetReasons(reasons);
    877 }
    878 
    879 void GpuDataManagerImplPrivate::GetDriverBugWorkarounds(
    880     base::ListValue* workarounds) const {
    881   for (std::set<int>::const_iterator it = gpu_driver_bugs_.begin();
    882        it != gpu_driver_bugs_.end(); ++it) {
    883     workarounds->AppendString(
    884         gpu::GpuDriverBugWorkaroundTypeToString(
    885             static_cast<gpu::GpuDriverBugWorkaroundType>(*it)));
    886   }
    887 }
    888 
    889 void GpuDataManagerImplPrivate::AddLogMessage(
    890     int level, const std::string& header, const std::string& message) {
    891   base::DictionaryValue* dict = new base::DictionaryValue();
    892   dict->SetInteger("level", level);
    893   dict->SetString("header", header);
    894   dict->SetString("message", message);
    895   log_messages_.Append(dict);
    896 }
    897 
    898 void GpuDataManagerImplPrivate::ProcessCrashed(
    899     base::TerminationStatus exit_code) {
    900   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    901     // Unretained is ok, because it's posted to UI thread, the thread
    902     // where the singleton GpuDataManagerImpl lives until the end.
    903     BrowserThread::PostTask(
    904         BrowserThread::UI,
    905         FROM_HERE,
    906         base::Bind(&GpuDataManagerImpl::ProcessCrashed,
    907                    base::Unretained(owner_),
    908                    exit_code));
    909     return;
    910   }
    911   {
    912     GpuDataManagerImpl::UnlockedSession session(owner_);
    913     observer_list_->Notify(
    914         &GpuDataManagerObserver::OnGpuProcessCrashed, exit_code);
    915   }
    916 }
    917 
    918 base::ListValue* GpuDataManagerImplPrivate::GetLogMessages() const {
    919   base::ListValue* value;
    920   value = log_messages_.DeepCopy();
    921   return value;
    922 }
    923 
    924 void GpuDataManagerImplPrivate::HandleGpuSwitch() {
    925   GpuDataManagerImpl::UnlockedSession session(owner_);
    926   observer_list_->Notify(&GpuDataManagerObserver::OnGpuSwitching);
    927 }
    928 
    929 #if defined(OS_WIN)
    930 bool GpuDataManagerImplPrivate::IsUsingAcceleratedSurface() const {
    931   if (base::win::GetVersion() < base::win::VERSION_VISTA)
    932     return false;
    933 
    934   if (use_swiftshader_)
    935     return false;
    936   CommandLine* command_line = CommandLine::ForCurrentProcess();
    937   if (command_line->HasSwitch(switches::kDisableImageTransportSurface))
    938     return false;
    939   return !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_TEXTURE_SHARING);
    940 }
    941 #endif
    942 
    943 bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const {
    944   return !ShouldUseSwiftShader() &&
    945          !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) &&
    946          !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FORCE_COMPOSITING_MODE);
    947 }
    948 
    949 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIs(
    950     const GURL& url, GpuDataManagerImpl::DomainGuilt guilt) {
    951   BlockDomainFrom3DAPIsAtTime(url, guilt, base::Time::Now());
    952 }
    953 
    954 bool GpuDataManagerImplPrivate::Are3DAPIsBlocked(const GURL& url,
    955                                                  int render_process_id,
    956                                                  int render_view_id,
    957                                                  ThreeDAPIType requester) {
    958   bool blocked = Are3DAPIsBlockedAtTime(url, base::Time::Now()) !=
    959       GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
    960   if (blocked) {
    961     // Unretained is ok, because it's posted to UI thread, the thread
    962     // where the singleton GpuDataManagerImpl lives until the end.
    963     BrowserThread::PostTask(
    964         BrowserThread::UI, FROM_HERE,
    965         base::Bind(&GpuDataManagerImpl::Notify3DAPIBlocked,
    966                    base::Unretained(owner_), url, render_process_id,
    967                    render_view_id, requester));
    968   }
    969 
    970   return blocked;
    971 }
    972 
    973 void GpuDataManagerImplPrivate::DisableDomainBlockingFor3DAPIsForTesting() {
    974   domain_blocking_enabled_ = false;
    975 }
    976 
    977 // static
    978 GpuDataManagerImplPrivate* GpuDataManagerImplPrivate::Create(
    979     GpuDataManagerImpl* owner) {
    980   return new GpuDataManagerImplPrivate(owner);
    981 }
    982 
    983 GpuDataManagerImplPrivate::GpuDataManagerImplPrivate(
    984     GpuDataManagerImpl* owner)
    985     : complete_gpu_info_already_requested_(false),
    986       gpu_switching_(gpu::GPU_SWITCHING_OPTION_AUTOMATIC),
    987       observer_list_(new GpuDataManagerObserverList),
    988       use_swiftshader_(false),
    989       card_blacklisted_(false),
    990       update_histograms_(true),
    991       window_count_(0),
    992       domain_blocking_enabled_(true),
    993       owner_(owner),
    994       display_count_(0),
    995       gpu_process_accessible_(true),
    996       use_software_compositor_(false) {
    997   DCHECK(owner_);
    998   CommandLine* command_line = CommandLine::ForCurrentProcess();
    999   if (command_line->HasSwitch(switches::kDisableAcceleratedCompositing)) {
   1000     command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
   1001     command_line->AppendSwitch(switches::kDisableAcceleratedLayers);
   1002   }
   1003   if (command_line->HasSwitch(switches::kDisableGpu))
   1004     DisableHardwareAcceleration();
   1005   if (command_line->HasSwitch(switches::kEnableSoftwareCompositing))
   1006     use_software_compositor_ = true;
   1007   //TODO(jbauman): enable for Chrome OS and Linux
   1008 #if defined(USE_AURA) && defined(OS_WIN)
   1009   use_software_compositor_ = true;
   1010 #endif
   1011   if (command_line->HasSwitch(switches::kGpuSwitching)) {
   1012     std::string option_string = command_line->GetSwitchValueASCII(
   1013         switches::kGpuSwitching);
   1014     gpu::GpuSwitchingOption option =
   1015         gpu::StringToGpuSwitchingOption(option_string);
   1016     if (option != gpu::GPU_SWITCHING_OPTION_UNKNOWN)
   1017       gpu_switching_ = option;
   1018   }
   1019 
   1020 #if defined(OS_MACOSX)
   1021   CGGetActiveDisplayList (0, NULL, &display_count_);
   1022   CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback, owner_);
   1023 #endif  // OS_MACOSX
   1024 }
   1025 
   1026 GpuDataManagerImplPrivate::~GpuDataManagerImplPrivate() {
   1027 #if defined(OS_MACOSX)
   1028   CGDisplayRemoveReconfigurationCallback(DisplayReconfigCallback, owner_);
   1029 #endif
   1030 }
   1031 
   1032 void GpuDataManagerImplPrivate::InitializeImpl(
   1033     const std::string& gpu_blacklist_json,
   1034     const std::string& gpu_switching_list_json,
   1035     const std::string& gpu_driver_bug_list_json,
   1036     const gpu::GPUInfo& gpu_info) {
   1037   std::string browser_version_string = ProcessVersionString(
   1038       GetContentClient()->GetProduct());
   1039   CHECK(!browser_version_string.empty());
   1040 
   1041   if (!gpu_blacklist_json.empty()) {
   1042     gpu_blacklist_.reset(gpu::GpuBlacklist::Create());
   1043     gpu_blacklist_->LoadList(
   1044         browser_version_string, gpu_blacklist_json,
   1045         gpu::GpuControlList::kCurrentOsOnly);
   1046   }
   1047   if (!gpu_switching_list_json.empty()) {
   1048     gpu_switching_list_.reset(gpu::GpuSwitchingList::Create());
   1049     gpu_switching_list_->LoadList(
   1050         browser_version_string, gpu_switching_list_json,
   1051         gpu::GpuControlList::kCurrentOsOnly);
   1052   }
   1053   if (!gpu_driver_bug_list_json.empty()) {
   1054     gpu_driver_bug_list_.reset(gpu::GpuDriverBugList::Create());
   1055     gpu_driver_bug_list_->LoadList(
   1056         browser_version_string, gpu_driver_bug_list_json,
   1057         gpu::GpuControlList::kCurrentOsOnly);
   1058   }
   1059 
   1060   gpu_info_ = gpu_info;
   1061   UpdateGpuInfo(gpu_info);
   1062   UpdateGpuSwitchingManager(gpu_info);
   1063   UpdatePreliminaryBlacklistedFeatures();
   1064 
   1065   CommandLine* command_line = CommandLine::ForCurrentProcess();
   1066   // We pass down the list to GPU command buffer through commandline
   1067   // switches at GPU process launch. However, in situations where we don't
   1068   // have a GPU process, we append the browser process commandline.
   1069   if (command_line->HasSwitch(switches::kSingleProcess) ||
   1070       command_line->HasSwitch(switches::kInProcessGPU)) {
   1071     if (!gpu_driver_bugs_.empty()) {
   1072       command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
   1073                                       IntSetToString(gpu_driver_bugs_));
   1074     }
   1075   }
   1076 #if defined(OS_ANDROID)
   1077   ApplyAndroidWorkarounds(gpu_info, command_line);
   1078 #endif  // OS_ANDROID
   1079 }
   1080 
   1081 void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures(
   1082     const std::set<int>& features) {
   1083   CommandLine* command_line = CommandLine::ForCurrentProcess();
   1084   blacklisted_features_ = features;
   1085 
   1086   // Force disable using the GPU for these features, even if they would
   1087   // otherwise be allowed.
   1088   if (card_blacklisted_ ||
   1089       command_line->HasSwitch(switches::kBlacklistAcceleratedCompositing)) {
   1090     blacklisted_features_.insert(
   1091         gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING);
   1092   }
   1093   if (card_blacklisted_ ||
   1094       command_line->HasSwitch(switches::kBlacklistWebGL)) {
   1095     blacklisted_features_.insert(gpu::GPU_FEATURE_TYPE_WEBGL);
   1096   }
   1097 
   1098   EnableSwiftShaderIfNecessary();
   1099 }
   1100 
   1101 void GpuDataManagerImplPrivate::UpdatePreliminaryBlacklistedFeatures() {
   1102   preliminary_blacklisted_features_ = blacklisted_features_;
   1103 }
   1104 
   1105 void GpuDataManagerImplPrivate::UpdateGpuSwitchingManager(
   1106     const gpu::GPUInfo& gpu_info) {
   1107   ui::GpuSwitchingManager::GetInstance()->SetGpuCount(
   1108       gpu_info.secondary_gpus.size() + 1);
   1109 
   1110   if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
   1111     switch (gpu_switching_) {
   1112       case gpu::GPU_SWITCHING_OPTION_FORCE_DISCRETE:
   1113         ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu();
   1114         break;
   1115       case gpu::GPU_SWITCHING_OPTION_FORCE_INTEGRATED:
   1116         ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu();
   1117         break;
   1118       case gpu::GPU_SWITCHING_OPTION_AUTOMATIC:
   1119       case gpu::GPU_SWITCHING_OPTION_UNKNOWN:
   1120         break;
   1121     }
   1122   }
   1123 }
   1124 
   1125 void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() {
   1126   observer_list_->Notify(&GpuDataManagerObserver::OnGpuInfoUpdate);
   1127 }
   1128 
   1129 void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() {
   1130   if (!GpuAccessAllowed(NULL) ||
   1131       blacklisted_features_.count(gpu::GPU_FEATURE_TYPE_WEBGL)) {
   1132     if (!swiftshader_path_.empty() &&
   1133         !CommandLine::ForCurrentProcess()->HasSwitch(
   1134              switches::kDisableSoftwareRasterizer))
   1135       use_swiftshader_ = true;
   1136   }
   1137 }
   1138 
   1139 std::string GpuDataManagerImplPrivate::GetDomainFromURL(
   1140     const GURL& url) const {
   1141   // For the moment, we just use the host, or its IP address, as the
   1142   // entry in the set, rather than trying to figure out the top-level
   1143   // domain. This does mean that a.foo.com and b.foo.com will be
   1144   // treated independently in the blocking of a given domain, but it
   1145   // would require a third-party library to reliably figure out the
   1146   // top-level domain from a URL.
   1147   if (!url.has_host()) {
   1148     return std::string();
   1149   }
   1150 
   1151   return url.host();
   1152 }
   1153 
   1154 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIsAtTime(
   1155     const GURL& url,
   1156     GpuDataManagerImpl::DomainGuilt guilt,
   1157     base::Time at_time) {
   1158   if (!domain_blocking_enabled_)
   1159     return;
   1160 
   1161   std::string domain = GetDomainFromURL(url);
   1162 
   1163   DomainBlockEntry& entry = blocked_domains_[domain];
   1164   entry.last_guilt = guilt;
   1165   timestamps_of_gpu_resets_.push_back(at_time);
   1166 }
   1167 
   1168 GpuDataManagerImpl::DomainBlockStatus
   1169 GpuDataManagerImplPrivate::Are3DAPIsBlockedAtTime(
   1170     const GURL& url, base::Time at_time) const {
   1171   if (!domain_blocking_enabled_)
   1172     return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
   1173 
   1174   // Note: adjusting the policies in this code will almost certainly
   1175   // require adjusting the associated unit tests.
   1176   std::string domain = GetDomainFromURL(url);
   1177 
   1178   DomainBlockMap::const_iterator iter = blocked_domains_.find(domain);
   1179   if (iter != blocked_domains_.end()) {
   1180     // Err on the side of caution, and assume that if a particular
   1181     // domain shows up in the block map, it's there for a good
   1182     // reason and don't let its presence there automatically expire.
   1183 
   1184     UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
   1185                               BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
   1186                               BLOCK_STATUS_MAX);
   1187 
   1188     return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED;
   1189   }
   1190 
   1191   // Look at the timestamps of the recent GPU resets to see if there are
   1192   // enough within the threshold which would cause us to blacklist all
   1193   // domains. This doesn't need to be overly precise -- if time goes
   1194   // backward due to a system clock adjustment, that's fine.
   1195   //
   1196   // TODO(kbr): make this pay attention to the TDR thresholds in the
   1197   // Windows registry, but make sure it continues to be testable.
   1198   {
   1199     std::list<base::Time>::iterator iter = timestamps_of_gpu_resets_.begin();
   1200     int num_resets_within_timeframe = 0;
   1201     while (iter != timestamps_of_gpu_resets_.end()) {
   1202       base::Time time = *iter;
   1203       base::TimeDelta delta_t = at_time - time;
   1204 
   1205       // If this entry has "expired", just remove it.
   1206       if (delta_t.InMilliseconds() > kBlockAllDomainsMs) {
   1207         iter = timestamps_of_gpu_resets_.erase(iter);
   1208         continue;
   1209       }
   1210 
   1211       ++num_resets_within_timeframe;
   1212       ++iter;
   1213     }
   1214 
   1215     if (num_resets_within_timeframe >= kNumResetsWithinDuration) {
   1216       UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
   1217                                 BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
   1218                                 BLOCK_STATUS_MAX);
   1219 
   1220       return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED;
   1221     }
   1222   }
   1223 
   1224   UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
   1225                             BLOCK_STATUS_NOT_BLOCKED,
   1226                             BLOCK_STATUS_MAX);
   1227 
   1228   return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
   1229 }
   1230 
   1231 int64 GpuDataManagerImplPrivate::GetBlockAllDomainsDurationInMs() const {
   1232   return kBlockAllDomainsMs;
   1233 }
   1234 
   1235 void GpuDataManagerImplPrivate::Notify3DAPIBlocked(const GURL& url,
   1236                                                    int render_process_id,
   1237                                                    int render_view_id,
   1238                                                    ThreeDAPIType requester) {
   1239   GpuDataManagerImpl::UnlockedSession session(owner_);
   1240   observer_list_->Notify(&GpuDataManagerObserver::DidBlock3DAPIs,
   1241                          url, render_process_id, render_view_id, requester);
   1242 }
   1243 
   1244 void GpuDataManagerImplPrivate::OnGpuProcessInitFailure() {
   1245   gpu_process_accessible_ = false;
   1246   gpu_info_.finalized = true;
   1247   complete_gpu_info_already_requested_ = true;
   1248   // Some observers might be waiting.
   1249   NotifyGpuInfoUpdate();
   1250 }
   1251 
   1252 }  // namespace content
   1253 
   1254