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