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 "gpu/command_buffer/service/gpu_switches.h"
27 #include "gpu/config/gpu_control_list_jsons.h"
28 #include "gpu/config/gpu_driver_bug_workaround_type.h"
29 #include "gpu/config/gpu_feature_type.h"
30 #include "gpu/config/gpu_info_collector.h"
31 #include "gpu/config/gpu_util.h"
32 #include "ui/base/ui_base_switches.h"
33 #include "ui/gl/gl_implementation.h"
34 #include "ui/gl/gl_switches.h"
35 #include "ui/gl/gpu_switching_manager.h"
36 #include "webkit/common/webpreferences.h"
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 CommandLine& command_line = *CommandLine::ForCurrentProcess();
117 bool disabled = false;
119 // Use entry 0 to capture the total number of times that data
120 // was recorded in this histogram in order to have a convenient
121 // denominator to compute blacklist percentages for the rest of the
123 UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
124 0, max_entry_id + 1);
126 if (blacklisted_features.size() != 0) {
127 std::vector<uint32> flag_entries;
128 blacklist->GetDecisionEntries(&flag_entries, disabled);
129 DCHECK_GT(flag_entries.size(), 0u);
130 for (size_t i = 0; i < flag_entries.size(); ++i) {
131 UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
132 flag_entries[i], max_entry_id + 1);
136 // This counts how many users are affected by a disabled entry - this allows
137 // us to understand the impact of an entry before enable it.
138 std::vector<uint32> flag_disabled_entries;
140 blacklist->GetDecisionEntries(&flag_disabled_entries, disabled);
141 for (size_t i = 0; i < flag_disabled_entries.size(); ++i) {
142 UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerDisabledEntry",
143 flag_disabled_entries[i], max_entry_id + 1);
146 const gpu::GpuFeatureType kGpuFeatures[] = {
147 gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS,
148 gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING,
149 gpu::GPU_FEATURE_TYPE_WEBGL
151 const std::string kGpuBlacklistFeatureHistogramNames[] = {
152 "GPU.BlacklistFeatureTestResults.Accelerated2dCanvas",
153 "GPU.BlacklistFeatureTestResults.AcceleratedCompositing",
154 "GPU.BlacklistFeatureTestResults.Webgl",
156 const bool kGpuFeatureUserFlags[] = {
157 command_line.HasSwitch(switches::kDisableAccelerated2dCanvas),
158 command_line.HasSwitch(switches::kDisableAcceleratedCompositing),
159 command_line.HasSwitch(switches::kDisableExperimentalWebGL),
162 const std::string kGpuBlacklistFeatureHistogramNamesWin[] = {
163 "GPU.BlacklistFeatureTestResultsWindows.Accelerated2dCanvas",
164 "GPU.BlacklistFeatureTestResultsWindows.AcceleratedCompositing",
165 "GPU.BlacklistFeatureTestResultsWindows.Webgl",
168 const size_t kNumFeatures =
169 sizeof(kGpuFeatures) / sizeof(gpu::GpuFeatureType);
170 for (size_t i = 0; i < kNumFeatures; ++i) {
171 // We can't use UMA_HISTOGRAM_ENUMERATION here because the same name is
172 // expected if the macro is used within a loop.
173 GpuFeatureStatus value = kGpuFeatureEnabled;
174 if (blacklisted_features.count(kGpuFeatures[i]))
175 value = kGpuFeatureBlacklisted;
176 else if (kGpuFeatureUserFlags[i])
177 value = kGpuFeatureDisabled;
178 base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
179 kGpuBlacklistFeatureHistogramNames[i],
180 1, kGpuFeatureNumStatus, kGpuFeatureNumStatus + 1,
181 base::HistogramBase::kUmaTargetedHistogramFlag);
182 histogram_pointer->Add(value);
184 histogram_pointer = base::LinearHistogram::FactoryGet(
185 kGpuBlacklistFeatureHistogramNamesWin[i],
186 1, kNumWinSubVersions * kGpuFeatureNumStatus,
187 kNumWinSubVersions * kGpuFeatureNumStatus + 1,
188 base::HistogramBase::kUmaTargetedHistogramFlag);
189 histogram_pointer->Add(GetGpuBlacklistHistogramValueWin(value));
193 UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.GLResetNotificationStrategy",
194 gpu_info.gl_reset_notification_strategy);
197 // Combine the integers into a string, seperated by ','.
198 std::string IntSetToString(const std::set<int>& list) {
200 for (std::set<int>::const_iterator it = list.begin();
201 it != list.end(); ++it) {
204 rt += base::IntToString(*it);
209 #if defined(OS_MACOSX)
210 void DisplayReconfigCallback(CGDirectDisplayID display,
211 CGDisplayChangeSummaryFlags flags,
212 void* gpu_data_manager) {
213 if (flags == kCGDisplayBeginConfigurationFlag)
214 return; // This call contains no information about the display change
216 GpuDataManagerImpl* manager =
217 reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager);
220 uint32_t displayCount;
221 CGGetActiveDisplayList(0, NULL, &displayCount);
223 bool fireGpuSwitch = flags & kCGDisplayAddFlag;
225 if (displayCount != manager->GetDisplayCount()) {
226 manager->SetDisplayCount(displayCount);
227 fireGpuSwitch = true;
231 manager->HandleGpuSwitch();
235 #if defined(OS_ANDROID)
236 void ApplyAndroidWorkarounds(const gpu::GPUInfo& gpu_info,
237 CommandLine* command_line) {
238 std::string vendor(StringToLowerASCII(gpu_info.gl_vendor));
239 std::string renderer(StringToLowerASCII(gpu_info.gl_renderer));
241 gpu_info.gl_vendor.find("Imagination") != std::string::npos;
243 gfx::DeviceDisplayInfo info;
244 int default_tile_size = 256;
246 // TODO(epenner): Now that this is somewhat generic, maybe we can
247 // unify this for all platforms (http://crbug.com/159524)
249 bool real_size_supported = true;
250 int display_width = info.GetPhysicalDisplayWidth();
251 int display_height = info.GetPhysicalDisplayHeight();
252 if (display_width == 0 || display_height == 0) {
253 real_size_supported = false;
254 display_width = info.GetDisplayWidth();
255 display_height = info.GetDisplayHeight();
258 int portrait_width = std::min(display_width, display_height);
259 int landscape_width = std::max(display_width, display_height);
261 if (real_size_supported) {
262 // Maximum HD dimensions should be 768x1280
263 // Maximum FHD dimensions should be 1200x1920
264 if (portrait_width > 768 || landscape_width > 1280)
265 default_tile_size = 384;
266 if (portrait_width > 1200 || landscape_width > 1920)
267 default_tile_size = 512;
269 // Adjust for some resolutions that barely straddle an extra
270 // tile when in portrait mode. This helps worst case scroll/raster
271 // by not needing a full extra tile for each row.
272 if (default_tile_size == 256 && portrait_width == 768)
273 default_tile_size += 32;
274 if (default_tile_size == 384 && portrait_width == 1200)
275 default_tile_size += 32;
277 // We don't know the exact resolution due to screen controls etc.
278 // So this just estimates the values above using tile counts.
279 int numTiles = (display_width * display_height) / (256 * 256);
281 default_tile_size = 384;
283 default_tile_size = 512;
286 // IMG: Fast async texture uploads only work with non-power-of-two,
287 // but still multiple-of-eight sizes.
288 // http://crbug.com/168099
290 default_tile_size -= 8;
292 // Set the command line if it isn't already set and we changed
293 // the default tile size.
294 if (default_tile_size != 256 &&
295 !command_line->HasSwitch(switches::kDefaultTileWidth) &&
296 !command_line->HasSwitch(switches::kDefaultTileHeight)) {
297 std::stringstream size;
298 size << default_tile_size;
299 command_line->AppendSwitchASCII(
300 switches::kDefaultTileWidth, size.str());
301 command_line->AppendSwitchASCII(
302 switches::kDefaultTileHeight, size.str());
307 // Overwrite force gpu workaround if a commandline switch exists.
308 void AdjustGpuSwitchingOption(std::set<int>* workarounds) {
310 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
311 std::string option = command_line.GetSwitchValueASCII(
312 switches::kGpuSwitching);
313 if (option == switches::kGpuSwitchingOptionNameForceDiscrete) {
314 workarounds->erase(gpu::FORCE_INTEGRATED_GPU);
315 workarounds->insert(gpu::FORCE_DISCRETE_GPU);
316 } else if (option == switches::kGpuSwitchingOptionNameForceIntegrated) {
317 workarounds->erase(gpu::FORCE_DISCRETE_GPU);
318 workarounds->insert(gpu::FORCE_INTEGRATED_GPU);
322 // Block all domains' use of 3D APIs for this many milliseconds if
323 // approaching a threshold where system stability might be compromised.
324 const int64 kBlockAllDomainsMs = 10000;
325 const int kNumResetsWithinDuration = 1;
327 // Enums for UMA histograms.
328 enum BlockStatusHistogram {
329 BLOCK_STATUS_NOT_BLOCKED,
330 BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
331 BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
335 } // namespace anonymous
337 void GpuDataManagerImplPrivate::InitializeForTesting(
338 const std::string& gpu_blacklist_json,
339 const gpu::GPUInfo& gpu_info) {
340 // This function is for testing only, so disable histograms.
341 update_histograms_ = false;
343 // Prevent all further initialization.
346 InitializeImpl(gpu_blacklist_json, std::string(), gpu_info);
349 bool GpuDataManagerImplPrivate::IsFeatureBlacklisted(int feature) const {
350 #if defined(OS_CHROMEOS)
351 if (feature == gpu::GPU_FEATURE_TYPE_PANEL_FITTING &&
352 CommandLine::ForCurrentProcess()->HasSwitch(
353 switches::kDisablePanelFitting)) {
356 #endif // OS_CHROMEOS
357 if (use_swiftshader_) {
358 // Skia's software rendering is probably more efficient than going through
359 // software emulation of the GPU, so use that.
360 if (feature == gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)
365 return (blacklisted_features_.count(feature) == 1);
368 bool GpuDataManagerImplPrivate::IsDriverBugWorkaroundActive(int feature) const {
369 return (gpu_driver_bugs_.count(feature) == 1);
372 size_t GpuDataManagerImplPrivate::GetBlacklistedFeatureCount() const {
373 if (use_swiftshader_)
375 return blacklisted_features_.size();
378 void GpuDataManagerImplPrivate::SetDisplayCount(unsigned int display_count) {
379 display_count_ = display_count;
382 unsigned int GpuDataManagerImplPrivate::GetDisplayCount() const {
383 return display_count_;
386 gpu::GPUInfo GpuDataManagerImplPrivate::GetGPUInfo() const {
390 void GpuDataManagerImplPrivate::GetGpuProcessHandles(
391 const GpuDataManager::GetGpuProcessHandlesCallback& callback) const {
392 GpuProcessHost::GetProcessHandles(callback);
395 bool GpuDataManagerImplPrivate::GpuAccessAllowed(
396 std::string* reason) const {
397 if (use_swiftshader_)
400 if (!gpu_process_accessible_) {
402 *reason = "GPU process launch failed.";
407 if (card_blacklisted_) {
409 *reason = "GPU access is disabled ";
410 CommandLine* command_line = CommandLine::ForCurrentProcess();
411 if (command_line->HasSwitch(switches::kDisableGpu))
412 *reason += "through commandline switch --disable-gpu.";
414 *reason += "in chrome://settings.";
419 // We only need to block GPU process if more features are disallowed other
420 // than those in the preliminary gpu feature flags because the latter work
421 // through renderer commandline switches.
422 std::set<int> features = preliminary_blacklisted_features_;
423 gpu::MergeFeatureSets(&features, blacklisted_features_);
424 if (features.size() > preliminary_blacklisted_features_.size()) {
426 *reason = "Features are disabled upon full but not preliminary GPU info.";
431 if (blacklisted_features_.size() == gpu::NUMBER_OF_GPU_FEATURE_TYPES) {
432 // On Linux, we use cached GL strings to make blacklist decsions at browser
433 // startup time. We need to launch the GPU process to validate these
434 // strings even if all features are blacklisted. If all GPU features are
435 // disabled, the GPU process will only initialize GL bindings, create a GL
436 // context, and collect full GPU info.
437 #if !defined(OS_LINUX)
439 *reason = "All GPU features are blacklisted.";
448 void GpuDataManagerImplPrivate::RequestCompleteGpuInfoIfNeeded() {
449 if (complete_gpu_info_already_requested_ || gpu_info_.finalized)
451 complete_gpu_info_already_requested_ = true;
453 GpuProcessHost::SendOnIO(
455 GpuProcessHost::GPU_PROCESS_KIND_UNSANDBOXED,
457 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
459 CAUSE_FOR_GPU_LAUNCH_GPUDATAMANAGER_REQUESTCOMPLETEGPUINFOIFNEEDED,
460 new GpuMsg_CollectGraphicsInfo());
463 bool GpuDataManagerImplPrivate::IsCompleteGpuInfoAvailable() const {
464 return gpu_info_.finalized;
467 void GpuDataManagerImplPrivate::RequestVideoMemoryUsageStatsUpdate() const {
468 GpuProcessHost::SendOnIO(
469 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
470 CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
471 new GpuMsg_GetVideoMemoryUsageStats());
474 bool GpuDataManagerImplPrivate::ShouldUseSwiftShader() const {
475 return use_swiftshader_;
478 void GpuDataManagerImplPrivate::RegisterSwiftShaderPath(
479 const base::FilePath& path) {
480 swiftshader_path_ = path;
481 EnableSwiftShaderIfNecessary();
484 void GpuDataManagerImplPrivate::AddObserver(GpuDataManagerObserver* observer) {
485 GpuDataManagerImpl::UnlockedSession session(owner_);
486 observer_list_->AddObserver(observer);
489 void GpuDataManagerImplPrivate::RemoveObserver(
490 GpuDataManagerObserver* observer) {
491 GpuDataManagerImpl::UnlockedSession session(owner_);
492 observer_list_->RemoveObserver(observer);
495 void GpuDataManagerImplPrivate::UnblockDomainFrom3DAPIs(const GURL& url) {
496 // This method must do two things:
498 // 1. If the specific domain is blocked, then unblock it.
500 // 2. Reset our notion of how many GPU resets have occurred recently.
501 // This is necessary even if the specific domain was blocked.
502 // Otherwise, if we call Are3DAPIsBlocked with the same domain right
503 // after unblocking it, it will probably still be blocked because of
504 // the recent GPU reset caused by that domain.
506 // These policies could be refined, but at a certain point the behavior
507 // will become difficult to explain.
508 std::string domain = GetDomainFromURL(url);
510 blocked_domains_.erase(domain);
511 timestamps_of_gpu_resets_.clear();
514 void GpuDataManagerImplPrivate::DisableGpuWatchdog() {
515 GpuProcessHost::SendOnIO(
516 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
517 CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
518 new GpuMsg_DisableWatchdog);
521 void GpuDataManagerImplPrivate::SetGLStrings(const std::string& gl_vendor,
522 const std::string& gl_renderer,
523 const std::string& gl_version) {
524 if (gl_vendor.empty() && gl_renderer.empty() && gl_version.empty())
527 // If GPUInfo already got GL strings, do nothing. This is for the rare
528 // situation where GPU process collected GL strings before this call.
529 if (!gpu_info_.gl_vendor.empty() ||
530 !gpu_info_.gl_renderer.empty() ||
531 !gpu_info_.gl_version_string.empty())
534 gpu::GPUInfo gpu_info = gpu_info_;
536 gpu_info.gl_vendor = gl_vendor;
537 gpu_info.gl_renderer = gl_renderer;
538 gpu_info.gl_version_string = gl_version;
540 gpu::CollectDriverInfoGL(&gpu_info);
542 UpdateGpuInfo(gpu_info);
543 UpdateGpuSwitchingManager(gpu_info);
544 UpdatePreliminaryBlacklistedFeatures();
547 void GpuDataManagerImplPrivate::GetGLStrings(std::string* gl_vendor,
548 std::string* gl_renderer,
549 std::string* gl_version) {
550 DCHECK(gl_vendor && gl_renderer && gl_version);
552 *gl_vendor = gpu_info_.gl_vendor;
553 *gl_renderer = gpu_info_.gl_renderer;
554 *gl_version = gpu_info_.gl_version_string;
557 void GpuDataManagerImplPrivate::Initialize() {
558 TRACE_EVENT0("startup", "GpuDataManagerImpl::Initialize");
560 DVLOG(0) << "GpuDataManagerImpl marked as finalized; skipping Initialize";
564 const CommandLine* command_line = CommandLine::ForCurrentProcess();
565 if (command_line->HasSwitch(switches::kSkipGpuDataLoading))
568 gpu::GPUInfo gpu_info;
569 if (command_line->GetSwitchValueASCII(
570 switches::kUseGL) == gfx::kGLImplementationOSMesaName) {
571 // If using the OSMesa GL implementation, use fake vendor and device ids to
572 // make sure it never gets blacklisted. This is better than simply
573 // cancelling GPUInfo gathering as it allows us to proceed with loading the
574 // blacklist below which may have non-device specific entries we want to
575 // apply anyways (e.g., OS version blacklisting).
576 gpu_info.gpu.vendor_id = 0xffff;
577 gpu_info.gpu.device_id = 0xffff;
579 // Also declare the driver_vendor to be osmesa to be able to specify
580 // exceptions based on driver_vendor==osmesa for some blacklist rules.
581 gpu_info.driver_vendor = gfx::kGLImplementationOSMesaName;
583 TRACE_EVENT0("startup",
584 "GpuDataManagerImpl::Initialize:CollectBasicGraphicsInfo");
585 gpu::CollectBasicGraphicsInfo(&gpu_info);
587 #if defined(ARCH_CPU_X86_FAMILY)
588 if (!gpu_info.gpu.vendor_id || !gpu_info.gpu.device_id)
589 gpu_info.finalized = true;
592 std::string gpu_blacklist_string;
593 std::string gpu_driver_bug_list_string;
594 if (!command_line->HasSwitch(switches::kIgnoreGpuBlacklist) &&
595 !command_line->HasSwitch(switches::kUseGpuInTests)) {
596 gpu_blacklist_string = gpu::kSoftwareRenderingListJson;
598 if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
599 gpu_driver_bug_list_string = gpu::kGpuDriverBugListJson;
601 InitializeImpl(gpu_blacklist_string,
602 gpu_driver_bug_list_string,
606 void GpuDataManagerImplPrivate::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) {
607 // No further update of gpu_info if falling back to SwiftShader.
608 if (use_swiftshader_)
611 gpu::MergeGPUInfo(&gpu_info_, gpu_info);
612 complete_gpu_info_already_requested_ =
613 complete_gpu_info_already_requested_ || gpu_info_.finalized;
615 GetContentClient()->SetGpuInfo(gpu_info_);
617 if (gpu_blacklist_) {
618 std::set<int> features = gpu_blacklist_->MakeDecision(
619 gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
620 if (update_histograms_)
621 UpdateStats(gpu_info_, gpu_blacklist_.get(), features);
623 UpdateBlacklistedFeatures(features);
625 if (gpu_driver_bug_list_) {
626 gpu_driver_bugs_ = gpu_driver_bug_list_->MakeDecision(
627 gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
629 AdjustGpuSwitchingOption(&gpu_driver_bugs_);
631 // We have to update GpuFeatureType before notify all the observers.
632 NotifyGpuInfoUpdate();
635 void GpuDataManagerImplPrivate::UpdateVideoMemoryUsageStats(
636 const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
637 GpuDataManagerImpl::UnlockedSession session(owner_);
638 observer_list_->Notify(&GpuDataManagerObserver::OnVideoMemoryUsageStatsUpdate,
639 video_memory_usage_stats);
642 void GpuDataManagerImplPrivate::AppendRendererCommandLine(
643 CommandLine* command_line) const {
644 DCHECK(command_line);
646 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) &&
647 !command_line->HasSwitch(switches::kDisableAcceleratedCompositing))
648 command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
649 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
650 !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
651 command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
652 #if defined(ENABLE_WEBRTC)
653 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_ENCODE) &&
654 !command_line->HasSwitch(switches::kDisableWebRtcHWEncoding))
655 command_line->AppendSwitch(switches::kDisableWebRtcHWEncoding);
658 if (use_software_compositor_ &&
659 !command_line->HasSwitch(switches::kEnableSoftwareCompositing))
660 command_line->AppendSwitch(switches::kEnableSoftwareCompositing);
662 #if defined(USE_AURA)
663 if (!CanUseGpuBrowserCompositor())
664 command_line->AppendSwitch(switches::kDisableGpuCompositing);
668 void GpuDataManagerImplPrivate::AppendGpuCommandLine(
669 CommandLine* command_line) const {
670 DCHECK(command_line);
673 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL);
674 base::FilePath swiftshader_path =
675 CommandLine::ForCurrentProcess()->GetSwitchValuePath(
676 switches::kSwiftShaderPath);
677 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_MULTISAMPLING) &&
678 !command_line->HasSwitch(switches::kDisableGLMultisampling)) {
679 command_line->AppendSwitch(switches::kDisableGLMultisampling);
681 if (gpu_driver_bugs_.find(gpu::DISABLE_D3D11) != gpu_driver_bugs_.end())
682 command_line->AppendSwitch(switches::kDisableD3D11);
683 if (use_swiftshader_) {
684 command_line->AppendSwitchASCII(switches::kUseGL, "swiftshader");
685 if (swiftshader_path.empty())
686 swiftshader_path = swiftshader_path_;
687 } else if ((IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL) ||
688 IsFeatureBlacklisted(
689 gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
690 IsFeatureBlacklisted(
691 gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)) &&
693 command_line->AppendSwitchASCII(
694 switches::kUseGL, gfx::kGLImplementationOSMesaName);
695 } else if (!use_gl.empty()) {
696 command_line->AppendSwitchASCII(switches::kUseGL, use_gl);
698 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus())
699 command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "true");
701 command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "false");
703 if (!swiftshader_path.empty()) {
704 command_line->AppendSwitchPath(switches::kSwiftShaderPath,
708 if (!gpu_driver_bugs_.empty()) {
709 command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
710 IntSetToString(gpu_driver_bugs_));
713 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
714 !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) {
715 command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
717 #if defined(ENABLE_WEBRTC)
718 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_ENCODE) &&
719 !command_line->HasSwitch(switches::kDisableWebRtcHWEncoding)) {
720 command_line->AppendSwitch(switches::kDisableWebRtcHWEncoding);
724 // Pass GPU and driver information to GPU process. We try to avoid full GPU
725 // info collection at GPU process startup, but we need gpu vendor_id,
726 // device_id, driver_vendor, driver_version for deciding whether we need to
727 // collect full info (on Linux) and for crash reporting purpose.
728 command_line->AppendSwitchASCII(switches::kGpuVendorID,
729 base::StringPrintf("0x%04x", gpu_info_.gpu.vendor_id));
730 command_line->AppendSwitchASCII(switches::kGpuDeviceID,
731 base::StringPrintf("0x%04x", gpu_info_.gpu.device_id));
732 command_line->AppendSwitchASCII(switches::kGpuDriverVendor,
733 gpu_info_.driver_vendor);
734 command_line->AppendSwitchASCII(switches::kGpuDriverVersion,
735 gpu_info_.driver_version);
738 void GpuDataManagerImplPrivate::AppendPluginCommandLine(
739 CommandLine* command_line) const {
740 DCHECK(command_line);
742 #if defined(OS_MACOSX)
743 // TODO(jbauman): Add proper blacklist support for core animation plugins so
744 // special-casing this video card won't be necessary. See
745 // http://crbug.com/134015
746 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
747 CommandLine::ForCurrentProcess()->HasSwitch(
748 switches::kDisableAcceleratedCompositing)) {
749 if (!command_line->HasSwitch(
750 switches::kDisableCoreAnimationPlugins))
751 command_line->AppendSwitch(
752 switches::kDisableCoreAnimationPlugins);
757 void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
758 WebPreferences* prefs) const {
761 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING))
762 prefs->accelerated_compositing_enabled = false;
763 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL)) {
764 prefs->experimental_webgl_enabled = false;
765 prefs->pepper_3d_enabled = false;
767 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH3D))
768 prefs->flash_3d_enabled = false;
769 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D)) {
770 prefs->flash_stage3d_enabled = false;
771 prefs->flash_stage3d_baseline_enabled = false;
773 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE))
774 prefs->flash_stage3d_baseline_enabled = false;
775 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS))
776 prefs->accelerated_2d_canvas_enabled = false;
777 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_MULTISAMPLING) ||
778 (IsDriverBugWorkaroundActive(gpu::DISABLE_MULTIMONITOR_MULTISAMPLING) &&
780 prefs->gl_multisampling_enabled = false;
781 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_3D_CSS)) {
782 prefs->accelerated_compositing_for_3d_transforms_enabled = false;
783 prefs->accelerated_compositing_for_animation_enabled = false;
785 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO))
786 prefs->accelerated_compositing_for_video_enabled = false;
788 // Accelerated video and animation are slower than regular when using
789 // SwiftShader. 3D CSS or Pepper 3D may also be too slow to be worthwhile.
790 if (ShouldUseSwiftShader()) {
791 prefs->accelerated_compositing_for_video_enabled = false;
792 prefs->accelerated_compositing_for_animation_enabled = false;
793 prefs->accelerated_compositing_for_3d_transforms_enabled = false;
794 prefs->accelerated_compositing_for_plugins_enabled = false;
795 prefs->pepper_3d_enabled = false;
798 if (use_software_compositor_) {
799 prefs->force_compositing_mode = true;
800 prefs->accelerated_compositing_enabled = true;
801 prefs->accelerated_compositing_for_3d_transforms_enabled = true;
802 prefs->accelerated_compositing_for_plugins_enabled = true;
803 prefs->accelerated_compositing_for_video_enabled = true;
806 #if defined(USE_AURA)
807 if (!CanUseGpuBrowserCompositor()) {
808 prefs->accelerated_2d_canvas_enabled = false;
809 prefs->pepper_3d_enabled = false;
814 void GpuDataManagerImplPrivate::DisableHardwareAcceleration() {
815 card_blacklisted_ = true;
817 for (int i = 0; i < gpu::NUMBER_OF_GPU_FEATURE_TYPES; ++i)
818 blacklisted_features_.insert(i);
820 EnableSwiftShaderIfNecessary();
821 NotifyGpuInfoUpdate();
824 std::string GpuDataManagerImplPrivate::GetBlacklistVersion() const {
826 return gpu_blacklist_->version();
830 std::string GpuDataManagerImplPrivate::GetDriverBugListVersion() const {
831 if (gpu_driver_bug_list_)
832 return gpu_driver_bug_list_->version();
836 void GpuDataManagerImplPrivate::GetBlacklistReasons(
837 base::ListValue* reasons) const {
839 gpu_blacklist_->GetReasons(reasons);
842 void GpuDataManagerImplPrivate::GetDriverBugWorkarounds(
843 base::ListValue* workarounds) const {
844 for (std::set<int>::const_iterator it = gpu_driver_bugs_.begin();
845 it != gpu_driver_bugs_.end(); ++it) {
846 workarounds->AppendString(
847 gpu::GpuDriverBugWorkaroundTypeToString(
848 static_cast<gpu::GpuDriverBugWorkaroundType>(*it)));
852 void GpuDataManagerImplPrivate::AddLogMessage(
853 int level, const std::string& header, const std::string& message) {
854 log_messages_.push_back(LogMessage(level, header, message));
857 void GpuDataManagerImplPrivate::ProcessCrashed(
858 base::TerminationStatus exit_code) {
859 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
860 // Unretained is ok, because it's posted to UI thread, the thread
861 // where the singleton GpuDataManagerImpl lives until the end.
862 BrowserThread::PostTask(
865 base::Bind(&GpuDataManagerImpl::ProcessCrashed,
866 base::Unretained(owner_),
871 GpuDataManagerImpl::UnlockedSession session(owner_);
872 observer_list_->Notify(
873 &GpuDataManagerObserver::OnGpuProcessCrashed, exit_code);
877 base::ListValue* GpuDataManagerImplPrivate::GetLogMessages() const {
878 base::ListValue* value = new base::ListValue;
879 for (size_t ii = 0; ii < log_messages_.size(); ++ii) {
880 base::DictionaryValue* dict = new base::DictionaryValue();
881 dict->SetInteger("level", log_messages_[ii].level);
882 dict->SetString("header", log_messages_[ii].header);
883 dict->SetString("message", log_messages_[ii].message);
889 void GpuDataManagerImplPrivate::HandleGpuSwitch() {
890 GpuDataManagerImpl::UnlockedSession session(owner_);
891 observer_list_->Notify(&GpuDataManagerObserver::OnGpuSwitching);
894 bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const {
895 return !ShouldUseSwiftShader() &&
896 !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) &&
897 !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FORCE_COMPOSITING_MODE);
900 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIs(
901 const GURL& url, GpuDataManagerImpl::DomainGuilt guilt) {
902 BlockDomainFrom3DAPIsAtTime(url, guilt, base::Time::Now());
905 bool GpuDataManagerImplPrivate::Are3DAPIsBlocked(const GURL& url,
906 int render_process_id,
908 ThreeDAPIType requester) {
909 bool blocked = Are3DAPIsBlockedAtTime(url, base::Time::Now()) !=
910 GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
912 // Unretained is ok, because it's posted to UI thread, the thread
913 // where the singleton GpuDataManagerImpl lives until the end.
914 BrowserThread::PostTask(
915 BrowserThread::UI, FROM_HERE,
916 base::Bind(&GpuDataManagerImpl::Notify3DAPIBlocked,
917 base::Unretained(owner_), url, render_process_id,
918 render_view_id, requester));
924 void GpuDataManagerImplPrivate::DisableDomainBlockingFor3DAPIsForTesting() {
925 domain_blocking_enabled_ = false;
929 GpuDataManagerImplPrivate* GpuDataManagerImplPrivate::Create(
930 GpuDataManagerImpl* owner) {
931 return new GpuDataManagerImplPrivate(owner);
934 GpuDataManagerImplPrivate::GpuDataManagerImplPrivate(
935 GpuDataManagerImpl* owner)
936 : complete_gpu_info_already_requested_(false),
937 observer_list_(new GpuDataManagerObserverList),
938 use_swiftshader_(false),
939 card_blacklisted_(false),
940 update_histograms_(true),
942 domain_blocking_enabled_(true),
945 gpu_process_accessible_(true),
946 use_software_compositor_(false),
949 CommandLine* command_line = CommandLine::ForCurrentProcess();
950 if (command_line->HasSwitch(switches::kDisableAcceleratedCompositing)) {
951 command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
952 command_line->AppendSwitch(switches::kDisableAcceleratedLayers);
954 if (command_line->HasSwitch(switches::kDisableGpu))
955 DisableHardwareAcceleration();
956 if (command_line->HasSwitch(switches::kEnableSoftwareCompositing))
957 use_software_compositor_ = true;
958 // TODO(jbauman): enable for Chrome OS
959 #if (defined(USE_AURA) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX)
960 use_software_compositor_ = true;
963 #if defined(OS_MACOSX)
964 CGGetActiveDisplayList (0, NULL, &display_count_);
965 CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback, owner_);
969 if (command_line->HasSwitch(switches::kDisableDomainBlockingFor3DAPIs)) {
970 domain_blocking_enabled_ = false;
974 GpuDataManagerImplPrivate::~GpuDataManagerImplPrivate() {
975 #if defined(OS_MACOSX)
976 CGDisplayRemoveReconfigurationCallback(DisplayReconfigCallback, owner_);
980 void GpuDataManagerImplPrivate::InitializeImpl(
981 const std::string& gpu_blacklist_json,
982 const std::string& gpu_driver_bug_list_json,
983 const gpu::GPUInfo& gpu_info) {
984 const bool log_gpu_control_list_decisions =
985 CommandLine::ForCurrentProcess()->HasSwitch(
986 switches::kLogGpuControlListDecisions);
988 if (!gpu_blacklist_json.empty()) {
989 gpu_blacklist_.reset(gpu::GpuBlacklist::Create());
990 if (log_gpu_control_list_decisions)
991 gpu_blacklist_->enable_control_list_logging("gpu_blacklist");
992 bool success = gpu_blacklist_->LoadList(
993 gpu_blacklist_json, gpu::GpuControlList::kCurrentOsOnly);
996 if (!gpu_driver_bug_list_json.empty()) {
997 gpu_driver_bug_list_.reset(gpu::GpuDriverBugList::Create());
998 if (log_gpu_control_list_decisions)
999 gpu_driver_bug_list_->enable_control_list_logging("gpu_driver_bug_list");
1000 bool success = gpu_driver_bug_list_->LoadList(
1001 gpu_driver_bug_list_json, gpu::GpuControlList::kCurrentOsOnly);
1005 gpu_info_ = gpu_info;
1006 UpdateGpuInfo(gpu_info);
1007 UpdateGpuSwitchingManager(gpu_info);
1008 UpdatePreliminaryBlacklistedFeatures();
1010 #if defined(OS_ANDROID)
1011 ApplyAndroidWorkarounds(gpu_info, CommandLine::ForCurrentProcess());
1012 #endif // OS_ANDROID
1015 void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures(
1016 const std::set<int>& features) {
1017 CommandLine* command_line = CommandLine::ForCurrentProcess();
1018 blacklisted_features_ = features;
1020 // Force disable using the GPU for these features, even if they would
1021 // otherwise be allowed.
1022 if (card_blacklisted_ ||
1023 command_line->HasSwitch(switches::kBlacklistAcceleratedCompositing)) {
1024 blacklisted_features_.insert(
1025 gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING);
1027 if (card_blacklisted_ ||
1028 command_line->HasSwitch(switches::kBlacklistWebGL)) {
1029 blacklisted_features_.insert(gpu::GPU_FEATURE_TYPE_WEBGL);
1032 EnableSwiftShaderIfNecessary();
1035 void GpuDataManagerImplPrivate::UpdatePreliminaryBlacklistedFeatures() {
1036 preliminary_blacklisted_features_ = blacklisted_features_;
1039 void GpuDataManagerImplPrivate::UpdateGpuSwitchingManager(
1040 const gpu::GPUInfo& gpu_info) {
1041 ui::GpuSwitchingManager::GetInstance()->SetGpuCount(
1042 gpu_info.secondary_gpus.size() + 1);
1044 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
1045 if (gpu_driver_bugs_.count(gpu::FORCE_DISCRETE_GPU) == 1)
1046 ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu();
1047 else if (gpu_driver_bugs_.count(gpu::FORCE_INTEGRATED_GPU) == 1)
1048 ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu();
1052 void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() {
1053 observer_list_->Notify(&GpuDataManagerObserver::OnGpuInfoUpdate);
1056 void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() {
1057 if (!GpuAccessAllowed(NULL) ||
1058 blacklisted_features_.count(gpu::GPU_FEATURE_TYPE_WEBGL)) {
1059 if (!swiftshader_path_.empty() &&
1060 !CommandLine::ForCurrentProcess()->HasSwitch(
1061 switches::kDisableSoftwareRasterizer))
1062 use_swiftshader_ = true;
1066 std::string GpuDataManagerImplPrivate::GetDomainFromURL(
1067 const GURL& url) const {
1068 // For the moment, we just use the host, or its IP address, as the
1069 // entry in the set, rather than trying to figure out the top-level
1070 // domain. This does mean that a.foo.com and b.foo.com will be
1071 // treated independently in the blocking of a given domain, but it
1072 // would require a third-party library to reliably figure out the
1073 // top-level domain from a URL.
1074 if (!url.has_host()) {
1075 return std::string();
1081 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIsAtTime(
1083 GpuDataManagerImpl::DomainGuilt guilt,
1084 base::Time at_time) {
1085 if (!domain_blocking_enabled_)
1088 std::string domain = GetDomainFromURL(url);
1090 DomainBlockEntry& entry = blocked_domains_[domain];
1091 entry.last_guilt = guilt;
1092 timestamps_of_gpu_resets_.push_back(at_time);
1095 GpuDataManagerImpl::DomainBlockStatus
1096 GpuDataManagerImplPrivate::Are3DAPIsBlockedAtTime(
1097 const GURL& url, base::Time at_time) const {
1098 if (!domain_blocking_enabled_)
1099 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
1101 // Note: adjusting the policies in this code will almost certainly
1102 // require adjusting the associated unit tests.
1103 std::string domain = GetDomainFromURL(url);
1105 DomainBlockMap::const_iterator iter = blocked_domains_.find(domain);
1106 if (iter != blocked_domains_.end()) {
1107 // Err on the side of caution, and assume that if a particular
1108 // domain shows up in the block map, it's there for a good
1109 // reason and don't let its presence there automatically expire.
1111 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
1112 BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
1115 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED;
1118 // Look at the timestamps of the recent GPU resets to see if there are
1119 // enough within the threshold which would cause us to blacklist all
1120 // domains. This doesn't need to be overly precise -- if time goes
1121 // backward due to a system clock adjustment, that's fine.
1123 // TODO(kbr): make this pay attention to the TDR thresholds in the
1124 // Windows registry, but make sure it continues to be testable.
1126 std::list<base::Time>::iterator iter = timestamps_of_gpu_resets_.begin();
1127 int num_resets_within_timeframe = 0;
1128 while (iter != timestamps_of_gpu_resets_.end()) {
1129 base::Time time = *iter;
1130 base::TimeDelta delta_t = at_time - time;
1132 // If this entry has "expired", just remove it.
1133 if (delta_t.InMilliseconds() > kBlockAllDomainsMs) {
1134 iter = timestamps_of_gpu_resets_.erase(iter);
1138 ++num_resets_within_timeframe;
1142 if (num_resets_within_timeframe >= kNumResetsWithinDuration) {
1143 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
1144 BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
1147 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED;
1151 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
1152 BLOCK_STATUS_NOT_BLOCKED,
1155 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
1158 int64 GpuDataManagerImplPrivate::GetBlockAllDomainsDurationInMs() const {
1159 return kBlockAllDomainsMs;
1162 void GpuDataManagerImplPrivate::Notify3DAPIBlocked(const GURL& url,
1163 int render_process_id,
1165 ThreeDAPIType requester) {
1166 GpuDataManagerImpl::UnlockedSession session(owner_);
1167 observer_list_->Notify(&GpuDataManagerObserver::DidBlock3DAPIs,
1168 url, render_process_id, render_view_id, requester);
1171 void GpuDataManagerImplPrivate::OnGpuProcessInitFailure() {
1172 gpu_process_accessible_ = false;
1173 gpu_info_.finalized = true;
1174 complete_gpu_info_already_requested_ = true;
1175 // Some observers might be waiting.
1176 NotifyGpuInfoUpdate();
1179 } // namespace content