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 "content/public/common/web_preferences.h"
     27 #include "gpu/command_buffer/service/gpu_switches.h"
     28 #include "gpu/config/gpu_control_list_jsons.h"
     29 #include "gpu/config/gpu_driver_bug_workaround_type.h"
     30 #include "gpu/config/gpu_feature_type.h"
     31 #include "gpu/config/gpu_info_collector.h"
     32 #include "gpu/config/gpu_util.h"
     33 #include "ui/base/ui_base_switches.h"
     34 #include "ui/gl/gl_implementation.h"
     35 #include "ui/gl/gl_switches.h"
     36 #include "ui/gl/gpu_switching_manager.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 "ui/gfx/android/device_display_info.h"
     46 #endif  // OS_ANDROID
     47 
     48 namespace content {
     49 
     50 namespace {
     51 
     52 enum GpuFeatureStatus {
     53     kGpuFeatureEnabled = 0,
     54     kGpuFeatureBlacklisted = 1,
     55     kGpuFeatureDisabled = 2,  // disabled by user but not blacklisted
     56     kGpuFeatureNumStatus
     57 };
     58 
     59 #if defined(OS_WIN)
     60 
     61 enum WinSubVersion {
     62   kWinOthers = 0,
     63   kWinXP,
     64   kWinVista,
     65   kWin7,
     66   kWin8,
     67   kNumWinSubVersions
     68 };
     69 
     70 int GetGpuBlacklistHistogramValueWin(GpuFeatureStatus status) {
     71   static WinSubVersion sub_version = kNumWinSubVersions;
     72   if (sub_version == kNumWinSubVersions) {
     73     sub_version = kWinOthers;
     74     std::string version_str = base::SysInfo::OperatingSystemVersion();
     75     size_t pos = version_str.find_first_not_of("0123456789.");
     76     if (pos != std::string::npos)
     77       version_str = version_str.substr(0, pos);
     78     Version os_version(version_str);
     79     if (os_version.IsValid() && os_version.components().size() >= 2) {
     80       const std::vector<uint16>& version_numbers = os_version.components();
     81       if (version_numbers[0] == 5)
     82         sub_version = kWinXP;
     83       else if (version_numbers[0] == 6 && version_numbers[1] == 0)
     84         sub_version = kWinVista;
     85       else if (version_numbers[0] == 6 && version_numbers[1] == 1)
     86         sub_version = kWin7;
     87       else if (version_numbers[0] == 6 && version_numbers[1] == 2)
     88         sub_version = kWin8;
     89     }
     90   }
     91   int entry_index = static_cast<int>(sub_version) * kGpuFeatureNumStatus;
     92   switch (status) {
     93     case kGpuFeatureEnabled:
     94       break;
     95     case kGpuFeatureBlacklisted:
     96       entry_index++;
     97       break;
     98     case kGpuFeatureDisabled:
     99       entry_index += 2;
    100       break;
    101   }
    102   return entry_index;
    103 }
    104 #endif  // OS_WIN
    105 
    106 // Send UMA histograms about the enabled features and GPU properties.
    107 void UpdateStats(const gpu::GPUInfo& gpu_info,
    108                  const gpu::GpuBlacklist* blacklist,
    109                  const std::set<int>& blacklisted_features) {
    110   uint32 max_entry_id = blacklist->max_entry_id();
    111   if (max_entry_id == 0) {
    112     // GPU Blacklist was not loaded.  No need to go further.
    113     return;
    114   }
    115 
    116   const base::CommandLine& command_line =
    117       *base::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 (uint32 disabled_entry : flag_disabled_entries) {
    143     UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerDisabledEntry",
    144         disabled_entry, max_entry_id + 1);
    145   }
    146 
    147   const gpu::GpuFeatureType kGpuFeatures[] = {
    148       gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS,
    149       gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING, gpu::GPU_FEATURE_TYPE_WEBGL};
    150   const std::string kGpuBlacklistFeatureHistogramNames[] = {
    151       "GPU.BlacklistFeatureTestResults.Accelerated2dCanvas",
    152       "GPU.BlacklistFeatureTestResults.GpuCompositing",
    153       "GPU.BlacklistFeatureTestResults.Webgl", };
    154   const bool kGpuFeatureUserFlags[] = {
    155       command_line.HasSwitch(switches::kDisableAccelerated2dCanvas),
    156       command_line.HasSwitch(switches::kDisableGpu),
    157       command_line.HasSwitch(switches::kDisableExperimentalWebGL), };
    158 #if defined(OS_WIN)
    159   const std::string kGpuBlacklistFeatureHistogramNamesWin[] = {
    160       "GPU.BlacklistFeatureTestResultsWindows.Accelerated2dCanvas",
    161       "GPU.BlacklistFeatureTestResultsWindows.GpuCompositing",
    162       "GPU.BlacklistFeatureTestResultsWindows.Webgl", };
    163 #endif
    164   const size_t kNumFeatures =
    165       sizeof(kGpuFeatures) / sizeof(gpu::GpuFeatureType);
    166   for (size_t i = 0; i < kNumFeatures; ++i) {
    167     // We can't use UMA_HISTOGRAM_ENUMERATION here because the same name is
    168     // expected if the macro is used within a loop.
    169     GpuFeatureStatus value = kGpuFeatureEnabled;
    170     if (blacklisted_features.count(kGpuFeatures[i]))
    171       value = kGpuFeatureBlacklisted;
    172     else if (kGpuFeatureUserFlags[i])
    173       value = kGpuFeatureDisabled;
    174     base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
    175         kGpuBlacklistFeatureHistogramNames[i],
    176         1, kGpuFeatureNumStatus, kGpuFeatureNumStatus + 1,
    177         base::HistogramBase::kUmaTargetedHistogramFlag);
    178     histogram_pointer->Add(value);
    179 #if defined(OS_WIN)
    180     histogram_pointer = base::LinearHistogram::FactoryGet(
    181         kGpuBlacklistFeatureHistogramNamesWin[i],
    182         1, kNumWinSubVersions * kGpuFeatureNumStatus,
    183         kNumWinSubVersions * kGpuFeatureNumStatus + 1,
    184         base::HistogramBase::kUmaTargetedHistogramFlag);
    185     histogram_pointer->Add(GetGpuBlacklistHistogramValueWin(value));
    186 #endif
    187   }
    188 
    189   UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.GLResetNotificationStrategy",
    190       gpu_info.gl_reset_notification_strategy);
    191 }
    192 
    193 // Combine the integers into a string, seperated by ','.
    194 std::string IntSetToString(const std::set<int>& list) {
    195   std::string rt;
    196   for (std::set<int>::const_iterator it = list.begin();
    197        it != list.end(); ++it) {
    198     if (!rt.empty())
    199       rt += ",";
    200     rt += base::IntToString(*it);
    201   }
    202   return rt;
    203 }
    204 
    205 #if defined(OS_MACOSX)
    206 void DisplayReconfigCallback(CGDirectDisplayID display,
    207                              CGDisplayChangeSummaryFlags flags,
    208                              void* gpu_data_manager) {
    209   if (flags == kCGDisplayBeginConfigurationFlag)
    210     return; // This call contains no information about the display change
    211 
    212   GpuDataManagerImpl* manager =
    213       reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager);
    214   DCHECK(manager);
    215 
    216   // Display change.
    217   bool display_changed = false;
    218   uint32_t displayCount;
    219   CGGetActiveDisplayList(0, NULL, &displayCount);
    220   if (displayCount != manager->GetDisplayCount()) {
    221     manager->SetDisplayCount(displayCount);
    222     display_changed = true;
    223   }
    224 
    225   // Gpu change.
    226   bool gpu_changed = false;
    227   if (flags & kCGDisplayAddFlag) {
    228     uint32 vendor_id, device_id;
    229     if (gpu::CollectGpuID(&vendor_id, &device_id) == gpu::kCollectInfoSuccess) {
    230       gpu_changed = manager->UpdateActiveGpu(vendor_id, device_id);
    231     }
    232   }
    233 
    234   if (display_changed || gpu_changed)
    235     manager->HandleGpuSwitch();
    236 }
    237 #endif  // OS_MACOSX
    238 
    239 // Block all domains' use of 3D APIs for this many milliseconds if
    240 // approaching a threshold where system stability might be compromised.
    241 const int64 kBlockAllDomainsMs = 10000;
    242 const int kNumResetsWithinDuration = 1;
    243 
    244 // Enums for UMA histograms.
    245 enum BlockStatusHistogram {
    246   BLOCK_STATUS_NOT_BLOCKED,
    247   BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
    248   BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
    249   BLOCK_STATUS_MAX
    250 };
    251 
    252 }  // namespace anonymous
    253 
    254 void GpuDataManagerImplPrivate::InitializeForTesting(
    255     const std::string& gpu_blacklist_json,
    256     const gpu::GPUInfo& gpu_info) {
    257   // This function is for testing only, so disable histograms.
    258   update_histograms_ = false;
    259 
    260   // Prevent all further initialization.
    261   finalized_ = true;
    262 
    263   InitializeImpl(gpu_blacklist_json, std::string(), gpu_info);
    264 }
    265 
    266 bool GpuDataManagerImplPrivate::IsFeatureBlacklisted(int feature) const {
    267 #if defined(OS_CHROMEOS)
    268   if (feature == gpu::GPU_FEATURE_TYPE_PANEL_FITTING &&
    269       base::CommandLine::ForCurrentProcess()->HasSwitch(
    270           switches::kDisablePanelFitting)) {
    271     return true;
    272   }
    273 #endif  // OS_CHROMEOS
    274   if (use_swiftshader_ || ShouldUseWarp()) {
    275     // Skia's software rendering is probably more efficient than going through
    276     // software emulation of the GPU, so use that.
    277     if (feature == gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)
    278       return true;
    279     return false;
    280   }
    281 
    282   return (blacklisted_features_.count(feature) == 1);
    283 }
    284 
    285 bool GpuDataManagerImplPrivate::IsDriverBugWorkaroundActive(int feature) const {
    286   return (gpu_driver_bugs_.count(feature) == 1);
    287 }
    288 
    289 size_t GpuDataManagerImplPrivate::GetBlacklistedFeatureCount() const {
    290   if (use_swiftshader_ || ShouldUseWarp())
    291     return 1;
    292   return blacklisted_features_.size();
    293 }
    294 
    295 void GpuDataManagerImplPrivate::SetDisplayCount(unsigned int display_count) {
    296   display_count_ = display_count;
    297 }
    298 
    299 unsigned int GpuDataManagerImplPrivate::GetDisplayCount() const {
    300   return display_count_;
    301 }
    302 
    303 gpu::GPUInfo GpuDataManagerImplPrivate::GetGPUInfo() const {
    304   return gpu_info_;
    305 }
    306 
    307 void GpuDataManagerImplPrivate::GetGpuProcessHandles(
    308     const GpuDataManager::GetGpuProcessHandlesCallback& callback) const {
    309   GpuProcessHost::GetProcessHandles(callback);
    310 }
    311 
    312 bool GpuDataManagerImplPrivate::GpuAccessAllowed(
    313     std::string* reason) const {
    314   if (use_swiftshader_ || ShouldUseWarp())
    315     return true;
    316 
    317   if (!gpu_process_accessible_) {
    318     if (reason) {
    319       *reason = "GPU process launch failed.";
    320     }
    321     return false;
    322   }
    323 
    324   if (card_blacklisted_) {
    325     if (reason) {
    326       *reason = "GPU access is disabled ";
    327       base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
    328       if (command_line->HasSwitch(switches::kDisableGpu))
    329         *reason += "through commandline switch --disable-gpu.";
    330       else
    331         *reason += "in chrome://settings.";
    332     }
    333     return false;
    334   }
    335 
    336   // We only need to block GPU process if more features are disallowed other
    337   // than those in the preliminary gpu feature flags because the latter work
    338   // through renderer commandline switches.
    339   std::set<int> features = preliminary_blacklisted_features_;
    340   gpu::MergeFeatureSets(&features, blacklisted_features_);
    341   if (features.size() > preliminary_blacklisted_features_.size()) {
    342     if (reason) {
    343       *reason = "Features are disabled upon full but not preliminary GPU info.";
    344     }
    345     return false;
    346   }
    347 
    348   if (blacklisted_features_.size() == gpu::NUMBER_OF_GPU_FEATURE_TYPES) {
    349     // On Linux, we use cached GL strings to make blacklist decsions at browser
    350     // startup time. We need to launch the GPU process to validate these
    351     // strings even if all features are blacklisted. If all GPU features are
    352     // disabled, the GPU process will only initialize GL bindings, create a GL
    353     // context, and collect full GPU info.
    354 #if !defined(OS_LINUX)
    355     if (reason) {
    356       *reason = "All GPU features are blacklisted.";
    357     }
    358     return false;
    359 #endif
    360   }
    361 
    362   return true;
    363 }
    364 
    365 void GpuDataManagerImplPrivate::RequestCompleteGpuInfoIfNeeded() {
    366   if (complete_gpu_info_already_requested_ || IsCompleteGpuInfoAvailable())
    367     return;
    368   complete_gpu_info_already_requested_ = true;
    369 
    370   GpuProcessHost::SendOnIO(
    371 #if defined(OS_WIN)
    372       GpuProcessHost::GPU_PROCESS_KIND_UNSANDBOXED,
    373 #else
    374       GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
    375 #endif
    376       CAUSE_FOR_GPU_LAUNCH_GPUDATAMANAGER_REQUESTCOMPLETEGPUINFOIFNEEDED,
    377       new GpuMsg_CollectGraphicsInfo());
    378 }
    379 
    380 bool GpuDataManagerImplPrivate::IsEssentialGpuInfoAvailable() const {
    381   if (gpu_info_.basic_info_state == gpu::kCollectInfoNone ||
    382       gpu_info_.context_info_state == gpu::kCollectInfoNone) {
    383     return false;
    384   }
    385   return true;
    386 }
    387 
    388 bool GpuDataManagerImplPrivate::IsCompleteGpuInfoAvailable() const {
    389 #if defined(OS_WIN)
    390   if (gpu_info_.dx_diagnostics_info_state == gpu::kCollectInfoNone)
    391     return false;
    392 #endif
    393   return IsEssentialGpuInfoAvailable();
    394 }
    395 
    396 void GpuDataManagerImplPrivate::RequestVideoMemoryUsageStatsUpdate() const {
    397   GpuProcessHost::SendOnIO(
    398       GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
    399       CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
    400       new GpuMsg_GetVideoMemoryUsageStats());
    401 }
    402 
    403 bool GpuDataManagerImplPrivate::ShouldUseSwiftShader() const {
    404   return use_swiftshader_;
    405 }
    406 
    407 void GpuDataManagerImplPrivate::RegisterSwiftShaderPath(
    408     const base::FilePath& path) {
    409   swiftshader_path_ = path;
    410   EnableSwiftShaderIfNecessary();
    411 }
    412 
    413 bool GpuDataManagerImplPrivate::ShouldUseWarp() const {
    414   return use_warp_ ||
    415       CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseWarp);
    416 }
    417 
    418 void GpuDataManagerImplPrivate::AddObserver(GpuDataManagerObserver* observer) {
    419   GpuDataManagerImpl::UnlockedSession session(owner_);
    420   observer_list_->AddObserver(observer);
    421 }
    422 
    423 void GpuDataManagerImplPrivate::RemoveObserver(
    424     GpuDataManagerObserver* observer) {
    425   GpuDataManagerImpl::UnlockedSession session(owner_);
    426   observer_list_->RemoveObserver(observer);
    427 }
    428 
    429 void GpuDataManagerImplPrivate::UnblockDomainFrom3DAPIs(const GURL& url) {
    430   // This method must do two things:
    431   //
    432   //  1. If the specific domain is blocked, then unblock it.
    433   //
    434   //  2. Reset our notion of how many GPU resets have occurred recently.
    435   //     This is necessary even if the specific domain was blocked.
    436   //     Otherwise, if we call Are3DAPIsBlocked with the same domain right
    437   //     after unblocking it, it will probably still be blocked because of
    438   //     the recent GPU reset caused by that domain.
    439   //
    440   // These policies could be refined, but at a certain point the behavior
    441   // will become difficult to explain.
    442   std::string domain = GetDomainFromURL(url);
    443 
    444   blocked_domains_.erase(domain);
    445   timestamps_of_gpu_resets_.clear();
    446 }
    447 
    448 void GpuDataManagerImplPrivate::DisableGpuWatchdog() {
    449   GpuProcessHost::SendOnIO(
    450       GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
    451       CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
    452       new GpuMsg_DisableWatchdog);
    453 }
    454 
    455 void GpuDataManagerImplPrivate::SetGLStrings(const std::string& gl_vendor,
    456                                              const std::string& gl_renderer,
    457                                              const std::string& gl_version) {
    458   if (gl_vendor.empty() && gl_renderer.empty() && gl_version.empty())
    459     return;
    460 
    461   // If GPUInfo already got GL strings, do nothing.  This is for the rare
    462   // situation where GPU process collected GL strings before this call.
    463   if (!gpu_info_.gl_vendor.empty() ||
    464       !gpu_info_.gl_renderer.empty() ||
    465       !gpu_info_.gl_version.empty())
    466     return;
    467 
    468   gpu::GPUInfo gpu_info = gpu_info_;
    469 
    470   gpu_info.gl_vendor = gl_vendor;
    471   gpu_info.gl_renderer = gl_renderer;
    472   gpu_info.gl_version = gl_version;
    473 
    474   gpu::CollectDriverInfoGL(&gpu_info);
    475 
    476   UpdateGpuInfo(gpu_info);
    477   UpdateGpuSwitchingManager(gpu_info);
    478   UpdatePreliminaryBlacklistedFeatures();
    479 }
    480 
    481 void GpuDataManagerImplPrivate::GetGLStrings(std::string* gl_vendor,
    482                                              std::string* gl_renderer,
    483                                              std::string* gl_version) {
    484   DCHECK(gl_vendor && gl_renderer && gl_version);
    485 
    486   *gl_vendor = gpu_info_.gl_vendor;
    487   *gl_renderer = gpu_info_.gl_renderer;
    488   *gl_version = gpu_info_.gl_version;
    489 }
    490 
    491 void GpuDataManagerImplPrivate::Initialize() {
    492   TRACE_EVENT0("startup", "GpuDataManagerImpl::Initialize");
    493   if (finalized_) {
    494     DVLOG(0) << "GpuDataManagerImpl marked as finalized; skipping Initialize";
    495     return;
    496   }
    497 
    498   const base::CommandLine* command_line =
    499       base::CommandLine::ForCurrentProcess();
    500   if (command_line->HasSwitch(switches::kSkipGpuDataLoading))
    501     return;
    502 
    503   gpu::GPUInfo gpu_info;
    504   if (command_line->GetSwitchValueASCII(
    505           switches::kUseGL) == gfx::kGLImplementationOSMesaName) {
    506     // If using the OSMesa GL implementation, use fake vendor and device ids to
    507     // make sure it never gets blacklisted. This is better than simply
    508     // cancelling GPUInfo gathering as it allows us to proceed with loading the
    509     // blacklist below which may have non-device specific entries we want to
    510     // apply anyways (e.g., OS version blacklisting).
    511     gpu_info.gpu.vendor_id = 0xffff;
    512     gpu_info.gpu.device_id = 0xffff;
    513 
    514     // Also declare the driver_vendor to be osmesa to be able to specify
    515     // exceptions based on driver_vendor==osmesa for some blacklist rules.
    516     gpu_info.driver_vendor = gfx::kGLImplementationOSMesaName;
    517   } else {
    518     TRACE_EVENT0("startup",
    519       "GpuDataManagerImpl::Initialize:CollectBasicGraphicsInfo");
    520     gpu::CollectBasicGraphicsInfo(&gpu_info);
    521   }
    522 #if defined(ARCH_CPU_X86_FAMILY)
    523   if (!gpu_info.gpu.vendor_id || !gpu_info.gpu.device_id) {
    524     gpu_info.context_info_state = gpu::kCollectInfoNonFatalFailure;
    525 #if defined(OS_WIN)
    526     gpu_info.dx_diagnostics_info_state = gpu::kCollectInfoNonFatalFailure;
    527 #endif  // OS_WIN
    528   }
    529 #endif  // ARCH_CPU_X86_FAMILY
    530 
    531   std::string gpu_blacklist_string;
    532   std::string gpu_driver_bug_list_string;
    533   if (!command_line->HasSwitch(switches::kIgnoreGpuBlacklist) &&
    534       !command_line->HasSwitch(switches::kUseGpuInTests)) {
    535     gpu_blacklist_string = gpu::kSoftwareRenderingListJson;
    536   }
    537   if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
    538     gpu_driver_bug_list_string = gpu::kGpuDriverBugListJson;
    539   }
    540   InitializeImpl(gpu_blacklist_string,
    541                  gpu_driver_bug_list_string,
    542                  gpu_info);
    543 }
    544 
    545 void GpuDataManagerImplPrivate::UpdateGpuInfoHelper() {
    546   GetContentClient()->SetGpuInfo(gpu_info_);
    547 
    548   if (gpu_blacklist_) {
    549     std::set<int> features = gpu_blacklist_->MakeDecision(
    550         gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
    551     if (update_histograms_)
    552       UpdateStats(gpu_info_, gpu_blacklist_.get(), features);
    553 
    554     UpdateBlacklistedFeatures(features);
    555   }
    556   if (gpu_driver_bug_list_) {
    557     gpu_driver_bugs_ = gpu_driver_bug_list_->MakeDecision(
    558         gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
    559   }
    560   gpu::GpuDriverBugList::AppendWorkaroundsFromCommandLine(
    561       &gpu_driver_bugs_, *base::CommandLine::ForCurrentProcess());
    562 
    563   // We have to update GpuFeatureType before notify all the observers.
    564   NotifyGpuInfoUpdate();
    565 }
    566 
    567 void GpuDataManagerImplPrivate::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) {
    568   // No further update of gpu_info if falling back to SwiftShader.
    569   if (use_swiftshader_ || ShouldUseWarp())
    570     return;
    571 
    572   gpu::MergeGPUInfo(&gpu_info_, gpu_info);
    573   if (IsCompleteGpuInfoAvailable())
    574     complete_gpu_info_already_requested_ = true;
    575 
    576   UpdateGpuInfoHelper();
    577 }
    578 
    579 void GpuDataManagerImplPrivate::UpdateVideoMemoryUsageStats(
    580     const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
    581   GpuDataManagerImpl::UnlockedSession session(owner_);
    582   observer_list_->Notify(&GpuDataManagerObserver::OnVideoMemoryUsageStatsUpdate,
    583                          video_memory_usage_stats);
    584 }
    585 
    586 void GpuDataManagerImplPrivate::AppendRendererCommandLine(
    587     base::CommandLine* command_line) const {
    588   DCHECK(command_line);
    589 
    590   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
    591       !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
    592     command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
    593 #if defined(ENABLE_WEBRTC)
    594   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_ENCODE) &&
    595       !command_line->HasSwitch(switches::kDisableWebRtcHWEncoding))
    596     command_line->AppendSwitch(switches::kDisableWebRtcHWEncoding);
    597 #endif
    598 
    599 #if defined(USE_AURA)
    600   if (!CanUseGpuBrowserCompositor())
    601     command_line->AppendSwitch(switches::kDisableGpuCompositing);
    602 #endif
    603 }
    604 
    605 void GpuDataManagerImplPrivate::AppendGpuCommandLine(
    606     base::CommandLine* command_line) const {
    607   DCHECK(command_line);
    608 
    609   std::string use_gl =
    610       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
    611           switches::kUseGL);
    612   base::FilePath swiftshader_path =
    613       base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
    614           switches::kSwiftShaderPath);
    615   if (gpu_driver_bugs_.find(gpu::DISABLE_D3D11) != gpu_driver_bugs_.end())
    616     command_line->AppendSwitch(switches::kDisableD3D11);
    617   if (use_swiftshader_) {
    618     command_line->AppendSwitchASCII(switches::kUseGL, "swiftshader");
    619     if (swiftshader_path.empty())
    620       swiftshader_path = swiftshader_path_;
    621   } else if ((IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL) ||
    622               IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING) ||
    623               IsFeatureBlacklisted(
    624                   gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)) &&
    625              (use_gl == "any")) {
    626     command_line->AppendSwitchASCII(
    627         switches::kUseGL, gfx::kGLImplementationOSMesaName);
    628   } else if (!use_gl.empty()) {
    629     command_line->AppendSwitchASCII(switches::kUseGL, use_gl);
    630   }
    631   if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus())
    632     command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "true");
    633   else
    634     command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "false");
    635 
    636   if (!swiftshader_path.empty()) {
    637     command_line->AppendSwitchPath(switches::kSwiftShaderPath,
    638                                    swiftshader_path);
    639   }
    640 
    641   if (!gpu_driver_bugs_.empty()) {
    642     command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
    643                                     IntSetToString(gpu_driver_bugs_));
    644   }
    645 
    646   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
    647       !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) {
    648     command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
    649   }
    650 #if defined(ENABLE_WEBRTC)
    651   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_ENCODE) &&
    652       !command_line->HasSwitch(switches::kDisableWebRtcHWEncoding)) {
    653     command_line->AppendSwitch(switches::kDisableWebRtcHWEncoding);
    654   }
    655 #endif
    656 
    657   // Pass GPU and driver information to GPU process. We try to avoid full GPU
    658   // info collection at GPU process startup, but we need gpu vendor_id,
    659   // device_id, driver_vendor, driver_version for deciding whether we need to
    660   // collect full info (on Linux) and for crash reporting purpose.
    661   command_line->AppendSwitchASCII(switches::kGpuVendorID,
    662       base::StringPrintf("0x%04x", gpu_info_.gpu.vendor_id));
    663   command_line->AppendSwitchASCII(switches::kGpuDeviceID,
    664       base::StringPrintf("0x%04x", gpu_info_.gpu.device_id));
    665   command_line->AppendSwitchASCII(switches::kGpuDriverVendor,
    666       gpu_info_.driver_vendor);
    667   command_line->AppendSwitchASCII(switches::kGpuDriverVersion,
    668       gpu_info_.driver_version);
    669 
    670   if (ShouldUseWarp())
    671     command_line->AppendSwitch(switches::kUseWarp);
    672 }
    673 
    674 void GpuDataManagerImplPrivate::AppendPluginCommandLine(
    675     base::CommandLine* command_line) const {
    676   DCHECK(command_line);
    677 
    678 #if defined(OS_MACOSX)
    679   // TODO(jbauman): Add proper blacklist support for core animation plugins so
    680   // special-casing this video card won't be necessary. See
    681   // http://crbug.com/134015
    682   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING)) {
    683     if (!command_line->HasSwitch(
    684            switches::kDisableCoreAnimationPlugins))
    685       command_line->AppendSwitch(
    686           switches::kDisableCoreAnimationPlugins);
    687   }
    688 #endif
    689 }
    690 
    691 void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
    692     WebPreferences* prefs) const {
    693   DCHECK(prefs);
    694 
    695   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL)) {
    696     prefs->experimental_webgl_enabled = false;
    697     prefs->pepper_3d_enabled = false;
    698   }
    699   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH3D))
    700     prefs->flash_3d_enabled = false;
    701   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D)) {
    702     prefs->flash_stage3d_enabled = false;
    703     prefs->flash_stage3d_baseline_enabled = false;
    704   }
    705   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE))
    706     prefs->flash_stage3d_baseline_enabled = false;
    707   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS))
    708     prefs->accelerated_2d_canvas_enabled = false;
    709   if (IsDriverBugWorkaroundActive(gpu::DISABLE_MULTISAMPLING) ||
    710       (IsDriverBugWorkaroundActive(gpu::DISABLE_MULTIMONITOR_MULTISAMPLING) &&
    711           display_count_ > 1))
    712     prefs->gl_multisampling_enabled = false;
    713 
    714 #if defined(USE_AURA)
    715   if (!CanUseGpuBrowserCompositor()) {
    716     prefs->accelerated_2d_canvas_enabled = false;
    717     prefs->pepper_3d_enabled = false;
    718   }
    719 #endif
    720 
    721   if (!IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
    722       !base::CommandLine::ForCurrentProcess()->HasSwitch(
    723           switches::kDisableAcceleratedVideoDecode)) {
    724     prefs->pepper_accelerated_video_decode_enabled = true;
    725   }
    726 }
    727 
    728 void GpuDataManagerImplPrivate::DisableHardwareAcceleration() {
    729   card_blacklisted_ = true;
    730 
    731   for (int i = 0; i < gpu::NUMBER_OF_GPU_FEATURE_TYPES; ++i)
    732     blacklisted_features_.insert(i);
    733 
    734   EnableWarpIfNecessary();
    735   EnableSwiftShaderIfNecessary();
    736   NotifyGpuInfoUpdate();
    737 }
    738 
    739 std::string GpuDataManagerImplPrivate::GetBlacklistVersion() const {
    740   if (gpu_blacklist_)
    741     return gpu_blacklist_->version();
    742   return "0";
    743 }
    744 
    745 std::string GpuDataManagerImplPrivate::GetDriverBugListVersion() const {
    746   if (gpu_driver_bug_list_)
    747     return gpu_driver_bug_list_->version();
    748   return "0";
    749 }
    750 
    751 void GpuDataManagerImplPrivate::GetBlacklistReasons(
    752     base::ListValue* reasons) const {
    753   if (gpu_blacklist_)
    754     gpu_blacklist_->GetReasons(reasons, "disabledFeatures");
    755   if (gpu_driver_bug_list_)
    756     gpu_driver_bug_list_->GetReasons(reasons, "workarounds");
    757 }
    758 
    759 void GpuDataManagerImplPrivate::GetDriverBugWorkarounds(
    760     base::ListValue* workarounds) const {
    761   for (std::set<int>::const_iterator it = gpu_driver_bugs_.begin();
    762        it != gpu_driver_bugs_.end(); ++it) {
    763     workarounds->AppendString(
    764         gpu::GpuDriverBugWorkaroundTypeToString(
    765             static_cast<gpu::GpuDriverBugWorkaroundType>(*it)));
    766   }
    767 }
    768 
    769 void GpuDataManagerImplPrivate::AddLogMessage(
    770     int level, const std::string& header, const std::string& message) {
    771   log_messages_.push_back(LogMessage(level, header, message));
    772 }
    773 
    774 void GpuDataManagerImplPrivate::ProcessCrashed(
    775     base::TerminationStatus exit_code) {
    776   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    777     // Unretained is ok, because it's posted to UI thread, the thread
    778     // where the singleton GpuDataManagerImpl lives until the end.
    779     BrowserThread::PostTask(
    780         BrowserThread::UI,
    781         FROM_HERE,
    782         base::Bind(&GpuDataManagerImpl::ProcessCrashed,
    783                    base::Unretained(owner_),
    784                    exit_code));
    785     return;
    786   }
    787   {
    788     gpu_info_.process_crash_count = GpuProcessHost::gpu_crash_count();
    789     GpuDataManagerImpl::UnlockedSession session(owner_);
    790     observer_list_->Notify(
    791         &GpuDataManagerObserver::OnGpuProcessCrashed, exit_code);
    792   }
    793 }
    794 
    795 base::ListValue* GpuDataManagerImplPrivate::GetLogMessages() const {
    796   base::ListValue* value = new base::ListValue;
    797   for (size_t ii = 0; ii < log_messages_.size(); ++ii) {
    798     base::DictionaryValue* dict = new base::DictionaryValue();
    799     dict->SetInteger("level", log_messages_[ii].level);
    800     dict->SetString("header", log_messages_[ii].header);
    801     dict->SetString("message", log_messages_[ii].message);
    802     value->Append(dict);
    803   }
    804   return value;
    805 }
    806 
    807 void GpuDataManagerImplPrivate::HandleGpuSwitch() {
    808   GpuDataManagerImpl::UnlockedSession session(owner_);
    809   observer_list_->Notify(&GpuDataManagerObserver::OnGpuSwitching);
    810 }
    811 
    812 bool GpuDataManagerImplPrivate::UpdateActiveGpu(
    813     uint32 vendor_id, uint32 device_id) {
    814   if (gpu_info_.gpu.vendor_id == vendor_id &&
    815       gpu_info_.gpu.device_id == device_id) {
    816     // The primary GPU is active.
    817     if (gpu_info_.gpu.active)
    818       return false;
    819     gpu_info_.gpu.active = true;
    820     for (size_t ii = 0; ii < gpu_info_.secondary_gpus.size(); ++ii)
    821       gpu_info_.secondary_gpus[ii].active = false;
    822   } else {
    823     // A secondary GPU is active.
    824     for (size_t ii = 0; ii < gpu_info_.secondary_gpus.size(); ++ii) {
    825       if (gpu_info_.secondary_gpus[ii].vendor_id == vendor_id &&
    826           gpu_info_.secondary_gpus[ii].device_id == device_id) {
    827         if (gpu_info_.secondary_gpus[ii].active)
    828           return false;
    829         gpu_info_.secondary_gpus[ii].active = true;
    830       } else {
    831         gpu_info_.secondary_gpus[ii].active = false;
    832       }
    833     }
    834     gpu_info_.gpu.active = false;
    835   }
    836   UpdateGpuInfoHelper();
    837   return true;
    838 }
    839 
    840 bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const {
    841   if (CommandLine::ForCurrentProcess()->HasSwitch(
    842           switches::kDisableGpuCompositing))
    843     return false;
    844   if (ShouldUseWarp())
    845     return true;
    846   if (ShouldUseSwiftShader())
    847     return false;
    848   if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING))
    849     return false;
    850   return true;
    851 }
    852 
    853 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIs(
    854     const GURL& url, GpuDataManagerImpl::DomainGuilt guilt) {
    855   BlockDomainFrom3DAPIsAtTime(url, guilt, base::Time::Now());
    856 }
    857 
    858 bool GpuDataManagerImplPrivate::Are3DAPIsBlocked(const GURL& url,
    859                                                  int render_process_id,
    860                                                  int render_view_id,
    861                                                  ThreeDAPIType requester) {
    862   bool blocked = Are3DAPIsBlockedAtTime(url, base::Time::Now()) !=
    863       GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
    864   if (blocked) {
    865     // Unretained is ok, because it's posted to UI thread, the thread
    866     // where the singleton GpuDataManagerImpl lives until the end.
    867     BrowserThread::PostTask(
    868         BrowserThread::UI, FROM_HERE,
    869         base::Bind(&GpuDataManagerImpl::Notify3DAPIBlocked,
    870                    base::Unretained(owner_), url, render_process_id,
    871                    render_view_id, requester));
    872   }
    873 
    874   return blocked;
    875 }
    876 
    877 void GpuDataManagerImplPrivate::DisableDomainBlockingFor3DAPIsForTesting() {
    878   domain_blocking_enabled_ = false;
    879 }
    880 
    881 // static
    882 GpuDataManagerImplPrivate* GpuDataManagerImplPrivate::Create(
    883     GpuDataManagerImpl* owner) {
    884   return new GpuDataManagerImplPrivate(owner);
    885 }
    886 
    887 GpuDataManagerImplPrivate::GpuDataManagerImplPrivate(
    888     GpuDataManagerImpl* owner)
    889     : complete_gpu_info_already_requested_(false),
    890       observer_list_(new GpuDataManagerObserverList),
    891       use_swiftshader_(false),
    892       use_warp_(false),
    893       card_blacklisted_(false),
    894       update_histograms_(true),
    895       window_count_(0),
    896       domain_blocking_enabled_(true),
    897       owner_(owner),
    898       display_count_(0),
    899       gpu_process_accessible_(true),
    900       finalized_(false) {
    901   DCHECK(owner_);
    902   const base::CommandLine* command_line =
    903       base::CommandLine::ForCurrentProcess();
    904   if (command_line->HasSwitch(switches::kDisableGpu))
    905     DisableHardwareAcceleration();
    906 
    907 #if defined(OS_MACOSX)
    908   CGGetActiveDisplayList (0, NULL, &display_count_);
    909   CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback, owner_);
    910 #endif  // OS_MACOSX
    911 
    912   // For testing only.
    913   if (command_line->HasSwitch(switches::kDisableDomainBlockingFor3DAPIs)) {
    914     domain_blocking_enabled_ = false;
    915   }
    916 }
    917 
    918 GpuDataManagerImplPrivate::~GpuDataManagerImplPrivate() {
    919 #if defined(OS_MACOSX)
    920   CGDisplayRemoveReconfigurationCallback(DisplayReconfigCallback, owner_);
    921 #endif
    922 }
    923 
    924 void GpuDataManagerImplPrivate::InitializeImpl(
    925     const std::string& gpu_blacklist_json,
    926     const std::string& gpu_driver_bug_list_json,
    927     const gpu::GPUInfo& gpu_info) {
    928   const bool log_gpu_control_list_decisions =
    929       base::CommandLine::ForCurrentProcess()->HasSwitch(
    930           switches::kLogGpuControlListDecisions);
    931 
    932   if (!gpu_blacklist_json.empty()) {
    933     gpu_blacklist_.reset(gpu::GpuBlacklist::Create());
    934     if (log_gpu_control_list_decisions)
    935       gpu_blacklist_->enable_control_list_logging("gpu_blacklist");
    936     bool success = gpu_blacklist_->LoadList(
    937         gpu_blacklist_json, gpu::GpuControlList::kCurrentOsOnly);
    938     DCHECK(success);
    939   }
    940   if (!gpu_driver_bug_list_json.empty()) {
    941     gpu_driver_bug_list_.reset(gpu::GpuDriverBugList::Create());
    942     if (log_gpu_control_list_decisions)
    943       gpu_driver_bug_list_->enable_control_list_logging("gpu_driver_bug_list");
    944     bool success = gpu_driver_bug_list_->LoadList(
    945         gpu_driver_bug_list_json, gpu::GpuControlList::kCurrentOsOnly);
    946     DCHECK(success);
    947   }
    948 
    949   gpu_info_ = gpu_info;
    950   UpdateGpuInfo(gpu_info);
    951   UpdateGpuSwitchingManager(gpu_info);
    952   UpdatePreliminaryBlacklistedFeatures();
    953 }
    954 
    955 void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures(
    956     const std::set<int>& features) {
    957   blacklisted_features_ = features;
    958 
    959   // Force disable using the GPU for these features, even if they would
    960   // otherwise be allowed.
    961   if (card_blacklisted_) {
    962     blacklisted_features_.insert(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING);
    963     blacklisted_features_.insert(gpu::GPU_FEATURE_TYPE_WEBGL);
    964   }
    965 
    966   EnableWarpIfNecessary();
    967   EnableSwiftShaderIfNecessary();
    968 }
    969 
    970 void GpuDataManagerImplPrivate::UpdatePreliminaryBlacklistedFeatures() {
    971   preliminary_blacklisted_features_ = blacklisted_features_;
    972 }
    973 
    974 void GpuDataManagerImplPrivate::UpdateGpuSwitchingManager(
    975     const gpu::GPUInfo& gpu_info) {
    976   ui::GpuSwitchingManager::GetInstance()->SetGpuCount(
    977       gpu_info.secondary_gpus.size() + 1);
    978 
    979   if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
    980     if (gpu_driver_bugs_.count(gpu::FORCE_DISCRETE_GPU) == 1)
    981       ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu();
    982     else if (gpu_driver_bugs_.count(gpu::FORCE_INTEGRATED_GPU) == 1)
    983       ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu();
    984   }
    985 }
    986 
    987 void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() {
    988   observer_list_->Notify(&GpuDataManagerObserver::OnGpuInfoUpdate);
    989 }
    990 
    991 void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() {
    992   if (ShouldUseWarp())
    993     return;
    994 
    995   if (!GpuAccessAllowed(NULL) ||
    996       blacklisted_features_.count(gpu::GPU_FEATURE_TYPE_WEBGL)) {
    997     if (!swiftshader_path_.empty() &&
    998         !base::CommandLine::ForCurrentProcess()->HasSwitch(
    999              switches::kDisableSoftwareRasterizer))
   1000       use_swiftshader_ = true;
   1001   }
   1002 }
   1003 
   1004 void GpuDataManagerImplPrivate::EnableWarpIfNecessary() {
   1005 #if defined(OS_WIN)
   1006   if (use_warp_)
   1007     return;
   1008   // We should only use WARP if we are unable to use the regular GPU for
   1009   // compositing, and if we in Metro mode.
   1010   use_warp_ =
   1011       CommandLine::ForCurrentProcess()->HasSwitch(switches::kViewerConnect) &&
   1012       !CanUseGpuBrowserCompositor();
   1013 #endif
   1014 }
   1015 
   1016 void GpuDataManagerImplPrivate::ForceWarpModeForTesting() {
   1017   use_warp_ = true;
   1018 }
   1019 
   1020 std::string GpuDataManagerImplPrivate::GetDomainFromURL(
   1021     const GURL& url) const {
   1022   // For the moment, we just use the host, or its IP address, as the
   1023   // entry in the set, rather than trying to figure out the top-level
   1024   // domain. This does mean that a.foo.com and b.foo.com will be
   1025   // treated independently in the blocking of a given domain, but it
   1026   // would require a third-party library to reliably figure out the
   1027   // top-level domain from a URL.
   1028   if (!url.has_host()) {
   1029     return std::string();
   1030   }
   1031 
   1032   return url.host();
   1033 }
   1034 
   1035 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIsAtTime(
   1036     const GURL& url,
   1037     GpuDataManagerImpl::DomainGuilt guilt,
   1038     base::Time at_time) {
   1039   if (!domain_blocking_enabled_)
   1040     return;
   1041 
   1042   std::string domain = GetDomainFromURL(url);
   1043 
   1044   DomainBlockEntry& entry = blocked_domains_[domain];
   1045   entry.last_guilt = guilt;
   1046   timestamps_of_gpu_resets_.push_back(at_time);
   1047 }
   1048 
   1049 GpuDataManagerImpl::DomainBlockStatus
   1050 GpuDataManagerImplPrivate::Are3DAPIsBlockedAtTime(
   1051     const GURL& url, base::Time at_time) const {
   1052   if (!domain_blocking_enabled_)
   1053     return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
   1054 
   1055   // Note: adjusting the policies in this code will almost certainly
   1056   // require adjusting the associated unit tests.
   1057   std::string domain = GetDomainFromURL(url);
   1058 
   1059   DomainBlockMap::const_iterator iter = blocked_domains_.find(domain);
   1060   if (iter != blocked_domains_.end()) {
   1061     // Err on the side of caution, and assume that if a particular
   1062     // domain shows up in the block map, it's there for a good
   1063     // reason and don't let its presence there automatically expire.
   1064 
   1065     UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
   1066                               BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
   1067                               BLOCK_STATUS_MAX);
   1068 
   1069     return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED;
   1070   }
   1071 
   1072   // Look at the timestamps of the recent GPU resets to see if there are
   1073   // enough within the threshold which would cause us to blacklist all
   1074   // domains. This doesn't need to be overly precise -- if time goes
   1075   // backward due to a system clock adjustment, that's fine.
   1076   //
   1077   // TODO(kbr): make this pay attention to the TDR thresholds in the
   1078   // Windows registry, but make sure it continues to be testable.
   1079   {
   1080     std::list<base::Time>::iterator iter = timestamps_of_gpu_resets_.begin();
   1081     int num_resets_within_timeframe = 0;
   1082     while (iter != timestamps_of_gpu_resets_.end()) {
   1083       base::Time time = *iter;
   1084       base::TimeDelta delta_t = at_time - time;
   1085 
   1086       // If this entry has "expired", just remove it.
   1087       if (delta_t.InMilliseconds() > kBlockAllDomainsMs) {
   1088         iter = timestamps_of_gpu_resets_.erase(iter);
   1089         continue;
   1090       }
   1091 
   1092       ++num_resets_within_timeframe;
   1093       ++iter;
   1094     }
   1095 
   1096     if (num_resets_within_timeframe >= kNumResetsWithinDuration) {
   1097       UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
   1098                                 BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
   1099                                 BLOCK_STATUS_MAX);
   1100 
   1101       return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED;
   1102     }
   1103   }
   1104 
   1105   UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
   1106                             BLOCK_STATUS_NOT_BLOCKED,
   1107                             BLOCK_STATUS_MAX);
   1108 
   1109   return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
   1110 }
   1111 
   1112 int64 GpuDataManagerImplPrivate::GetBlockAllDomainsDurationInMs() const {
   1113   return kBlockAllDomainsMs;
   1114 }
   1115 
   1116 void GpuDataManagerImplPrivate::Notify3DAPIBlocked(const GURL& url,
   1117                                                    int render_process_id,
   1118                                                    int render_view_id,
   1119                                                    ThreeDAPIType requester) {
   1120   GpuDataManagerImpl::UnlockedSession session(owner_);
   1121   observer_list_->Notify(&GpuDataManagerObserver::DidBlock3DAPIs,
   1122                          url, render_process_id, render_view_id, requester);
   1123 }
   1124 
   1125 void GpuDataManagerImplPrivate::OnGpuProcessInitFailure() {
   1126   gpu_process_accessible_ = false;
   1127   gpu_info_.context_info_state = gpu::kCollectInfoFatalFailure;
   1128 #if defined(OS_WIN)
   1129   gpu_info_.dx_diagnostics_info_state = gpu::kCollectInfoFatalFailure;
   1130 #endif
   1131   complete_gpu_info_already_requested_ = true;
   1132   // Some observers might be waiting.
   1133   NotifyGpuInfoUpdate();
   1134 }
   1135 
   1136 }  // namespace content
   1137