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