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;
704 void GpuDataManagerImplPrivate::DisableHardwareAcceleration() {
705 card_blacklisted_
= true;
707 for (int i
= 0; i
< gpu::NUMBER_OF_GPU_FEATURE_TYPES
; ++i
)
708 blacklisted_features_
.insert(i
);
710 EnableSwiftShaderIfNecessary();
711 NotifyGpuInfoUpdate();
714 std::string
GpuDataManagerImplPrivate::GetBlacklistVersion() const {
716 return gpu_blacklist_
->version();
720 std::string
GpuDataManagerImplPrivate::GetDriverBugListVersion() const {
721 if (gpu_driver_bug_list_
)
722 return gpu_driver_bug_list_
->version();
726 void GpuDataManagerImplPrivate::GetBlacklistReasons(
727 base::ListValue
* reasons
) const {
729 gpu_blacklist_
->GetReasons(reasons
, "disabledFeatures");
730 if (gpu_driver_bug_list_
)
731 gpu_driver_bug_list_
->GetReasons(reasons
, "workarounds");
734 void GpuDataManagerImplPrivate::GetDriverBugWorkarounds(
735 base::ListValue
* workarounds
) const {
736 for (std::set
<int>::const_iterator it
= gpu_driver_bugs_
.begin();
737 it
!= gpu_driver_bugs_
.end(); ++it
) {
738 workarounds
->AppendString(
739 gpu::GpuDriverBugWorkaroundTypeToString(
740 static_cast<gpu::GpuDriverBugWorkaroundType
>(*it
)));
744 void GpuDataManagerImplPrivate::AddLogMessage(
745 int level
, const std::string
& header
, const std::string
& message
) {
746 log_messages_
.push_back(LogMessage(level
, header
, message
));
749 void GpuDataManagerImplPrivate::ProcessCrashed(
750 base::TerminationStatus exit_code
) {
751 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
752 // Unretained is ok, because it's posted to UI thread, the thread
753 // where the singleton GpuDataManagerImpl lives until the end.
754 BrowserThread::PostTask(
757 base::Bind(&GpuDataManagerImpl::ProcessCrashed
,
758 base::Unretained(owner_
),
763 gpu_info_
.process_crash_count
= GpuProcessHost::gpu_crash_count();
764 GpuDataManagerImpl::UnlockedSession
session(owner_
);
765 observer_list_
->Notify(
766 &GpuDataManagerObserver::OnGpuProcessCrashed
, exit_code
);
770 base::ListValue
* GpuDataManagerImplPrivate::GetLogMessages() const {
771 base::ListValue
* value
= new base::ListValue
;
772 for (size_t ii
= 0; ii
< log_messages_
.size(); ++ii
) {
773 base::DictionaryValue
* dict
= new base::DictionaryValue();
774 dict
->SetInteger("level", log_messages_
[ii
].level
);
775 dict
->SetString("header", log_messages_
[ii
].header
);
776 dict
->SetString("message", log_messages_
[ii
].message
);
782 void GpuDataManagerImplPrivate::HandleGpuSwitch() {
783 GpuDataManagerImpl::UnlockedSession
session(owner_
);
784 observer_list_
->Notify(&GpuDataManagerObserver::OnGpuSwitching
);
787 bool GpuDataManagerImplPrivate::UpdateActiveGpu(
788 uint32 vendor_id
, uint32 device_id
) {
789 if (gpu_info_
.gpu
.vendor_id
== vendor_id
&&
790 gpu_info_
.gpu
.device_id
== device_id
) {
791 // The primary GPU is active.
792 if (gpu_info_
.gpu
.active
)
794 gpu_info_
.gpu
.active
= true;
795 for (size_t ii
= 0; ii
< gpu_info_
.secondary_gpus
.size(); ++ii
)
796 gpu_info_
.secondary_gpus
[ii
].active
= false;
798 // A secondary GPU is active.
799 for (size_t ii
= 0; ii
< gpu_info_
.secondary_gpus
.size(); ++ii
) {
800 if (gpu_info_
.secondary_gpus
[ii
].vendor_id
== vendor_id
&&
801 gpu_info_
.secondary_gpus
[ii
].device_id
== device_id
) {
802 if (gpu_info_
.secondary_gpus
[ii
].active
)
804 gpu_info_
.secondary_gpus
[ii
].active
= true;
806 gpu_info_
.secondary_gpus
[ii
].active
= false;
809 gpu_info_
.gpu
.active
= false;
811 UpdateGpuInfoHelper();
815 bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const {
816 if (ShouldUseSwiftShader())
818 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING
))
823 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIs(
824 const GURL
& url
, GpuDataManagerImpl::DomainGuilt guilt
) {
825 BlockDomainFrom3DAPIsAtTime(url
, guilt
, base::Time::Now());
828 bool GpuDataManagerImplPrivate::Are3DAPIsBlocked(const GURL
& url
,
829 int render_process_id
,
831 ThreeDAPIType requester
) {
832 bool blocked
= Are3DAPIsBlockedAtTime(url
, base::Time::Now()) !=
833 GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED
;
835 // Unretained is ok, because it's posted to UI thread, the thread
836 // where the singleton GpuDataManagerImpl lives until the end.
837 BrowserThread::PostTask(
838 BrowserThread::UI
, FROM_HERE
,
839 base::Bind(&GpuDataManagerImpl::Notify3DAPIBlocked
,
840 base::Unretained(owner_
), url
, render_process_id
,
841 render_view_id
, requester
));
847 void GpuDataManagerImplPrivate::DisableDomainBlockingFor3DAPIsForTesting() {
848 domain_blocking_enabled_
= false;
852 GpuDataManagerImplPrivate
* GpuDataManagerImplPrivate::Create(
853 GpuDataManagerImpl
* owner
) {
854 return new GpuDataManagerImplPrivate(owner
);
857 GpuDataManagerImplPrivate::GpuDataManagerImplPrivate(
858 GpuDataManagerImpl
* owner
)
859 : complete_gpu_info_already_requested_(false),
860 observer_list_(new GpuDataManagerObserverList
),
861 use_swiftshader_(false),
862 card_blacklisted_(false),
863 update_histograms_(true),
865 domain_blocking_enabled_(true),
868 gpu_process_accessible_(true),
871 const base::CommandLine
* command_line
=
872 base::CommandLine::ForCurrentProcess();
873 if (command_line
->HasSwitch(switches::kDisableGpu
))
874 DisableHardwareAcceleration();
876 #if defined(OS_MACOSX)
877 CGGetActiveDisplayList (0, NULL
, &display_count_
);
878 CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback
, owner_
);
882 if (command_line
->HasSwitch(switches::kDisableDomainBlockingFor3DAPIs
)) {
883 domain_blocking_enabled_
= false;
887 GpuDataManagerImplPrivate::~GpuDataManagerImplPrivate() {
888 #if defined(OS_MACOSX)
889 CGDisplayRemoveReconfigurationCallback(DisplayReconfigCallback
, owner_
);
893 void GpuDataManagerImplPrivate::InitializeImpl(
894 const std::string
& gpu_blacklist_json
,
895 const std::string
& gpu_driver_bug_list_json
,
896 const gpu::GPUInfo
& gpu_info
) {
897 const bool log_gpu_control_list_decisions
=
898 base::CommandLine::ForCurrentProcess()->HasSwitch(
899 switches::kLogGpuControlListDecisions
);
901 if (!gpu_blacklist_json
.empty()) {
902 gpu_blacklist_
.reset(gpu::GpuBlacklist::Create());
903 if (log_gpu_control_list_decisions
)
904 gpu_blacklist_
->enable_control_list_logging("gpu_blacklist");
905 bool success
= gpu_blacklist_
->LoadList(
906 gpu_blacklist_json
, gpu::GpuControlList::kCurrentOsOnly
);
909 if (!gpu_driver_bug_list_json
.empty()) {
910 gpu_driver_bug_list_
.reset(gpu::GpuDriverBugList::Create());
911 if (log_gpu_control_list_decisions
)
912 gpu_driver_bug_list_
->enable_control_list_logging("gpu_driver_bug_list");
913 bool success
= gpu_driver_bug_list_
->LoadList(
914 gpu_driver_bug_list_json
, gpu::GpuControlList::kCurrentOsOnly
);
918 gpu_info_
= gpu_info
;
919 UpdateGpuInfo(gpu_info
);
920 UpdateGpuSwitchingManager(gpu_info
);
921 UpdatePreliminaryBlacklistedFeatures();
924 void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures(
925 const std::set
<int>& features
) {
926 blacklisted_features_
= features
;
928 // Force disable using the GPU for these features, even if they would
929 // otherwise be allowed.
930 if (card_blacklisted_
) {
931 blacklisted_features_
.insert(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING
);
932 blacklisted_features_
.insert(gpu::GPU_FEATURE_TYPE_WEBGL
);
935 EnableSwiftShaderIfNecessary();
938 void GpuDataManagerImplPrivate::UpdatePreliminaryBlacklistedFeatures() {
939 preliminary_blacklisted_features_
= blacklisted_features_
;
942 void GpuDataManagerImplPrivate::UpdateGpuSwitchingManager(
943 const gpu::GPUInfo
& gpu_info
) {
944 ui::GpuSwitchingManager::GetInstance()->SetGpuCount(
945 gpu_info
.secondary_gpus
.size() + 1);
947 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
948 if (gpu_driver_bugs_
.count(gpu::FORCE_DISCRETE_GPU
) == 1)
949 ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu();
950 else if (gpu_driver_bugs_
.count(gpu::FORCE_INTEGRATED_GPU
) == 1)
951 ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu();
955 void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() {
956 observer_list_
->Notify(&GpuDataManagerObserver::OnGpuInfoUpdate
);
959 void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() {
960 if (!GpuAccessAllowed(NULL
) ||
961 blacklisted_features_
.count(gpu::GPU_FEATURE_TYPE_WEBGL
)) {
962 if (!swiftshader_path_
.empty() &&
963 !base::CommandLine::ForCurrentProcess()->HasSwitch(
964 switches::kDisableSoftwareRasterizer
))
965 use_swiftshader_
= true;
969 std::string
GpuDataManagerImplPrivate::GetDomainFromURL(
970 const GURL
& url
) const {
971 // For the moment, we just use the host, or its IP address, as the
972 // entry in the set, rather than trying to figure out the top-level
973 // domain. This does mean that a.foo.com and b.foo.com will be
974 // treated independently in the blocking of a given domain, but it
975 // would require a third-party library to reliably figure out the
976 // top-level domain from a URL.
977 if (!url
.has_host()) {
978 return std::string();
984 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIsAtTime(
986 GpuDataManagerImpl::DomainGuilt guilt
,
987 base::Time at_time
) {
988 if (!domain_blocking_enabled_
)
991 std::string domain
= GetDomainFromURL(url
);
993 DomainBlockEntry
& entry
= blocked_domains_
[domain
];
994 entry
.last_guilt
= guilt
;
995 timestamps_of_gpu_resets_
.push_back(at_time
);
998 GpuDataManagerImpl::DomainBlockStatus
999 GpuDataManagerImplPrivate::Are3DAPIsBlockedAtTime(
1000 const GURL
& url
, base::Time at_time
) const {
1001 if (!domain_blocking_enabled_
)
1002 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED
;
1004 // Note: adjusting the policies in this code will almost certainly
1005 // require adjusting the associated unit tests.
1006 std::string domain
= GetDomainFromURL(url
);
1008 DomainBlockMap::const_iterator iter
= blocked_domains_
.find(domain
);
1009 if (iter
!= blocked_domains_
.end()) {
1010 // Err on the side of caution, and assume that if a particular
1011 // domain shows up in the block map, it's there for a good
1012 // reason and don't let its presence there automatically expire.
1014 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
1015 BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED
,
1018 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED
;
1021 // Look at the timestamps of the recent GPU resets to see if there are
1022 // enough within the threshold which would cause us to blacklist all
1023 // domains. This doesn't need to be overly precise -- if time goes
1024 // backward due to a system clock adjustment, that's fine.
1026 // TODO(kbr): make this pay attention to the TDR thresholds in the
1027 // Windows registry, but make sure it continues to be testable.
1029 std::list
<base::Time
>::iterator iter
= timestamps_of_gpu_resets_
.begin();
1030 int num_resets_within_timeframe
= 0;
1031 while (iter
!= timestamps_of_gpu_resets_
.end()) {
1032 base::Time time
= *iter
;
1033 base::TimeDelta delta_t
= at_time
- time
;
1035 // If this entry has "expired", just remove it.
1036 if (delta_t
.InMilliseconds() > kBlockAllDomainsMs
) {
1037 iter
= timestamps_of_gpu_resets_
.erase(iter
);
1041 ++num_resets_within_timeframe
;
1045 if (num_resets_within_timeframe
>= kNumResetsWithinDuration
) {
1046 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
1047 BLOCK_STATUS_ALL_DOMAINS_BLOCKED
,
1050 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED
;
1054 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
1055 BLOCK_STATUS_NOT_BLOCKED
,
1058 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED
;
1061 int64
GpuDataManagerImplPrivate::GetBlockAllDomainsDurationInMs() const {
1062 return kBlockAllDomainsMs
;
1065 void GpuDataManagerImplPrivate::Notify3DAPIBlocked(const GURL
& url
,
1066 int render_process_id
,
1068 ThreeDAPIType requester
) {
1069 GpuDataManagerImpl::UnlockedSession
session(owner_
);
1070 observer_list_
->Notify(&GpuDataManagerObserver::DidBlock3DAPIs
,
1071 url
, render_process_id
, render_view_id
, requester
);
1074 void GpuDataManagerImplPrivate::OnGpuProcessInitFailure() {
1075 gpu_process_accessible_
= false;
1076 gpu_info_
.finalized
= true;
1077 complete_gpu_info_already_requested_
= true;
1078 // Some observers might be waiting.
1079 NotifyGpuInfoUpdate();
1082 } // namespace content