| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/gpu/gpu_data_manager_impl.h" | 5 #include "content/browser/gpu/gpu_data_manager_impl.h" |
| 6 | 6 |
| 7 #if defined(OS_MACOSX) | 7 #if defined(OS_MACOSX) |
| 8 #include <ApplicationServices/ApplicationServices.h> | 8 #include <ApplicationServices/ApplicationServices.h> |
| 9 #endif // OS_MACOSX | 9 #endif // OS_MACOSX |
| 10 | 10 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 void* gpu_data_manager) { | 62 void* gpu_data_manager) { |
| 63 if (flags & kCGDisplayAddFlag) { | 63 if (flags & kCGDisplayAddFlag) { |
| 64 GpuDataManagerImpl* manager = | 64 GpuDataManagerImpl* manager = |
| 65 reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager); | 65 reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager); |
| 66 DCHECK(manager); | 66 DCHECK(manager); |
| 67 manager->HandleGpuSwitch(); | 67 manager->HandleGpuSwitch(); |
| 68 } | 68 } |
| 69 } | 69 } |
| 70 #endif // OS_MACOSX | 70 #endif // OS_MACOSX |
| 71 | 71 |
| 72 // Block all domains' use of 3D APIs for this many milliseconds if |
| 73 // approaching a threshold where system stability might be compromised. |
| 74 const int64 kBlockAllDomainsMs = 10000; |
| 75 const int kNumResetsWithinDuration = 1; |
| 76 |
| 72 } // namespace anonymous | 77 } // namespace anonymous |
| 73 | 78 |
| 74 // static | 79 // static |
| 75 GpuDataManager* GpuDataManager::GetInstance() { | 80 GpuDataManager* GpuDataManager::GetInstance() { |
| 76 return GpuDataManagerImpl::GetInstance(); | 81 return GpuDataManagerImpl::GetInstance(); |
| 77 } | 82 } |
| 78 | 83 |
| 79 // static | 84 // static |
| 80 GpuDataManagerImpl* GpuDataManagerImpl::GetInstance() { | 85 GpuDataManagerImpl* GpuDataManagerImpl::GetInstance() { |
| 81 return Singleton<GpuDataManagerImpl>::get(); | 86 return Singleton<GpuDataManagerImpl>::get(); |
| 82 } | 87 } |
| 83 | 88 |
| 84 GpuDataManagerImpl::GpuDataManagerImpl() | 89 GpuDataManagerImpl::GpuDataManagerImpl() |
| 85 : complete_gpu_info_already_requested_(false), | 90 : complete_gpu_info_already_requested_(false), |
| 86 blacklisted_features_(GPU_FEATURE_TYPE_UNKNOWN), | 91 blacklisted_features_(GPU_FEATURE_TYPE_UNKNOWN), |
| 87 preliminary_blacklisted_features_(GPU_FEATURE_TYPE_UNKNOWN), | 92 preliminary_blacklisted_features_(GPU_FEATURE_TYPE_UNKNOWN), |
| 88 gpu_switching_(GPU_SWITCHING_OPTION_AUTOMATIC), | 93 gpu_switching_(GPU_SWITCHING_OPTION_AUTOMATIC), |
| 89 observer_list_(new GpuDataManagerObserverList), | 94 observer_list_(new GpuDataManagerObserverList), |
| 90 software_rendering_(false), | 95 software_rendering_(false), |
| 91 card_blacklisted_(false), | 96 card_blacklisted_(false), |
| 92 update_histograms_(true), | 97 update_histograms_(true), |
| 93 window_count_(0) { | 98 window_count_(0), |
| 99 domain_blocking_enabled_(true) { |
| 94 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 100 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 95 if (command_line->HasSwitch(switches::kDisableAcceleratedCompositing)) { | 101 if (command_line->HasSwitch(switches::kDisableAcceleratedCompositing)) { |
| 96 command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas); | 102 command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas); |
| 97 command_line->AppendSwitch(switches::kDisableAcceleratedLayers); | 103 command_line->AppendSwitch(switches::kDisableAcceleratedLayers); |
| 98 } | 104 } |
| 99 if (command_line->HasSwitch(switches::kDisableGpu)) | 105 if (command_line->HasSwitch(switches::kDisableGpu)) |
| 100 BlacklistCard(); | 106 BlacklistCard(); |
| 101 if (command_line->HasSwitch(switches::kGpuSwitching)) { | 107 if (command_line->HasSwitch(switches::kGpuSwitching)) { |
| 102 std::string option_string = command_line->GetSwitchValueASCII( | 108 std::string option_string = command_line->GetSwitchValueASCII( |
| 103 switches::kGpuSwitching); | 109 switches::kGpuSwitching); |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, | 339 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, |
| 334 CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH, | 340 CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH, |
| 335 new GpuMsg_SetVideoMemoryWindowCount(count)); | 341 new GpuMsg_SetVideoMemoryWindowCount(count)); |
| 336 } | 342 } |
| 337 | 343 |
| 338 uint32 GpuDataManagerImpl::GetWindowCount() const { | 344 uint32 GpuDataManagerImpl::GetWindowCount() const { |
| 339 base::AutoLock auto_lock(gpu_info_lock_); | 345 base::AutoLock auto_lock(gpu_info_lock_); |
| 340 return window_count_; | 346 return window_count_; |
| 341 } | 347 } |
| 342 | 348 |
| 349 void GpuDataManagerImpl::BlockDomainFrom3DAPIs( |
| 350 const GURL& url, DomainGuilt guilt) { |
| 351 BlockDomainFrom3DAPIsAtTime(url, guilt, base::Time::Now()); |
| 352 } |
| 353 |
| 354 GpuDataManager::DomainBlockStatus |
| 355 GpuDataManagerImpl::Are3DAPIsBlocked(const GURL& url) const { |
| 356 return Are3DAPIsBlockedAtTime(url, base::Time::Now()); |
| 357 } |
| 358 |
| 359 void GpuDataManagerImpl::UnblockDomainFrom3DAPIs(const GURL& url) { |
| 360 // This method must do two things: |
| 361 // |
| 362 // 1. If the specific domain is blocked, then unblock it. |
| 363 // |
| 364 // 2. Reset our notion of how many GPU resets have occurred recently. |
| 365 // This is necessary even if the specific domain was blocked. |
| 366 // Otherwise, if we call Are3DAPIsBlocked with the same domain right |
| 367 // after unblocking it, it will probably still be blocked because of |
| 368 // the recent GPU reset caused by that domain. |
| 369 // |
| 370 // These policies could be refined, but at a certain point the behavior |
| 371 // will become difficult to explain. |
| 372 std::string domain = GetDomainFromURL(url); |
| 373 |
| 374 base::AutoLock auto_lock(gpu_info_lock_); |
| 375 blocked_domains_.erase(domain); |
| 376 timestamps_of_gpu_resets_.clear(); |
| 377 } |
| 378 |
| 379 void GpuDataManagerImpl::DisableDomainBlockingFor3DAPIsForTesting() { |
| 380 domain_blocking_enabled_ = false; |
| 381 } |
| 382 |
| 343 void GpuDataManagerImpl::AppendRendererCommandLine( | 383 void GpuDataManagerImpl::AppendRendererCommandLine( |
| 344 CommandLine* command_line) const { | 384 CommandLine* command_line) const { |
| 345 DCHECK(command_line); | 385 DCHECK(command_line); |
| 346 | 386 |
| 347 uint32 flags = GetBlacklistedFeatures(); | 387 uint32 flags = GetBlacklistedFeatures(); |
| 348 if ((flags & GPU_FEATURE_TYPE_WEBGL)) { | 388 if ((flags & GPU_FEATURE_TYPE_WEBGL)) { |
| 349 #if !defined(OS_ANDROID) | 389 #if !defined(OS_ANDROID) |
| 350 if (!command_line->HasSwitch(switches::kDisableExperimentalWebGL)) | 390 if (!command_line->HasSwitch(switches::kDisableExperimentalWebGL)) |
| 351 command_line->AppendSwitch(switches::kDisableExperimentalWebGL); | 391 command_line->AppendSwitch(switches::kDisableExperimentalWebGL); |
| 352 #endif | 392 #endif |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 560 | 600 |
| 561 void GpuDataManagerImpl::BlacklistCard() { | 601 void GpuDataManagerImpl::BlacklistCard() { |
| 562 card_blacklisted_ = true; | 602 card_blacklisted_ = true; |
| 563 | 603 |
| 564 blacklisted_features_ = GPU_FEATURE_TYPE_ALL; | 604 blacklisted_features_ = GPU_FEATURE_TYPE_ALL; |
| 565 | 605 |
| 566 EnableSoftwareRenderingIfNecessary(); | 606 EnableSoftwareRenderingIfNecessary(); |
| 567 NotifyGpuInfoUpdate(); | 607 NotifyGpuInfoUpdate(); |
| 568 } | 608 } |
| 569 | 609 |
| 610 std::string GpuDataManagerImpl::GetDomainFromURL(const GURL& url) const { |
| 611 // For the moment, we just use the host, or its IP address, as the |
| 612 // entry in the set, rather than trying to figure out the top-level |
| 613 // domain. This does mean that a.foo.com and b.foo.com will be |
| 614 // treated independently in the blocking of a given domain, but it |
| 615 // would require a third-party library to reliably figure out the |
| 616 // top-level domain from a URL. |
| 617 if (!url.has_host()) { |
| 618 return std::string(); |
| 619 } |
| 620 |
| 621 return url.host(); |
| 622 } |
| 623 |
| 624 void GpuDataManagerImpl::BlockDomainFrom3DAPIsAtTime( |
| 625 const GURL& url, DomainGuilt guilt, base::Time at_time) { |
| 626 if (!domain_blocking_enabled_) |
| 627 return; |
| 628 |
| 629 std::string domain = GetDomainFromURL(url); |
| 630 |
| 631 base::AutoLock auto_lock(gpu_info_lock_); |
| 632 DomainBlockEntry& entry = blocked_domains_[domain]; |
| 633 entry.last_guilt = guilt; |
| 634 timestamps_of_gpu_resets_.push_back(at_time); |
| 635 } |
| 636 |
| 637 GpuDataManager::DomainBlockStatus GpuDataManagerImpl::Are3DAPIsBlockedAtTime( |
| 638 const GURL& url, base::Time at_time) const { |
| 639 if (!domain_blocking_enabled_) |
| 640 return DOMAIN_BLOCK_STATUS_NOT_BLOCKED; |
| 641 |
| 642 // Note: adjusting the policies in this code will almost certainly |
| 643 // require adjusting the associated unit tests. |
| 644 std::string domain = GetDomainFromURL(url); |
| 645 |
| 646 base::AutoLock auto_lock(gpu_info_lock_); |
| 647 { |
| 648 DomainBlockMap::const_iterator iter = blocked_domains_.find(domain); |
| 649 if (iter != blocked_domains_.end()) { |
| 650 // Err on the side of caution, and assume that if a particular |
| 651 // domain shows up in the block map, it's there for a good |
| 652 // reason and don't let its presence there automatically expire. |
| 653 return DOMAIN_BLOCK_STATUS_BLOCKED; |
| 654 } |
| 655 } |
| 656 |
| 657 // Look at the timestamps of the recent GPU resets to see if there are |
| 658 // enough within the threshold which would cause us to blacklist all |
| 659 // domains. This doesn't need to be overly precise -- if time goes |
| 660 // backward due to a system clock adjustment, that's fine. |
| 661 // |
| 662 // TODO(kbr): make this pay attention to the TDR thresholds in the |
| 663 // Windows registry, but make sure it continues to be testable. |
| 664 std::list<base::Time>::iterator iter = timestamps_of_gpu_resets_.begin(); |
| 665 int num_resets_within_timeframe = 0; |
| 666 while (iter != timestamps_of_gpu_resets_.end()) { |
| 667 base::Time time = *iter; |
| 668 base::TimeDelta delta_t = at_time - time; |
| 669 |
| 670 // If this entry has "expired", just remove it. |
| 671 if (delta_t.InMilliseconds() > kBlockAllDomainsMs) { |
| 672 iter = timestamps_of_gpu_resets_.erase(iter); |
| 673 continue; |
| 674 } |
| 675 |
| 676 ++num_resets_within_timeframe; |
| 677 ++iter; |
| 678 } |
| 679 |
| 680 if (num_resets_within_timeframe >= kNumResetsWithinDuration) { |
| 681 return DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED; |
| 682 } |
| 683 |
| 684 return DOMAIN_BLOCK_STATUS_NOT_BLOCKED; |
| 685 } |
| 686 |
| 687 int64 GpuDataManagerImpl::GetBlockAllDomainsDurationInMs() const { |
| 688 return kBlockAllDomainsMs; |
| 689 } |
| 690 |
| 570 } // namespace content | 691 } // namespace content |
| OLD | NEW |