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