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