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