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.
5 #include "content/browser/gpu/gpu_data_manager_impl_private.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"
38 #if defined(OS_MACOSX)
39 #include <ApplicationServices/ApplicationServices.h>
42 #include "base/win/windows_version.h"
44 #if defined(OS_ANDROID)
45 #include "ui/gfx/android/device_display_info.h"
52 enum GpuFeatureStatus {
53 kGpuFeatureEnabled = 0,
54 kGpuFeatureBlacklisted = 1,
55 kGpuFeatureDisabled = 2, // disabled by user but not blacklisted
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)
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)
87 else if (version_numbers[0] == 6 && version_numbers[1] == 2)
91 int entry_index = static_cast<int>(sub_version) * kGpuFeatureNumStatus;
93 case kGpuFeatureEnabled:
95 case kGpuFeatureBlacklisted:
98 case kGpuFeatureDisabled:
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.
116 const base::CommandLine& command_line =
117 *base::CommandLine::ForCurrentProcess();
118 bool disabled = false;
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
124 UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
125 0, max_entry_id + 1);
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);
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;
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);
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), };
159 const std::string kGpuBlacklistFeatureHistogramNamesWin[] = {
160 "GPU.BlacklistFeatureTestResultsWindows.Accelerated2dCanvas",
161 "GPU.BlacklistFeatureTestResultsWindows.GpuCompositing",
162 "GPU.BlacklistFeatureTestResultsWindows.Webgl", };
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);
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));
189 UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.GLResetNotificationStrategy",
190 gpu_info.gl_reset_notification_strategy);
193 // Combine the integers into a string, seperated by ','.
194 std::string IntSetToString(const std::set<int>& list) {
196 for (std::set<int>::const_iterator it = list.begin();
197 it != list.end(); ++it) {
200 rt += base::IntToString(*it);
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
212 GpuDataManagerImpl* manager =
213 reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager);
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;
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);
234 if (display_changed || gpu_changed)
235 manager->HandleGpuSwitch();
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;
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,
252 } // namespace anonymous
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;
260 // Prevent all further initialization.
263 InitializeImpl(gpu_blacklist_json, std::string(), gpu_info);
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)) {
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)
282 return (blacklisted_features_.count(feature) == 1);
285 bool GpuDataManagerImplPrivate::IsDriverBugWorkaroundActive(int feature) const {
286 return (gpu_driver_bugs_.count(feature) == 1);
289 size_t GpuDataManagerImplPrivate::GetBlacklistedFeatureCount() const {
290 if (use_swiftshader_)
292 return blacklisted_features_.size();
295 void GpuDataManagerImplPrivate::SetDisplayCount(unsigned int display_count) {
296 display_count_ = display_count;
299 unsigned int GpuDataManagerImplPrivate::GetDisplayCount() const {
300 return display_count_;
303 gpu::GPUInfo GpuDataManagerImplPrivate::GetGPUInfo() const {
307 void GpuDataManagerImplPrivate::GetGpuProcessHandles(
308 const GpuDataManager::GetGpuProcessHandlesCallback& callback) const {
309 GpuProcessHost::GetProcessHandles(callback);
312 bool GpuDataManagerImplPrivate::GpuAccessAllowed(
313 std::string* reason) const {
314 if (use_swiftshader_)
317 if (!gpu_process_accessible_) {
319 *reason = "GPU process launch failed.";
324 if (card_blacklisted_) {
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.";
331 *reason += "in chrome://settings.";
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()) {
343 *reason = "Features are disabled upon full but not preliminary GPU info.";
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)
356 *reason = "All GPU features are blacklisted.";
365 void GpuDataManagerImplPrivate::RequestCompleteGpuInfoIfNeeded() {
366 if (complete_gpu_info_already_requested_ || gpu_info_.finalized)
368 complete_gpu_info_already_requested_ = true;
370 GpuProcessHost::SendOnIO(
372 GpuProcessHost::GPU_PROCESS_KIND_UNSANDBOXED,
374 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
376 CAUSE_FOR_GPU_LAUNCH_GPUDATAMANAGER_REQUESTCOMPLETEGPUINFOIFNEEDED,
377 new GpuMsg_CollectGraphicsInfo());
380 bool GpuDataManagerImplPrivate::IsCompleteGpuInfoAvailable() const {
381 return gpu_info_.finalized;
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());
391 bool GpuDataManagerImplPrivate::ShouldUseSwiftShader() const {
392 return use_swiftshader_;
395 void GpuDataManagerImplPrivate::RegisterSwiftShaderPath(
396 const base::FilePath& path) {
397 swiftshader_path_ = path;
398 EnableSwiftShaderIfNecessary();
401 void GpuDataManagerImplPrivate::AddObserver(GpuDataManagerObserver* observer) {
402 GpuDataManagerImpl::UnlockedSession session(owner_);
403 observer_list_->AddObserver(observer);
406 void GpuDataManagerImplPrivate::RemoveObserver(
407 GpuDataManagerObserver* observer) {
408 GpuDataManagerImpl::UnlockedSession session(owner_);
409 observer_list_->RemoveObserver(observer);
412 void GpuDataManagerImplPrivate::UnblockDomainFrom3DAPIs(const GURL& url) {
413 // This method must do two things:
415 // 1. If the specific domain is blocked, then unblock it.
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.
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);
427 blocked_domains_.erase(domain);
428 timestamps_of_gpu_resets_.clear();
431 void GpuDataManagerImplPrivate::DisableGpuWatchdog() {
432 GpuProcessHost::SendOnIO(
433 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
434 CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
435 new GpuMsg_DisableWatchdog);
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())
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())
451 gpu::GPUInfo gpu_info = gpu_info_;
453 gpu_info.gl_vendor = gl_vendor;
454 gpu_info.gl_renderer = gl_renderer;
455 gpu_info.gl_version = gl_version;
457 gpu::CollectDriverInfoGL(&gpu_info);
459 UpdateGpuInfo(gpu_info);
460 UpdateGpuSwitchingManager(gpu_info);
461 UpdatePreliminaryBlacklistedFeatures();
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);
469 *gl_vendor = gpu_info_.gl_vendor;
470 *gl_renderer = gpu_info_.gl_renderer;
471 *gl_version = gpu_info_.gl_version;
474 void GpuDataManagerImplPrivate::Initialize() {
475 TRACE_EVENT0("startup", "GpuDataManagerImpl::Initialize");
477 DVLOG(0) << "GpuDataManagerImpl marked as finalized; skipping Initialize";
481 const base::CommandLine* command_line =
482 base::CommandLine::ForCurrentProcess();
483 if (command_line->HasSwitch(switches::kSkipGpuDataLoading))
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;
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;
501 TRACE_EVENT0("startup",
502 "GpuDataManagerImpl::Initialize:CollectBasicGraphicsInfo");
503 gpu::CollectBasicGraphicsInfo(&gpu_info);
505 #if defined(ARCH_CPU_X86_FAMILY)
506 if (!gpu_info.gpu.vendor_id || !gpu_info.gpu.device_id)
507 gpu_info.finalized = true;
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;
516 if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
517 gpu_driver_bug_list_string = gpu::kGpuDriverBugListJson;
519 InitializeImpl(gpu_blacklist_string,
520 gpu_driver_bug_list_string,
524 void GpuDataManagerImplPrivate::UpdateGpuInfoHelper() {
525 GetContentClient()->SetGpuInfo(gpu_info_);
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);
533 UpdateBlacklistedFeatures(features);
535 if (gpu_driver_bug_list_) {
536 gpu_driver_bugs_ = gpu_driver_bug_list_->MakeDecision(
537 gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
539 gpu::GpuDriverBugList::AppendWorkaroundsFromCommandLine(
540 &gpu_driver_bugs_, *base::CommandLine::ForCurrentProcess());
542 // We have to update GpuFeatureType before notify all the observers.
543 NotifyGpuInfoUpdate();
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_)
551 gpu::MergeGPUInfo(&gpu_info_, gpu_info);
552 complete_gpu_info_already_requested_ =
553 complete_gpu_info_already_requested_ || gpu_info_.finalized;
555 UpdateGpuInfoHelper();
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);
565 void GpuDataManagerImplPrivate::AppendRendererCommandLine(
566 base::CommandLine* command_line) const {
567 DCHECK(command_line);
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);
578 #if defined(USE_AURA)
579 if (!CanUseGpuBrowserCompositor())
580 command_line->AppendSwitch(switches::kDisableGpuCompositing);
584 void GpuDataManagerImplPrivate::AppendGpuCommandLine(
585 base::CommandLine* command_line) const {
586 DCHECK(command_line);
589 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
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)) &&
605 command_line->AppendSwitchASCII(
606 switches::kUseGL, gfx::kGLImplementationOSMesaName);
607 } else if (!use_gl.empty()) {
608 command_line->AppendSwitchASCII(switches::kUseGL, use_gl);
610 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus())
611 command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "true");
613 command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "false");
615 if (!swiftshader_path.empty()) {
616 command_line->AppendSwitchPath(switches::kSwiftShaderPath,
620 if (!gpu_driver_bugs_.empty()) {
621 command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
622 IntSetToString(gpu_driver_bugs_));
625 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
626 !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) {
627 command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
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);
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);
650 void GpuDataManagerImplPrivate::AppendPluginCommandLine(
651 base::CommandLine* command_line) const {
652 DCHECK(command_line);
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);
667 void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
668 WebPreferences* prefs) const {
671 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL)) {
672 prefs->experimental_webgl_enabled = false;
673 prefs->pepper_3d_enabled = false;
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;
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) &&
688 prefs->gl_multisampling_enabled = false;
690 #if defined(USE_AURA)
691 if (!CanUseGpuBrowserCompositor()) {
692 prefs->accelerated_2d_canvas_enabled = false;
693 prefs->pepper_3d_enabled = false;
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;
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;
710 void GpuDataManagerImplPrivate::DisableHardwareAcceleration() {
711 card_blacklisted_ = true;
713 for (int i = 0; i < gpu::NUMBER_OF_GPU_FEATURE_TYPES; ++i)
714 blacklisted_features_.insert(i);
716 EnableSwiftShaderIfNecessary();
717 NotifyGpuInfoUpdate();
720 std::string GpuDataManagerImplPrivate::GetBlacklistVersion() const {
722 return gpu_blacklist_->version();
726 std::string GpuDataManagerImplPrivate::GetDriverBugListVersion() const {
727 if (gpu_driver_bug_list_)
728 return gpu_driver_bug_list_->version();
732 void GpuDataManagerImplPrivate::GetBlacklistReasons(
733 base::ListValue* reasons) const {
735 gpu_blacklist_->GetReasons(reasons, "disabledFeatures");
736 if (gpu_driver_bug_list_)
737 gpu_driver_bug_list_->GetReasons(reasons, "workarounds");
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)));
750 void GpuDataManagerImplPrivate::AddLogMessage(
751 int level, const std::string& header, const std::string& message) {
752 log_messages_.push_back(LogMessage(level, header, message));
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(
763 base::Bind(&GpuDataManagerImpl::ProcessCrashed,
764 base::Unretained(owner_),
769 gpu_info_.process_crash_count = GpuProcessHost::gpu_crash_count();
770 GpuDataManagerImpl::UnlockedSession session(owner_);
771 observer_list_->Notify(
772 &GpuDataManagerObserver::OnGpuProcessCrashed, exit_code);
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);
788 void GpuDataManagerImplPrivate::HandleGpuSwitch() {
789 GpuDataManagerImpl::UnlockedSession session(owner_);
790 observer_list_->Notify(&GpuDataManagerObserver::OnGpuSwitching);
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)
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;
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)
810 gpu_info_.secondary_gpus[ii].active = true;
812 gpu_info_.secondary_gpus[ii].active = false;
815 gpu_info_.gpu.active = false;
817 UpdateGpuInfoHelper();
821 bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const {
822 if (ShouldUseSwiftShader())
824 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING))
829 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIs(
830 const GURL& url, GpuDataManagerImpl::DomainGuilt guilt) {
831 BlockDomainFrom3DAPIsAtTime(url, guilt, base::Time::Now());
834 bool GpuDataManagerImplPrivate::Are3DAPIsBlocked(const GURL& url,
835 int render_process_id,
837 ThreeDAPIType requester) {
838 bool blocked = Are3DAPIsBlockedAtTime(url, base::Time::Now()) !=
839 GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_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));
853 void GpuDataManagerImplPrivate::DisableDomainBlockingFor3DAPIsForTesting() {
854 domain_blocking_enabled_ = false;
858 GpuDataManagerImplPrivate* GpuDataManagerImplPrivate::Create(
859 GpuDataManagerImpl* owner) {
860 return new GpuDataManagerImplPrivate(owner);
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),
871 domain_blocking_enabled_(true),
874 gpu_process_accessible_(true),
877 const base::CommandLine* command_line =
878 base::CommandLine::ForCurrentProcess();
879 if (command_line->HasSwitch(switches::kDisableGpu))
880 DisableHardwareAcceleration();
882 #if defined(OS_MACOSX)
883 CGGetActiveDisplayList (0, NULL, &display_count_);
884 CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback, owner_);
888 if (command_line->HasSwitch(switches::kDisableDomainBlockingFor3DAPIs)) {
889 domain_blocking_enabled_ = false;
893 GpuDataManagerImplPrivate::~GpuDataManagerImplPrivate() {
894 #if defined(OS_MACOSX)
895 CGDisplayRemoveReconfigurationCallback(DisplayReconfigCallback, owner_);
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);
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);
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);
924 gpu_info_ = gpu_info;
925 UpdateGpuInfo(gpu_info);
926 UpdateGpuSwitchingManager(gpu_info);
927 UpdatePreliminaryBlacklistedFeatures();
930 void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures(
931 const std::set<int>& features) {
932 blacklisted_features_ = features;
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);
941 EnableSwiftShaderIfNecessary();
944 void GpuDataManagerImplPrivate::UpdatePreliminaryBlacklistedFeatures() {
945 preliminary_blacklisted_features_ = blacklisted_features_;
948 void GpuDataManagerImplPrivate::UpdateGpuSwitchingManager(
949 const gpu::GPUInfo& gpu_info) {
950 ui::GpuSwitchingManager::GetInstance()->SetGpuCount(
951 gpu_info.secondary_gpus.size() + 1);
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();
961 void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() {
962 observer_list_->Notify(&GpuDataManagerObserver::OnGpuInfoUpdate);
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;
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();
990 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIsAtTime(
992 GpuDataManagerImpl::DomainGuilt guilt,
993 base::Time at_time) {
994 if (!domain_blocking_enabled_)
997 std::string domain = GetDomainFromURL(url);
999 DomainBlockEntry& entry = blocked_domains_[domain];
1000 entry.last_guilt = guilt;
1001 timestamps_of_gpu_resets_.push_back(at_time);
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;
1010 // Note: adjusting the policies in this code will almost certainly
1011 // require adjusting the associated unit tests.
1012 std::string domain = GetDomainFromURL(url);
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.
1020 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
1021 BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
1024 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED;
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.
1032 // TODO(kbr): make this pay attention to the TDR thresholds in the
1033 // Windows registry, but make sure it continues to be testable.
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;
1041 // If this entry has "expired", just remove it.
1042 if (delta_t.InMilliseconds() > kBlockAllDomainsMs) {
1043 iter = timestamps_of_gpu_resets_.erase(iter);
1047 ++num_resets_within_timeframe;
1051 if (num_resets_within_timeframe >= kNumResetsWithinDuration) {
1052 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
1053 BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
1056 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED;
1060 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
1061 BLOCK_STATUS_NOT_BLOCKED,
1064 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
1067 int64 GpuDataManagerImplPrivate::GetBlockAllDomainsDurationInMs() const {
1068 return kBlockAllDomainsMs;
1071 void GpuDataManagerImplPrivate::Notify3DAPIBlocked(const GURL& url,
1072 int render_process_id,
1074 ThreeDAPIType requester) {
1075 GpuDataManagerImpl::UnlockedSession session(owner_);
1076 observer_list_->Notify(&GpuDataManagerObserver::DidBlock3DAPIs,
1077 url, render_process_id, render_view_id, requester);
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();
1088 } // namespace content