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 "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" 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 "base/android/build_info.h" 46 #include "ui/gfx/android/device_display_info.h" 47 #endif // OS_ANDROID 48 49 namespace content { 50 51 namespace { 52 53 enum GpuFeatureStatus { 54 kGpuFeatureEnabled = 0, 55 kGpuFeatureBlacklisted = 1, 56 kGpuFeatureDisabled = 2, // disabled by user but not blacklisted 57 kGpuFeatureNumStatus 58 }; 59 60 #if defined(OS_WIN) 61 62 enum WinSubVersion { 63 kWinOthers = 0, 64 kWinXP, 65 kWinVista, 66 kWin7, 67 kWin8, 68 kNumWinSubVersions 69 }; 70 71 int GetGpuBlacklistHistogramValueWin(GpuFeatureStatus status) { 72 static WinSubVersion sub_version = kNumWinSubVersions; 73 if (sub_version == kNumWinSubVersions) { 74 sub_version = kWinOthers; 75 std::string version_str = base::SysInfo::OperatingSystemVersion(); 76 size_t pos = version_str.find_first_not_of("0123456789."); 77 if (pos != std::string::npos) 78 version_str = version_str.substr(0, pos); 79 Version os_version(version_str); 80 if (os_version.IsValid() && os_version.components().size() >= 2) { 81 const std::vector<uint16>& version_numbers = os_version.components(); 82 if (version_numbers[0] == 5) 83 sub_version = kWinXP; 84 else if (version_numbers[0] == 6 && version_numbers[1] == 0) 85 sub_version = kWinVista; 86 else if (version_numbers[0] == 6 && version_numbers[1] == 1) 87 sub_version = kWin7; 88 else if (version_numbers[0] == 6 && version_numbers[1] == 2) 89 sub_version = kWin8; 90 } 91 } 92 int entry_index = static_cast<int>(sub_version) * kGpuFeatureNumStatus; 93 switch (status) { 94 case kGpuFeatureEnabled: 95 break; 96 case kGpuFeatureBlacklisted: 97 entry_index++; 98 break; 99 case kGpuFeatureDisabled: 100 entry_index += 2; 101 break; 102 } 103 return entry_index; 104 } 105 #endif // OS_WIN 106 107 // Send UMA histograms about the enabled features and GPU properties. 108 void UpdateStats(const gpu::GPUInfo& gpu_info, 109 const gpu::GpuBlacklist* blacklist, 110 const std::set<int>& blacklisted_features) { 111 uint32 max_entry_id = blacklist->max_entry_id(); 112 if (max_entry_id == 0) { 113 // GPU Blacklist was not loaded. No need to go further. 114 return; 115 } 116 117 const CommandLine& command_line = *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 (size_t i = 0; i < flag_disabled_entries.size(); ++i) { 143 UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerDisabledEntry", 144 flag_disabled_entries[i], max_entry_id + 1); 145 } 146 147 const gpu::GpuFeatureType kGpuFeatures[] = { 148 gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS, 149 gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING, 150 gpu::GPU_FEATURE_TYPE_WEBGL, 151 gpu::GPU_FEATURE_TYPE_TEXTURE_SHARING 152 }; 153 const std::string kGpuBlacklistFeatureHistogramNames[] = { 154 "GPU.BlacklistFeatureTestResults.Accelerated2dCanvas", 155 "GPU.BlacklistFeatureTestResults.AcceleratedCompositing", 156 "GPU.BlacklistFeatureTestResults.Webgl", 157 "GPU.BlacklistFeatureTestResults.TextureSharing" 158 }; 159 const bool kGpuFeatureUserFlags[] = { 160 command_line.HasSwitch(switches::kDisableAccelerated2dCanvas), 161 command_line.HasSwitch(switches::kDisableAcceleratedCompositing), 162 command_line.HasSwitch(switches::kDisableExperimentalWebGL), 163 command_line.HasSwitch(switches::kDisableImageTransportSurface) 164 }; 165 #if defined(OS_WIN) 166 const std::string kGpuBlacklistFeatureHistogramNamesWin[] = { 167 "GPU.BlacklistFeatureTestResultsWindows.Accelerated2dCanvas", 168 "GPU.BlacklistFeatureTestResultsWindows.AcceleratedCompositing", 169 "GPU.BlacklistFeatureTestResultsWindows.Webgl", 170 "GPU.BlacklistFeatureTestResultsWindows.TextureSharing" 171 }; 172 #endif 173 const size_t kNumFeatures = 174 sizeof(kGpuFeatures) / sizeof(gpu::GpuFeatureType); 175 for (size_t i = 0; i < kNumFeatures; ++i) { 176 // We can't use UMA_HISTOGRAM_ENUMERATION here because the same name is 177 // expected if the macro is used within a loop. 178 GpuFeatureStatus value = kGpuFeatureEnabled; 179 if (blacklisted_features.count(kGpuFeatures[i])) 180 value = kGpuFeatureBlacklisted; 181 else if (kGpuFeatureUserFlags[i]) 182 value = kGpuFeatureDisabled; 183 base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet( 184 kGpuBlacklistFeatureHistogramNames[i], 185 1, kGpuFeatureNumStatus, kGpuFeatureNumStatus + 1, 186 base::HistogramBase::kUmaTargetedHistogramFlag); 187 histogram_pointer->Add(value); 188 #if defined(OS_WIN) 189 histogram_pointer = base::LinearHistogram::FactoryGet( 190 kGpuBlacklistFeatureHistogramNamesWin[i], 191 1, kNumWinSubVersions * kGpuFeatureNumStatus, 192 kNumWinSubVersions * kGpuFeatureNumStatus + 1, 193 base::HistogramBase::kUmaTargetedHistogramFlag); 194 histogram_pointer->Add(GetGpuBlacklistHistogramValueWin(value)); 195 #endif 196 } 197 198 UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.GLResetNotificationStrategy", 199 gpu_info.gl_reset_notification_strategy); 200 } 201 202 // Strip out the non-digital info; if after that, we get an empty string, 203 // return "0". 204 std::string ProcessVersionString(const std::string& raw_string) { 205 const std::string valid_set = "0123456789."; 206 size_t start_pos = raw_string.find_first_of(valid_set); 207 if (start_pos == std::string::npos) 208 return "0"; 209 size_t end_pos = raw_string.find_first_not_of(raw_string, start_pos); 210 std::string version_string = raw_string.substr( 211 start_pos, end_pos - start_pos); 212 if (version_string.empty()) 213 return "0"; 214 return version_string; 215 } 216 217 // Combine the integers into a string, seperated by ','. 218 std::string IntSetToString(const std::set<int>& list) { 219 std::string rt; 220 for (std::set<int>::const_iterator it = list.begin(); 221 it != list.end(); ++it) { 222 if (!rt.empty()) 223 rt += ","; 224 rt += base::IntToString(*it); 225 } 226 return rt; 227 } 228 229 #if defined(OS_MACOSX) 230 void DisplayReconfigCallback(CGDirectDisplayID display, 231 CGDisplayChangeSummaryFlags flags, 232 void* gpu_data_manager) { 233 if(flags == kCGDisplayBeginConfigurationFlag) 234 return; // This call contains no information about the display change 235 236 GpuDataManagerImpl* manager = 237 reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager); 238 DCHECK(manager); 239 240 uint32_t displayCount; 241 CGGetActiveDisplayList(0, NULL, &displayCount); 242 243 bool fireGpuSwitch = flags & kCGDisplayAddFlag; 244 245 if (displayCount != manager->GetDisplayCount()) { 246 manager->SetDisplayCount(displayCount); 247 fireGpuSwitch = true; 248 } 249 250 if (fireGpuSwitch) 251 manager->HandleGpuSwitch(); 252 } 253 #endif // OS_MACOSX 254 255 #if defined(OS_ANDROID) 256 void ApplyAndroidWorkarounds(const gpu::GPUInfo& gpu_info, 257 CommandLine* command_line) { 258 std::string vendor(StringToLowerASCII(gpu_info.gl_vendor)); 259 std::string renderer(StringToLowerASCII(gpu_info.gl_renderer)); 260 bool is_img = 261 gpu_info.gl_vendor.find("Imagination") != std::string::npos; 262 bool is_arm = 263 gpu_info.gl_vendor.find("ARM") != std::string::npos; 264 bool is_qualcomm = 265 gpu_info.gl_vendor.find("Qualcomm") != std::string::npos; 266 bool is_broadcom = 267 gpu_info.gl_vendor.find("Broadcom") != std::string::npos; 268 bool is_mali_t604 = is_arm && 269 gpu_info.gl_renderer.find("Mali-T604") != std::string::npos; 270 bool is_nvidia = 271 gpu_info.gl_vendor.find("NVIDIA") != std::string::npos; 272 273 bool is_vivante = 274 gpu_info.gl_extensions.find("GL_VIV_shader_binary") != 275 std::string::npos; 276 277 bool is_nexus7 = 278 gpu_info.machine_model.find("Nexus 7") != std::string::npos; 279 bool is_nexus10 = 280 gpu_info.machine_model.find("Nexus 10") != std::string::npos; 281 282 int sdk_int = base::android::BuildInfo::GetInstance()->sdk_int(); 283 284 // IMG: avoid context switching perf problems, crashes with share groups 285 // Mali-T604: http://crbug.com/154715 286 // QualComm, NVIDIA: Crashes with share groups 287 if (is_vivante || is_img || is_mali_t604 || (is_nvidia && (sdk_int < 18)) || 288 is_qualcomm || is_broadcom) { 289 command_line->AppendSwitch(switches::kEnableVirtualGLContexts); 290 } 291 292 gfx::DeviceDisplayInfo info; 293 int default_tile_size = 256; 294 295 // For very high resolution displays (eg. Nexus 10), set the default 296 // tile size to be 512. This should be removed in favour of a generic 297 // hueristic that works across all platforms and devices, once that 298 // exists: http://crbug.com/159524. This switches to 512 for screens 299 // containing 40 or more 256x256 tiles, such that 1080p devices do 300 // not use 512x512 tiles (eg. 1920x1280 requires 37.5 tiles) 301 int numTiles = (info.GetDisplayWidth() * 302 info.GetDisplayHeight()) / (256 * 256); 303 if (numTiles >= 40) 304 default_tile_size = 512; 305 306 // IMG: Fast async texture uploads only work with non-power-of-two, 307 // but still multiple-of-eight sizes. 308 // http://crbug.com/168099 309 if (is_img) 310 default_tile_size -= 8; 311 312 // If we are using the MapImage API double the tile size to reduce 313 // the number of zero-copy buffers being used. 314 if (command_line->HasSwitch(cc::switches::kUseMapImage)) 315 default_tile_size *= 2; 316 317 // Set the command line if it isn't already set and we changed 318 // the default tile size. 319 if (default_tile_size != 256 && 320 !command_line->HasSwitch(switches::kDefaultTileWidth) && 321 !command_line->HasSwitch(switches::kDefaultTileHeight)) { 322 std::stringstream size; 323 size << default_tile_size; 324 command_line->AppendSwitchASCII( 325 switches::kDefaultTileWidth, size.str()); 326 command_line->AppendSwitchASCII( 327 switches::kDefaultTileHeight, size.str()); 328 } 329 330 // Increase the resolution of low resolution tiles for Nexus tablets. 331 if ((is_nexus7 || is_nexus10) && 332 !command_line->HasSwitch( 333 cc::switches::kLowResolutionContentsScaleFactor)) { 334 command_line->AppendSwitchASCII( 335 cc::switches::kLowResolutionContentsScaleFactor, "0.25"); 336 } 337 } 338 #endif // OS_ANDROID 339 340 // Block all domains' use of 3D APIs for this many milliseconds if 341 // approaching a threshold where system stability might be compromised. 342 const int64 kBlockAllDomainsMs = 10000; 343 const int kNumResetsWithinDuration = 1; 344 345 // Enums for UMA histograms. 346 enum BlockStatusHistogram { 347 BLOCK_STATUS_NOT_BLOCKED, 348 BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED, 349 BLOCK_STATUS_ALL_DOMAINS_BLOCKED, 350 BLOCK_STATUS_MAX 351 }; 352 353 } // namespace anonymous 354 355 void GpuDataManagerImplPrivate::InitializeForTesting( 356 const std::string& gpu_blacklist_json, 357 const gpu::GPUInfo& gpu_info) { 358 // This function is for testing only, so disable histograms. 359 update_histograms_ = false; 360 361 InitializeImpl(gpu_blacklist_json, std::string(), std::string(), gpu_info); 362 } 363 364 bool GpuDataManagerImplPrivate::IsFeatureBlacklisted(int feature) const { 365 if (use_swiftshader_) { 366 // Skia's software rendering is probably more efficient than going through 367 // software emulation of the GPU, so use that. 368 if (feature == gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS) 369 return true; 370 return false; 371 } 372 373 return (blacklisted_features_.count(feature) == 1); 374 } 375 376 size_t GpuDataManagerImplPrivate::GetBlacklistedFeatureCount() const { 377 if (use_swiftshader_) 378 return 1; 379 return blacklisted_features_.size(); 380 } 381 382 void GpuDataManagerImplPrivate::SetDisplayCount(unsigned int display_count) { 383 display_count_ = display_count; 384 } 385 386 unsigned int GpuDataManagerImplPrivate::GetDisplayCount() const { 387 return display_count_; 388 } 389 390 gpu::GPUInfo GpuDataManagerImplPrivate::GetGPUInfo() const { 391 return gpu_info_; 392 } 393 394 void GpuDataManagerImplPrivate::GetGpuProcessHandles( 395 const GpuDataManager::GetGpuProcessHandlesCallback& callback) const { 396 GpuProcessHost::GetProcessHandles(callback); 397 } 398 399 bool GpuDataManagerImplPrivate::GpuAccessAllowed( 400 std::string* reason) const { 401 if (use_swiftshader_) 402 return true; 403 404 if (!gpu_process_accessible_) { 405 if (reason) { 406 *reason = "GPU process launch failed."; 407 } 408 return false; 409 } 410 411 if (card_blacklisted_) { 412 if (reason) { 413 *reason = "GPU access is disabled "; 414 CommandLine* command_line = CommandLine::ForCurrentProcess(); 415 if (command_line->HasSwitch(switches::kDisableGpu)) 416 *reason += "through commandline switch --disable-gpu."; 417 else 418 *reason += "in chrome://settings."; 419 } 420 return false; 421 } 422 423 // We only need to block GPU process if more features are disallowed other 424 // than those in the preliminary gpu feature flags because the latter work 425 // through renderer commandline switches. 426 std::set<int> features = preliminary_blacklisted_features_; 427 gpu::MergeFeatureSets(&features, blacklisted_features_); 428 if (features.size() > preliminary_blacklisted_features_.size()) { 429 if (reason) { 430 *reason = "Features are disabled upon full but not preliminary GPU info."; 431 } 432 return false; 433 } 434 435 if (blacklisted_features_.size() == gpu::NUMBER_OF_GPU_FEATURE_TYPES) { 436 // On Linux, we use cached GL strings to make blacklist decsions at browser 437 // startup time. We need to launch the GPU process to validate these 438 // strings even if all features are blacklisted. If all GPU features are 439 // disabled, the GPU process will only initialize GL bindings, create a GL 440 // context, and collect full GPU info. 441 #if !defined(OS_LINUX) 442 if (reason) { 443 *reason = "All GPU features are blacklisted."; 444 } 445 return false; 446 #endif 447 } 448 449 return true; 450 } 451 452 void GpuDataManagerImplPrivate::RequestCompleteGpuInfoIfNeeded() { 453 if (complete_gpu_info_already_requested_ || gpu_info_.finalized) 454 return; 455 complete_gpu_info_already_requested_ = true; 456 457 GpuProcessHost::SendOnIO( 458 #if defined(OS_WIN) 459 GpuProcessHost::GPU_PROCESS_KIND_UNSANDBOXED, 460 #else 461 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, 462 #endif 463 CAUSE_FOR_GPU_LAUNCH_GPUDATAMANAGER_REQUESTCOMPLETEGPUINFOIFNEEDED, 464 new GpuMsg_CollectGraphicsInfo()); 465 } 466 467 bool GpuDataManagerImplPrivate::IsCompleteGpuInfoAvailable() const { 468 return gpu_info_.finalized; 469 } 470 471 void GpuDataManagerImplPrivate::RequestVideoMemoryUsageStatsUpdate() const { 472 GpuProcessHost::SendOnIO( 473 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, 474 CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH, 475 new GpuMsg_GetVideoMemoryUsageStats()); 476 } 477 478 bool GpuDataManagerImplPrivate::ShouldUseSwiftShader() const { 479 return use_swiftshader_; 480 } 481 482 void GpuDataManagerImplPrivate::RegisterSwiftShaderPath( 483 const base::FilePath& path) { 484 swiftshader_path_ = path; 485 EnableSwiftShaderIfNecessary(); 486 } 487 488 void GpuDataManagerImplPrivate::AddObserver(GpuDataManagerObserver* observer) { 489 GpuDataManagerImpl::UnlockedSession session(owner_); 490 observer_list_->AddObserver(observer); 491 } 492 493 void GpuDataManagerImplPrivate::RemoveObserver( 494 GpuDataManagerObserver* observer) { 495 GpuDataManagerImpl::UnlockedSession session(owner_); 496 observer_list_->RemoveObserver(observer); 497 } 498 499 void GpuDataManagerImplPrivate::UnblockDomainFrom3DAPIs(const GURL& url) { 500 // This method must do two things: 501 // 502 // 1. If the specific domain is blocked, then unblock it. 503 // 504 // 2. Reset our notion of how many GPU resets have occurred recently. 505 // This is necessary even if the specific domain was blocked. 506 // Otherwise, if we call Are3DAPIsBlocked with the same domain right 507 // after unblocking it, it will probably still be blocked because of 508 // the recent GPU reset caused by that domain. 509 // 510 // These policies could be refined, but at a certain point the behavior 511 // will become difficult to explain. 512 std::string domain = GetDomainFromURL(url); 513 514 blocked_domains_.erase(domain); 515 timestamps_of_gpu_resets_.clear(); 516 } 517 518 void GpuDataManagerImplPrivate::DisableGpuWatchdog() { 519 GpuProcessHost::SendOnIO( 520 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, 521 CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH, 522 new GpuMsg_DisableWatchdog); 523 } 524 525 void GpuDataManagerImplPrivate::SetGLStrings(const std::string& gl_vendor, 526 const std::string& gl_renderer, 527 const std::string& gl_version) { 528 if (gl_vendor.empty() && gl_renderer.empty() && gl_version.empty()) 529 return; 530 531 // If GPUInfo already got GL strings, do nothing. This is for the rare 532 // situation where GPU process collected GL strings before this call. 533 if (!gpu_info_.gl_vendor.empty() || 534 !gpu_info_.gl_renderer.empty() || 535 !gpu_info_.gl_version_string.empty()) 536 return; 537 538 gpu::GPUInfo gpu_info = gpu_info_; 539 540 gpu_info.gl_vendor = gl_vendor; 541 gpu_info.gl_renderer = gl_renderer; 542 gpu_info.gl_version_string = gl_version; 543 544 gpu::CollectDriverInfoGL(&gpu_info); 545 546 UpdateGpuInfo(gpu_info); 547 UpdateGpuSwitchingManager(gpu_info); 548 UpdatePreliminaryBlacklistedFeatures(); 549 } 550 551 void GpuDataManagerImplPrivate::GetGLStrings(std::string* gl_vendor, 552 std::string* gl_renderer, 553 std::string* gl_version) { 554 DCHECK(gl_vendor && gl_renderer && gl_version); 555 556 *gl_vendor = gpu_info_.gl_vendor; 557 *gl_renderer = gpu_info_.gl_renderer; 558 *gl_version = gpu_info_.gl_version_string; 559 } 560 561 void GpuDataManagerImplPrivate::Initialize() { 562 TRACE_EVENT0("startup", "GpuDataManagerImpl::Initialize"); 563 CommandLine* command_line = CommandLine::ForCurrentProcess(); 564 if (command_line->HasSwitch(switches::kSkipGpuDataLoading) && 565 !command_line->HasSwitch(switches::kUseGpuInTests)) 566 return; 567 568 gpu::GPUInfo gpu_info; 569 { 570 TRACE_EVENT0("startup", 571 "GpuDataManagerImpl::Initialize:CollectBasicGraphicsInfo"); 572 gpu::CollectBasicGraphicsInfo(&gpu_info); 573 } 574 #if defined(ARCH_CPU_X86_FAMILY) 575 if (!gpu_info.gpu.vendor_id || !gpu_info.gpu.device_id) 576 gpu_info.finalized = true; 577 #endif 578 579 std::string gpu_blacklist_string; 580 std::string gpu_switching_list_string; 581 std::string gpu_driver_bug_list_string; 582 if (!command_line->HasSwitch(switches::kIgnoreGpuBlacklist) && 583 !command_line->HasSwitch(switches::kUseGpuInTests)) { 584 gpu_blacklist_string = gpu::kSoftwareRenderingListJson; 585 gpu_switching_list_string = gpu::kGpuSwitchingListJson; 586 } 587 if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) { 588 gpu_driver_bug_list_string = gpu::kGpuDriverBugListJson; 589 } 590 InitializeImpl(gpu_blacklist_string, 591 gpu_switching_list_string, 592 gpu_driver_bug_list_string, 593 gpu_info); 594 } 595 596 void GpuDataManagerImplPrivate::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) { 597 // No further update of gpu_info if falling back to SwiftShader. 598 if (use_swiftshader_) 599 return; 600 601 gpu::MergeGPUInfo(&gpu_info_, gpu_info); 602 complete_gpu_info_already_requested_ = 603 complete_gpu_info_already_requested_ || gpu_info_.finalized; 604 605 GetContentClient()->SetGpuInfo(gpu_info_); 606 607 if (gpu_blacklist_) { 608 std::set<int> features = gpu_blacklist_->MakeDecision( 609 gpu::GpuControlList::kOsAny, std::string(), gpu_info_); 610 if (update_histograms_) 611 UpdateStats(gpu_info_, gpu_blacklist_.get(), features); 612 613 UpdateBlacklistedFeatures(features); 614 } 615 if (gpu_switching_list_) { 616 std::set<int> option = gpu_switching_list_->MakeDecision( 617 gpu::GpuControlList::kOsAny, std::string(), gpu_info_); 618 if (option.size() == 1) { 619 // Blacklist decision should not overwrite commandline switch from users. 620 CommandLine* command_line = CommandLine::ForCurrentProcess(); 621 if (!command_line->HasSwitch(switches::kGpuSwitching)) { 622 gpu_switching_ = static_cast<gpu::GpuSwitchingOption>( 623 *(option.begin())); 624 } 625 } 626 } 627 if (gpu_driver_bug_list_) { 628 gpu_driver_bugs_ = gpu_driver_bug_list_->MakeDecision( 629 gpu::GpuControlList::kOsAny, std::string(), gpu_info_); 630 } 631 632 // We have to update GpuFeatureType before notify all the observers. 633 NotifyGpuInfoUpdate(); 634 } 635 636 void GpuDataManagerImplPrivate::UpdateVideoMemoryUsageStats( 637 const GPUVideoMemoryUsageStats& video_memory_usage_stats) { 638 GpuDataManagerImpl::UnlockedSession session(owner_); 639 observer_list_->Notify(&GpuDataManagerObserver::OnVideoMemoryUsageStatsUpdate, 640 video_memory_usage_stats); 641 } 642 643 void GpuDataManagerImplPrivate::AppendRendererCommandLine( 644 CommandLine* command_line) const { 645 DCHECK(command_line); 646 647 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL)) { 648 if (!command_line->HasSwitch(switches::kDisableExperimentalWebGL)) 649 command_line->AppendSwitch(switches::kDisableExperimentalWebGL); 650 if (!command_line->HasSwitch(switches::kDisablePepper3d)) 651 command_line->AppendSwitch(switches::kDisablePepper3d); 652 } 653 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_MULTISAMPLING) && 654 !command_line->HasSwitch(switches::kDisableGLMultisampling)) 655 command_line->AppendSwitch(switches::kDisableGLMultisampling); 656 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) && 657 !command_line->HasSwitch(switches::kDisableAcceleratedCompositing)) 658 command_line->AppendSwitch(switches::kDisableAcceleratedCompositing); 659 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS) && 660 !command_line->HasSwitch(switches::kDisableAccelerated2dCanvas)) 661 command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas); 662 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) && 663 !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) 664 command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode); 665 666 if (use_software_compositor_ && 667 !command_line->HasSwitch(switches::kEnableSoftwareCompositing)) 668 command_line->AppendSwitch(switches::kEnableSoftwareCompositing); 669 670 #if defined(USE_AURA) 671 if (!CanUseGpuBrowserCompositor()) { 672 command_line->AppendSwitch(switches::kDisableGpuCompositing); 673 command_line->AppendSwitch(switches::kDisablePepper3d); 674 } 675 #endif 676 } 677 678 void GpuDataManagerImplPrivate::AppendGpuCommandLine( 679 CommandLine* command_line) const { 680 DCHECK(command_line); 681 682 bool reduce_sandbox = false; 683 684 std::string use_gl = 685 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL); 686 base::FilePath swiftshader_path = 687 CommandLine::ForCurrentProcess()->GetSwitchValuePath( 688 switches::kSwiftShaderPath); 689 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_MULTISAMPLING) && 690 !command_line->HasSwitch(switches::kDisableGLMultisampling)) { 691 command_line->AppendSwitch(switches::kDisableGLMultisampling); 692 } 693 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_TEXTURE_SHARING)) { 694 command_line->AppendSwitch(switches::kDisableImageTransportSurface); 695 reduce_sandbox = true; 696 } 697 if (gpu_driver_bugs_.find(gpu::DISABLE_D3D11) != gpu_driver_bugs_.end()) 698 command_line->AppendSwitch(switches::kDisableD3D11); 699 if (use_swiftshader_) { 700 command_line->AppendSwitchASCII(switches::kUseGL, "swiftshader"); 701 if (swiftshader_path.empty()) 702 swiftshader_path = swiftshader_path_; 703 } else if ((IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL) || 704 IsFeatureBlacklisted( 705 gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) || 706 IsFeatureBlacklisted( 707 gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)) && 708 (use_gl == "any")) { 709 command_line->AppendSwitchASCII( 710 switches::kUseGL, gfx::kGLImplementationOSMesaName); 711 } else if (!use_gl.empty()) { 712 command_line->AppendSwitchASCII(switches::kUseGL, use_gl); 713 } 714 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) { 715 command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "true"); 716 switch (gpu_switching_) { 717 case gpu::GPU_SWITCHING_OPTION_FORCE_DISCRETE: 718 command_line->AppendSwitchASCII(switches::kGpuSwitching, 719 switches::kGpuSwitchingOptionNameForceDiscrete); 720 break; 721 case gpu::GPU_SWITCHING_OPTION_FORCE_INTEGRATED: 722 command_line->AppendSwitchASCII(switches::kGpuSwitching, 723 switches::kGpuSwitchingOptionNameForceIntegrated); 724 break; 725 case gpu::GPU_SWITCHING_OPTION_AUTOMATIC: 726 case gpu::GPU_SWITCHING_OPTION_UNKNOWN: 727 break; 728 } 729 } else { 730 command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "false"); 731 } 732 733 if (!swiftshader_path.empty()) { 734 command_line->AppendSwitchPath(switches::kSwiftShaderPath, 735 swiftshader_path); 736 } 737 738 if (!gpu_driver_bugs_.empty()) { 739 command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds, 740 IntSetToString(gpu_driver_bugs_)); 741 } 742 743 #if defined(OS_WIN) 744 // DisplayLink 7.1 and earlier can cause the GPU process to crash on startup. 745 // http://crbug.com/177611 746 // Thinkpad USB Port Replicator driver causes GPU process to crash when the 747 // sandbox is enabled. http://crbug.com/181665. 748 if ((gpu_info_.display_link_version.IsValid() 749 && gpu_info_.display_link_version.IsOlderThan("7.2")) || 750 gpu_info_.lenovo_dcute) { 751 reduce_sandbox = true; 752 } 753 #endif 754 755 if (gpu_info_.optimus) 756 reduce_sandbox = true; 757 758 if (reduce_sandbox) 759 command_line->AppendSwitch(switches::kReduceGpuSandbox); 760 761 // Pass GPU and driver information to GPU process. We try to avoid full GPU 762 // info collection at GPU process startup, but we need gpu vendor_id, 763 // device_id, driver_vendor, driver_version for deciding whether we need to 764 // collect full info (on Linux) and for crash reporting purpose. 765 command_line->AppendSwitchASCII(switches::kGpuVendorID, 766 base::StringPrintf("0x%04x", gpu_info_.gpu.vendor_id)); 767 command_line->AppendSwitchASCII(switches::kGpuDeviceID, 768 base::StringPrintf("0x%04x", gpu_info_.gpu.device_id)); 769 command_line->AppendSwitchASCII(switches::kGpuDriverVendor, 770 gpu_info_.driver_vendor); 771 command_line->AppendSwitchASCII(switches::kGpuDriverVersion, 772 gpu_info_.driver_version); 773 } 774 775 void GpuDataManagerImplPrivate::AppendPluginCommandLine( 776 CommandLine* command_line) const { 777 DCHECK(command_line); 778 779 #if defined(OS_MACOSX) 780 // TODO(jbauman): Add proper blacklist support for core animation plugins so 781 // special-casing this video card won't be necessary. See 782 // http://crbug.com/134015 783 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) || 784 CommandLine::ForCurrentProcess()->HasSwitch( 785 switches::kDisableAcceleratedCompositing)) { 786 if (!command_line->HasSwitch( 787 switches::kDisableCoreAnimationPlugins)) 788 command_line->AppendSwitch( 789 switches::kDisableCoreAnimationPlugins); 790 } 791 #endif 792 } 793 794 void GpuDataManagerImplPrivate::UpdateRendererWebPrefs( 795 WebPreferences* prefs) const { 796 DCHECK(prefs); 797 798 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING)) 799 prefs->accelerated_compositing_enabled = false; 800 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL)) 801 prefs->experimental_webgl_enabled = false; 802 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH3D)) 803 prefs->flash_3d_enabled = false; 804 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D)) { 805 prefs->flash_stage3d_enabled = false; 806 prefs->flash_stage3d_baseline_enabled = false; 807 } 808 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE)) 809 prefs->flash_stage3d_baseline_enabled = false; 810 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)) 811 prefs->accelerated_2d_canvas_enabled = false; 812 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_MULTISAMPLING) 813 || display_count_ > 1) 814 prefs->gl_multisampling_enabled = false; 815 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_3D_CSS)) { 816 prefs->accelerated_compositing_for_3d_transforms_enabled = false; 817 prefs->accelerated_compositing_for_animation_enabled = false; 818 } 819 if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO)) 820 prefs->accelerated_compositing_for_video_enabled = false; 821 822 // Accelerated video and animation are slower than regular when using 823 // SwiftShader. 3D CSS may also be too slow to be worthwhile. 824 if (ShouldUseSwiftShader()) { 825 prefs->accelerated_compositing_for_video_enabled = false; 826 prefs->accelerated_compositing_for_animation_enabled = false; 827 prefs->accelerated_compositing_for_3d_transforms_enabled = false; 828 prefs->accelerated_compositing_for_plugins_enabled = false; 829 } 830 831 if (use_software_compositor_) { 832 prefs->force_compositing_mode = true; 833 prefs->accelerated_compositing_enabled = true; 834 prefs->accelerated_compositing_for_3d_transforms_enabled = true; 835 prefs->accelerated_compositing_for_plugins_enabled = true; 836 } 837 838 #if defined(USE_AURA) 839 if (!CanUseGpuBrowserCompositor()) 840 prefs->accelerated_2d_canvas_enabled = false; 841 #endif 842 } 843 844 gpu::GpuSwitchingOption 845 GpuDataManagerImplPrivate::GetGpuSwitchingOption() const { 846 if (!ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) 847 return gpu::GPU_SWITCHING_OPTION_UNKNOWN; 848 return gpu_switching_; 849 } 850 851 void GpuDataManagerImplPrivate::DisableHardwareAcceleration() { 852 card_blacklisted_ = true; 853 854 for (int i = 0; i < gpu::NUMBER_OF_GPU_FEATURE_TYPES; ++i) 855 blacklisted_features_.insert(i); 856 857 EnableSwiftShaderIfNecessary(); 858 NotifyGpuInfoUpdate(); 859 } 860 861 std::string GpuDataManagerImplPrivate::GetBlacklistVersion() const { 862 if (gpu_blacklist_) 863 return gpu_blacklist_->version(); 864 return "0"; 865 } 866 867 std::string GpuDataManagerImplPrivate::GetDriverBugListVersion() const { 868 if (gpu_driver_bug_list_) 869 return gpu_driver_bug_list_->version(); 870 return "0"; 871 } 872 873 void GpuDataManagerImplPrivate::GetBlacklistReasons( 874 base::ListValue* reasons) const { 875 if (gpu_blacklist_) 876 gpu_blacklist_->GetReasons(reasons); 877 } 878 879 void GpuDataManagerImplPrivate::GetDriverBugWorkarounds( 880 base::ListValue* workarounds) const { 881 for (std::set<int>::const_iterator it = gpu_driver_bugs_.begin(); 882 it != gpu_driver_bugs_.end(); ++it) { 883 workarounds->AppendString( 884 gpu::GpuDriverBugWorkaroundTypeToString( 885 static_cast<gpu::GpuDriverBugWorkaroundType>(*it))); 886 } 887 } 888 889 void GpuDataManagerImplPrivate::AddLogMessage( 890 int level, const std::string& header, const std::string& message) { 891 base::DictionaryValue* dict = new base::DictionaryValue(); 892 dict->SetInteger("level", level); 893 dict->SetString("header", header); 894 dict->SetString("message", message); 895 log_messages_.Append(dict); 896 } 897 898 void GpuDataManagerImplPrivate::ProcessCrashed( 899 base::TerminationStatus exit_code) { 900 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 901 // Unretained is ok, because it's posted to UI thread, the thread 902 // where the singleton GpuDataManagerImpl lives until the end. 903 BrowserThread::PostTask( 904 BrowserThread::UI, 905 FROM_HERE, 906 base::Bind(&GpuDataManagerImpl::ProcessCrashed, 907 base::Unretained(owner_), 908 exit_code)); 909 return; 910 } 911 { 912 GpuDataManagerImpl::UnlockedSession session(owner_); 913 observer_list_->Notify( 914 &GpuDataManagerObserver::OnGpuProcessCrashed, exit_code); 915 } 916 } 917 918 base::ListValue* GpuDataManagerImplPrivate::GetLogMessages() const { 919 base::ListValue* value; 920 value = log_messages_.DeepCopy(); 921 return value; 922 } 923 924 void GpuDataManagerImplPrivate::HandleGpuSwitch() { 925 GpuDataManagerImpl::UnlockedSession session(owner_); 926 observer_list_->Notify(&GpuDataManagerObserver::OnGpuSwitching); 927 } 928 929 #if defined(OS_WIN) 930 bool GpuDataManagerImplPrivate::IsUsingAcceleratedSurface() const { 931 if (base::win::GetVersion() < base::win::VERSION_VISTA) 932 return false; 933 934 if (use_swiftshader_) 935 return false; 936 CommandLine* command_line = CommandLine::ForCurrentProcess(); 937 if (command_line->HasSwitch(switches::kDisableImageTransportSurface)) 938 return false; 939 return !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_TEXTURE_SHARING); 940 } 941 #endif 942 943 bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const { 944 return !ShouldUseSwiftShader() && 945 !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) && 946 !IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FORCE_COMPOSITING_MODE); 947 } 948 949 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIs( 950 const GURL& url, GpuDataManagerImpl::DomainGuilt guilt) { 951 BlockDomainFrom3DAPIsAtTime(url, guilt, base::Time::Now()); 952 } 953 954 bool GpuDataManagerImplPrivate::Are3DAPIsBlocked(const GURL& url, 955 int render_process_id, 956 int render_view_id, 957 ThreeDAPIType requester) { 958 bool blocked = Are3DAPIsBlockedAtTime(url, base::Time::Now()) != 959 GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED; 960 if (blocked) { 961 // Unretained is ok, because it's posted to UI thread, the thread 962 // where the singleton GpuDataManagerImpl lives until the end. 963 BrowserThread::PostTask( 964 BrowserThread::UI, FROM_HERE, 965 base::Bind(&GpuDataManagerImpl::Notify3DAPIBlocked, 966 base::Unretained(owner_), url, render_process_id, 967 render_view_id, requester)); 968 } 969 970 return blocked; 971 } 972 973 void GpuDataManagerImplPrivate::DisableDomainBlockingFor3DAPIsForTesting() { 974 domain_blocking_enabled_ = false; 975 } 976 977 // static 978 GpuDataManagerImplPrivate* GpuDataManagerImplPrivate::Create( 979 GpuDataManagerImpl* owner) { 980 return new GpuDataManagerImplPrivate(owner); 981 } 982 983 GpuDataManagerImplPrivate::GpuDataManagerImplPrivate( 984 GpuDataManagerImpl* owner) 985 : complete_gpu_info_already_requested_(false), 986 gpu_switching_(gpu::GPU_SWITCHING_OPTION_AUTOMATIC), 987 observer_list_(new GpuDataManagerObserverList), 988 use_swiftshader_(false), 989 card_blacklisted_(false), 990 update_histograms_(true), 991 window_count_(0), 992 domain_blocking_enabled_(true), 993 owner_(owner), 994 display_count_(0), 995 gpu_process_accessible_(true), 996 use_software_compositor_(false) { 997 DCHECK(owner_); 998 CommandLine* command_line = CommandLine::ForCurrentProcess(); 999 if (command_line->HasSwitch(switches::kDisableAcceleratedCompositing)) { 1000 command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas); 1001 command_line->AppendSwitch(switches::kDisableAcceleratedLayers); 1002 } 1003 if (command_line->HasSwitch(switches::kDisableGpu)) 1004 DisableHardwareAcceleration(); 1005 if (command_line->HasSwitch(switches::kEnableSoftwareCompositing)) 1006 use_software_compositor_ = true; 1007 //TODO(jbauman): enable for Chrome OS and Linux 1008 #if defined(USE_AURA) && defined(OS_WIN) 1009 use_software_compositor_ = true; 1010 #endif 1011 if (command_line->HasSwitch(switches::kGpuSwitching)) { 1012 std::string option_string = command_line->GetSwitchValueASCII( 1013 switches::kGpuSwitching); 1014 gpu::GpuSwitchingOption option = 1015 gpu::StringToGpuSwitchingOption(option_string); 1016 if (option != gpu::GPU_SWITCHING_OPTION_UNKNOWN) 1017 gpu_switching_ = option; 1018 } 1019 1020 #if defined(OS_MACOSX) 1021 CGGetActiveDisplayList (0, NULL, &display_count_); 1022 CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback, owner_); 1023 #endif // OS_MACOSX 1024 } 1025 1026 GpuDataManagerImplPrivate::~GpuDataManagerImplPrivate() { 1027 #if defined(OS_MACOSX) 1028 CGDisplayRemoveReconfigurationCallback(DisplayReconfigCallback, owner_); 1029 #endif 1030 } 1031 1032 void GpuDataManagerImplPrivate::InitializeImpl( 1033 const std::string& gpu_blacklist_json, 1034 const std::string& gpu_switching_list_json, 1035 const std::string& gpu_driver_bug_list_json, 1036 const gpu::GPUInfo& gpu_info) { 1037 std::string browser_version_string = ProcessVersionString( 1038 GetContentClient()->GetProduct()); 1039 CHECK(!browser_version_string.empty()); 1040 1041 if (!gpu_blacklist_json.empty()) { 1042 gpu_blacklist_.reset(gpu::GpuBlacklist::Create()); 1043 gpu_blacklist_->LoadList( 1044 browser_version_string, gpu_blacklist_json, 1045 gpu::GpuControlList::kCurrentOsOnly); 1046 } 1047 if (!gpu_switching_list_json.empty()) { 1048 gpu_switching_list_.reset(gpu::GpuSwitchingList::Create()); 1049 gpu_switching_list_->LoadList( 1050 browser_version_string, gpu_switching_list_json, 1051 gpu::GpuControlList::kCurrentOsOnly); 1052 } 1053 if (!gpu_driver_bug_list_json.empty()) { 1054 gpu_driver_bug_list_.reset(gpu::GpuDriverBugList::Create()); 1055 gpu_driver_bug_list_->LoadList( 1056 browser_version_string, gpu_driver_bug_list_json, 1057 gpu::GpuControlList::kCurrentOsOnly); 1058 } 1059 1060 gpu_info_ = gpu_info; 1061 UpdateGpuInfo(gpu_info); 1062 UpdateGpuSwitchingManager(gpu_info); 1063 UpdatePreliminaryBlacklistedFeatures(); 1064 1065 CommandLine* command_line = CommandLine::ForCurrentProcess(); 1066 // We pass down the list to GPU command buffer through commandline 1067 // switches at GPU process launch. However, in situations where we don't 1068 // have a GPU process, we append the browser process commandline. 1069 if (command_line->HasSwitch(switches::kSingleProcess) || 1070 command_line->HasSwitch(switches::kInProcessGPU)) { 1071 if (!gpu_driver_bugs_.empty()) { 1072 command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds, 1073 IntSetToString(gpu_driver_bugs_)); 1074 } 1075 } 1076 #if defined(OS_ANDROID) 1077 ApplyAndroidWorkarounds(gpu_info, command_line); 1078 #endif // OS_ANDROID 1079 } 1080 1081 void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures( 1082 const std::set<int>& features) { 1083 CommandLine* command_line = CommandLine::ForCurrentProcess(); 1084 blacklisted_features_ = features; 1085 1086 // Force disable using the GPU for these features, even if they would 1087 // otherwise be allowed. 1088 if (card_blacklisted_ || 1089 command_line->HasSwitch(switches::kBlacklistAcceleratedCompositing)) { 1090 blacklisted_features_.insert( 1091 gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING); 1092 } 1093 if (card_blacklisted_ || 1094 command_line->HasSwitch(switches::kBlacklistWebGL)) { 1095 blacklisted_features_.insert(gpu::GPU_FEATURE_TYPE_WEBGL); 1096 } 1097 1098 EnableSwiftShaderIfNecessary(); 1099 } 1100 1101 void GpuDataManagerImplPrivate::UpdatePreliminaryBlacklistedFeatures() { 1102 preliminary_blacklisted_features_ = blacklisted_features_; 1103 } 1104 1105 void GpuDataManagerImplPrivate::UpdateGpuSwitchingManager( 1106 const gpu::GPUInfo& gpu_info) { 1107 ui::GpuSwitchingManager::GetInstance()->SetGpuCount( 1108 gpu_info.secondary_gpus.size() + 1); 1109 1110 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) { 1111 switch (gpu_switching_) { 1112 case gpu::GPU_SWITCHING_OPTION_FORCE_DISCRETE: 1113 ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu(); 1114 break; 1115 case gpu::GPU_SWITCHING_OPTION_FORCE_INTEGRATED: 1116 ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu(); 1117 break; 1118 case gpu::GPU_SWITCHING_OPTION_AUTOMATIC: 1119 case gpu::GPU_SWITCHING_OPTION_UNKNOWN: 1120 break; 1121 } 1122 } 1123 } 1124 1125 void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() { 1126 observer_list_->Notify(&GpuDataManagerObserver::OnGpuInfoUpdate); 1127 } 1128 1129 void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() { 1130 if (!GpuAccessAllowed(NULL) || 1131 blacklisted_features_.count(gpu::GPU_FEATURE_TYPE_WEBGL)) { 1132 if (!swiftshader_path_.empty() && 1133 !CommandLine::ForCurrentProcess()->HasSwitch( 1134 switches::kDisableSoftwareRasterizer)) 1135 use_swiftshader_ = true; 1136 } 1137 } 1138 1139 std::string GpuDataManagerImplPrivate::GetDomainFromURL( 1140 const GURL& url) const { 1141 // For the moment, we just use the host, or its IP address, as the 1142 // entry in the set, rather than trying to figure out the top-level 1143 // domain. This does mean that a.foo.com and b.foo.com will be 1144 // treated independently in the blocking of a given domain, but it 1145 // would require a third-party library to reliably figure out the 1146 // top-level domain from a URL. 1147 if (!url.has_host()) { 1148 return std::string(); 1149 } 1150 1151 return url.host(); 1152 } 1153 1154 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIsAtTime( 1155 const GURL& url, 1156 GpuDataManagerImpl::DomainGuilt guilt, 1157 base::Time at_time) { 1158 if (!domain_blocking_enabled_) 1159 return; 1160 1161 std::string domain = GetDomainFromURL(url); 1162 1163 DomainBlockEntry& entry = blocked_domains_[domain]; 1164 entry.last_guilt = guilt; 1165 timestamps_of_gpu_resets_.push_back(at_time); 1166 } 1167 1168 GpuDataManagerImpl::DomainBlockStatus 1169 GpuDataManagerImplPrivate::Are3DAPIsBlockedAtTime( 1170 const GURL& url, base::Time at_time) const { 1171 if (!domain_blocking_enabled_) 1172 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED; 1173 1174 // Note: adjusting the policies in this code will almost certainly 1175 // require adjusting the associated unit tests. 1176 std::string domain = GetDomainFromURL(url); 1177 1178 DomainBlockMap::const_iterator iter = blocked_domains_.find(domain); 1179 if (iter != blocked_domains_.end()) { 1180 // Err on the side of caution, and assume that if a particular 1181 // domain shows up in the block map, it's there for a good 1182 // reason and don't let its presence there automatically expire. 1183 1184 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs", 1185 BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED, 1186 BLOCK_STATUS_MAX); 1187 1188 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED; 1189 } 1190 1191 // Look at the timestamps of the recent GPU resets to see if there are 1192 // enough within the threshold which would cause us to blacklist all 1193 // domains. This doesn't need to be overly precise -- if time goes 1194 // backward due to a system clock adjustment, that's fine. 1195 // 1196 // TODO(kbr): make this pay attention to the TDR thresholds in the 1197 // Windows registry, but make sure it continues to be testable. 1198 { 1199 std::list<base::Time>::iterator iter = timestamps_of_gpu_resets_.begin(); 1200 int num_resets_within_timeframe = 0; 1201 while (iter != timestamps_of_gpu_resets_.end()) { 1202 base::Time time = *iter; 1203 base::TimeDelta delta_t = at_time - time; 1204 1205 // If this entry has "expired", just remove it. 1206 if (delta_t.InMilliseconds() > kBlockAllDomainsMs) { 1207 iter = timestamps_of_gpu_resets_.erase(iter); 1208 continue; 1209 } 1210 1211 ++num_resets_within_timeframe; 1212 ++iter; 1213 } 1214 1215 if (num_resets_within_timeframe >= kNumResetsWithinDuration) { 1216 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs", 1217 BLOCK_STATUS_ALL_DOMAINS_BLOCKED, 1218 BLOCK_STATUS_MAX); 1219 1220 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED; 1221 } 1222 } 1223 1224 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs", 1225 BLOCK_STATUS_NOT_BLOCKED, 1226 BLOCK_STATUS_MAX); 1227 1228 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED; 1229 } 1230 1231 int64 GpuDataManagerImplPrivate::GetBlockAllDomainsDurationInMs() const { 1232 return kBlockAllDomainsMs; 1233 } 1234 1235 void GpuDataManagerImplPrivate::Notify3DAPIBlocked(const GURL& url, 1236 int render_process_id, 1237 int render_view_id, 1238 ThreeDAPIType requester) { 1239 GpuDataManagerImpl::UnlockedSession session(owner_); 1240 observer_list_->Notify(&GpuDataManagerObserver::DidBlock3DAPIs, 1241 url, render_process_id, render_view_id, requester); 1242 } 1243 1244 void GpuDataManagerImplPrivate::OnGpuProcessInitFailure() { 1245 gpu_process_accessible_ = false; 1246 gpu_info_.finalized = true; 1247 complete_gpu_info_already_requested_ = true; 1248 // Some observers might be waiting. 1249 NotifyGpuInfoUpdate(); 1250 } 1251 1252 } // namespace content 1253 1254