Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: content/browser/gpu/gpu_data_manager_impl_private.cc

Issue 14794006: Refactor GpuDataManagerImpl to make it thread-safe, now and forever. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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 #if defined(OS_MACOSX)
8 #include <ApplicationServices/ApplicationServices.h>
9 #endif // OS_MACOSX
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/command_line.h"
14 #include "base/debug/trace_event.h"
15 #include "base/file_util.h"
16 #include "base/metrics/field_trial.h"
17 #include "base/metrics/histogram.h"
18 #include "base/stringprintf.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_piece.h"
21 #include "base/sys_info.h"
22 #include "base/version.h"
23 #include "content/browser/gpu/gpu_process_host.h"
24 #include "content/browser/gpu/gpu_util.h"
25 #include "content/common/gpu/gpu_messages.h"
26 #include "content/gpu/gpu_info_collector.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/gpu_data_manager_observer.h"
29 #include "content/public/common/content_client.h"
30 #include "content/public/common/content_constants.h"
31 #include "content/public/common/content_switches.h"
32 #include "content/public/common/gpu_feature_type.h"
33 #include "gpu/command_buffer/service/gpu_switches.h"
34 #include "grit/content_resources.h"
35 #include "ui/base/ui_base_switches.h"
36 #include "ui/gl/gl_implementation.h"
37 #include "ui/gl/gl_switches.h"
38 #include "ui/gl/gpu_switching_manager.h"
39 #include "webkit/glue/webpreferences.h"
40 #include "webkit/plugins/plugin_switches.h"
41
42 #if defined(OS_WIN)
43 #include "base/win/windows_version.h"
44 #endif
45
46 namespace content {
47 namespace {
48
49 // Strip out the non-digital info; if after that, we get an empty string,
50 // return "0".
51 std::string ProcessVersionString(const std::string& raw_string) {
52 const std::string valid_set = "0123456789.";
53 size_t start_pos = raw_string.find_first_of(valid_set);
54 if (start_pos == std::string::npos)
55 return "0";
56 size_t end_pos = raw_string.find_first_not_of(raw_string, start_pos);
57 std::string version_string = raw_string.substr(
58 start_pos, end_pos - start_pos);
59 if (version_string.empty())
60 return "0";
61 return version_string;
62 }
63
64 // Combine the integers into a string, seperated by ','.
65 std::string IntSetToString(const std::set<int>& list) {
66 std::string rt;
67 for (std::set<int>::const_iterator it = list.begin();
68 it != list.end(); ++it) {
69 if (!rt.empty())
70 rt += ",";
71 rt += base::IntToString(*it);
72 }
73 return rt;
74 }
75
76 #if defined(OS_MACOSX)
77 void DisplayReconfigCallback(CGDirectDisplayID display,
78 CGDisplayChangeSummaryFlags flags,
79 void* gpu_data_manager) {
80 if (flags & kCGDisplayAddFlag) {
81 GpuDataManagerImpl* manager =
82 reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager);
83 DCHECK(manager);
84 manager->HandleGpuSwitch();
85 }
86 }
87 #endif // OS_MACOSX
88
89 // Block all domains' use of 3D APIs for this many milliseconds if
90 // approaching a threshold where system stability might be compromised.
91 const int64 kBlockAllDomainsMs = 10000;
92 const int kNumResetsWithinDuration = 1;
93
94 // Enums for UMA histograms.
95 enum BlockStatusHistogram {
96 BLOCK_STATUS_NOT_BLOCKED,
97 BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
98 BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
99 BLOCK_STATUS_MAX
100 };
101
102 } // namespace anonymous
103
104 void GpuDataManagerImplPrivate::InitializeForTesting(
105 const std::string& gpu_blacklist_json,
106 const GPUInfo& gpu_info) {
107 // This function is for testing only, so disable histograms.
108 update_histograms_ = false;
109
110 InitializeImpl(gpu_blacklist_json, std::string(), std::string(), gpu_info);
111 }
112
113 bool GpuDataManagerImplPrivate::IsFeatureBlacklisted(int feature) const {
114 if (use_swiftshader_) {
115 // Skia's software rendering is probably more efficient than going through
116 // software emulation of the GPU, so use that.
117 if (feature == GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)
118 return true;
119 return false;
120 }
121
122 return (blacklisted_features_.count(feature) == 1);
123 }
124
125 size_t GpuDataManagerImplPrivate::GetBlacklistedFeatureCount() const {
126 if (use_swiftshader_)
127 return 1;
128 return blacklisted_features_.size();
129 }
130
131 void GpuDataManagerImplPrivate::AddGpuSwitchCallback(
132 const GpuSwitchCallback& callback) {
133 gpu_switch_callbacks_.push_back(callback);
134 }
135
136 void GpuDataManagerImplPrivate::RemoveGpuSwitchCallback(
137 const GpuSwitchCallback& callback) {
138 for (size_t i = 0; i < gpu_switch_callbacks_.size(); i++) {
139 if (gpu_switch_callbacks_[i].Equals(callback)) {
140 gpu_switch_callbacks_.erase(gpu_switch_callbacks_.begin() + i);
141 return;
142 }
143 }
144 }
145
146 GPUInfo GpuDataManagerImplPrivate::GetGPUInfo() const {
147 return gpu_info_;
148 }
149
150 void GpuDataManagerImplPrivate::GetGpuProcessHandles(
151 const GpuDataManager::GetGpuProcessHandlesCallback& callback) const {
152 GpuProcessHost::GetProcessHandles(callback);
153 }
154
155 bool GpuDataManagerImplPrivate::GpuAccessAllowed(
156 std::string* reason) const {
157 if (use_swiftshader_)
158 return true;
159
160 if (!gpu_info_.gpu_accessible) {
161 if (reason) {
162 *reason = "GPU process launch failed.";
163 }
164 return false;
165 }
166
167 if (card_blacklisted_) {
168 if (reason) {
169 *reason = "GPU access is disabled ";
170 CommandLine* command_line = CommandLine::ForCurrentProcess();
171 if (command_line->HasSwitch(switches::kDisableGpu))
172 *reason += "through commandline switch --disable-gpu.";
173 else
174 *reason += "in chrome://settings.";
175 }
176 return false;
177 }
178
179 // We only need to block GPU process if more features are disallowed other
180 // than those in the preliminary gpu feature flags because the latter work
181 // through renderer commandline switches.
182 std::set<int> features = preliminary_blacklisted_features_;
183 MergeFeatureSets(&features, blacklisted_features_);
184 if (features.size() > preliminary_blacklisted_features_.size()) {
185 if (reason) {
186 *reason = "Features are disabled upon full but not preliminary GPU info.";
187 }
188 return false;
189 }
190
191 if (blacklisted_features_.size() == NUMBER_OF_GPU_FEATURE_TYPES) {
192 // On Linux, we use cached GL strings to make blacklist decsions at browser
193 // startup time. We need to launch the GPU process to validate these
194 // strings even if all features are blacklisted. If all GPU features are
195 // disabled, the GPU process will only initialize GL bindings, create a GL
196 // context, and collect full GPU info.
197 #if !defined(OS_LINUX)
198 if (reason) {
199 *reason = "All GPU features are blacklisted.";
200 }
201 return false;
202 #endif
203 }
204
205 return true;
206 }
207
208 void GpuDataManagerImplPrivate::RequestCompleteGpuInfoIfNeeded() {
209 if (complete_gpu_info_already_requested_ || gpu_info_.finalized)
210 return;
211 complete_gpu_info_already_requested_ = true;
212
213 GpuProcessHost::SendOnIO(
214 #if defined(OS_WIN)
215 GpuProcessHost::GPU_PROCESS_KIND_UNSANDBOXED,
216 #else
217 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
218 #endif
219 CAUSE_FOR_GPU_LAUNCH_GPUDATAMANAGER_REQUESTCOMPLETEGPUINFOIFNEEDED,
220 new GpuMsg_CollectGraphicsInfo());
221 }
222
223 bool GpuDataManagerImplPrivate::IsCompleteGpuInfoAvailable() const {
224 return gpu_info_.finalized;
225 }
226
227 void GpuDataManagerImplPrivate::RequestVideoMemoryUsageStatsUpdate() const {
228 GpuProcessHost::SendOnIO(
229 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
230 CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
231 new GpuMsg_GetVideoMemoryUsageStats());
232 }
233
234 bool GpuDataManagerImplPrivate::ShouldUseSwiftShader() const {
235 return use_swiftshader_;
236 }
237
238 void GpuDataManagerImplPrivate::RegisterSwiftShaderPath(
239 const base::FilePath& path) {
240 swiftshader_path_ = path;
241 EnableSwiftShaderIfNecessary();
242 }
243
244 void GpuDataManagerImplPrivate::AddObserver(GpuDataManagerObserver* observer) {
245 observer_list_->AddObserver(observer);
246 }
247
248 void GpuDataManagerImplPrivate::RemoveObserver(
249 GpuDataManagerObserver* observer) {
250 observer_list_->RemoveObserver(observer);
251 }
252
253 void GpuDataManagerImplPrivate::UnblockDomainFrom3DAPIs(const GURL& url) {
254 // This method must do two things:
255 //
256 // 1. If the specific domain is blocked, then unblock it.
257 //
258 // 2. Reset our notion of how many GPU resets have occurred recently.
259 // This is necessary even if the specific domain was blocked.
260 // Otherwise, if we call Are3DAPIsBlocked with the same domain right
261 // after unblocking it, it will probably still be blocked because of
262 // the recent GPU reset caused by that domain.
263 //
264 // These policies could be refined, but at a certain point the behavior
265 // will become difficult to explain.
266 std::string domain = GetDomainFromURL(url);
267
268 blocked_domains_.erase(domain);
269 timestamps_of_gpu_resets_.clear();
270 }
271
272 void GpuDataManagerImplPrivate::DisableGpuWatchdog() {
273 GpuProcessHost::SendOnIO(
274 GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
275 CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
276 new GpuMsg_DisableWatchdog);
277 }
278
279 void GpuDataManagerImplPrivate::SetGLStrings(const std::string& gl_vendor,
280 const std::string& gl_renderer,
281 const std::string& gl_version) {
282 if (gl_vendor.empty() && gl_renderer.empty() && gl_version.empty())
283 return;
284
285 // If GPUInfo already got GL strings, do nothing. This is for the rare
286 // situation where GPU process collected GL strings before this call.
287 if (!gpu_info_.gl_vendor.empty() ||
288 !gpu_info_.gl_renderer.empty() ||
289 !gpu_info_.gl_version_string.empty())
290 return;
291
292 GPUInfo gpu_info = gpu_info_;
293
294 gpu_info.gl_vendor = gl_vendor;
295 gpu_info.gl_renderer = gl_renderer;
296 gpu_info.gl_version_string = gl_version;
297
298 gpu_info_collector::CollectDriverInfoGL(&gpu_info);
299
300 UpdateGpuInfo(gpu_info);
301 UpdateGpuSwitchingManager(gpu_info);
302 UpdatePreliminaryBlacklistedFeatures();
303 }
304
305 void GpuDataManagerImplPrivate::GetGLStrings(std::string* gl_vendor,
306 std::string* gl_renderer,
307 std::string* gl_version) {
308 DCHECK(gl_vendor && gl_renderer && gl_version);
309
310 *gl_vendor = gpu_info_.gl_vendor;
311 *gl_renderer = gpu_info_.gl_renderer;
312 *gl_version = gpu_info_.gl_version_string;
313 }
314
315 void GpuDataManagerImplPrivate::Initialize() {
316 TRACE_EVENT0("startup", "GpuDataManagerImpl::Initialize");
317 CommandLine* command_line = CommandLine::ForCurrentProcess();
318 if (command_line->HasSwitch(switches::kSkipGpuDataLoading))
319 return;
320
321 GPUInfo gpu_info;
322 {
323 TRACE_EVENT0("startup",
324 "GpuDataManagerImpl::Initialize:CollectBasicGraphicsInfo");
325 gpu_info_collector::CollectBasicGraphicsInfo(&gpu_info);
326 }
327 #if defined(ARCH_CPU_X86_FAMILY)
328 if (!gpu_info.gpu.vendor_id || !gpu_info.gpu.device_id)
329 gpu_info.finalized = true;
330 #endif
331
332 std::string gpu_blacklist_string;
333 std::string gpu_switching_list_string;
334 std::string gpu_driver_bug_list_string;
335 if (!command_line->HasSwitch(switches::kIgnoreGpuBlacklist)) {
336 const base::StringPiece gpu_blacklist_json =
337 GetContentClient()->GetDataResource(
338 IDR_GPU_BLACKLIST, ui::SCALE_FACTOR_NONE);
339 gpu_blacklist_string = gpu_blacklist_json.as_string();
340 const base::StringPiece gpu_switching_list_json =
341 GetContentClient()->GetDataResource(
342 IDR_GPU_SWITCHING_LIST, ui::SCALE_FACTOR_NONE);
343 gpu_switching_list_string = gpu_switching_list_json.as_string();
344 }
345 if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
346 const base::StringPiece gpu_driver_bug_list_json =
347 GetContentClient()->GetDataResource(
348 IDR_GPU_DRIVER_BUG_LIST, ui::SCALE_FACTOR_NONE);
349 gpu_driver_bug_list_string = gpu_driver_bug_list_json.as_string();
350 }
351 InitializeImpl(gpu_blacklist_string,
352 gpu_switching_list_string,
353 gpu_driver_bug_list_string,
354 gpu_info);
355 // We pass down the list to GPU command buffer through commandline
356 // switches at GPU process launch. However, in situations where we don't
357 // have a GPU process, we append the browser process commandline.
358 if (command_line->HasSwitch(switches::kSingleProcess) ||
359 command_line->HasSwitch(switches::kInProcessGPU)) {
360 if (!gpu_driver_bugs_.empty()) {
361 command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
362 IntSetToString(gpu_driver_bugs_));
363 }
364 }
365 }
366
367 void GpuDataManagerImplPrivate::UpdateGpuInfo(const GPUInfo& gpu_info) {
368 // No further update of gpu_info if falling back to SwiftShader.
369 if (use_swiftshader_)
370 return;
371
372 gpu_info_collector::MergeGPUInfo(&gpu_info_, gpu_info);
373 complete_gpu_info_already_requested_ =
374 complete_gpu_info_already_requested_ || gpu_info_.finalized;
375
376 GetContentClient()->SetGpuInfo(gpu_info_);
377
378 if (gpu_blacklist_) {
379 std::set<int> features = gpu_blacklist_->MakeDecision(
380 GpuControlList::kOsAny, std::string(), gpu_info_);
381 if (update_histograms_)
382 UpdateStats(gpu_blacklist_.get(), features);
383
384 UpdateBlacklistedFeatures(features);
385 }
386 if (gpu_switching_list_) {
387 std::set<int> option = gpu_switching_list_->MakeDecision(
388 GpuControlList::kOsAny, std::string(), gpu_info_);
389 if (option.size() == 1) {
390 // Blacklist decision should not overwrite commandline switch from users.
391 CommandLine* command_line = CommandLine::ForCurrentProcess();
392 if (!command_line->HasSwitch(switches::kGpuSwitching))
393 gpu_switching_ = static_cast<GpuSwitchingOption>(*(option.begin()));
394 }
395 }
396 if (gpu_driver_bug_list_)
397 gpu_driver_bugs_ = gpu_driver_bug_list_->MakeDecision(
398 GpuControlList::kOsAny, std::string(), gpu_info_);
399
400 // We have to update GpuFeatureType before notify all the observers.
401 NotifyGpuInfoUpdate();
402 }
403
404 void GpuDataManagerImplPrivate::UpdateVideoMemoryUsageStats(
405 const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
406 observer_list_->Notify(&GpuDataManagerObserver::OnVideoMemoryUsageStatsUpdate,
407 video_memory_usage_stats);
408 }
409
410 void GpuDataManagerImplPrivate::AppendRendererCommandLine(
411 CommandLine* command_line) const {
412 DCHECK(command_line);
413
414 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL)) {
415 #if !defined(OS_ANDROID)
416 if (!command_line->HasSwitch(switches::kDisableExperimentalWebGL))
417 command_line->AppendSwitch(switches::kDisableExperimentalWebGL);
418 #endif
419 if (!command_line->HasSwitch(switches::kDisablePepper3d))
420 command_line->AppendSwitch(switches::kDisablePepper3d);
421 }
422 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_MULTISAMPLING) &&
423 !command_line->HasSwitch(switches::kDisableGLMultisampling))
424 command_line->AppendSwitch(switches::kDisableGLMultisampling);
425 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) &&
426 !command_line->HasSwitch(switches::kDisableAcceleratedCompositing))
427 command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
428 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS) &&
429 !command_line->HasSwitch(switches::kDisableAccelerated2dCanvas))
430 command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
431 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
432 !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
433 command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
434 if (ShouldUseSwiftShader())
435 command_line->AppendSwitch(switches::kDisableFlashFullscreen3d);
436 }
437
438 void GpuDataManagerImplPrivate::AppendGpuCommandLine(
439 CommandLine* command_line) const {
440 DCHECK(command_line);
441
442 std::string use_gl =
443 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL);
444 base::FilePath swiftshader_path =
445 CommandLine::ForCurrentProcess()->GetSwitchValuePath(
446 switches::kSwiftShaderPath);
447 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_MULTISAMPLING) &&
448 !command_line->HasSwitch(switches::kDisableGLMultisampling))
449 command_line->AppendSwitch(switches::kDisableGLMultisampling);
450 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_TEXTURE_SHARING))
451 command_line->AppendSwitch(switches::kDisableImageTransportSurface);
452
453 if (use_swiftshader_) {
454 command_line->AppendSwitchASCII(switches::kUseGL, "swiftshader");
455 if (swiftshader_path.empty())
456 swiftshader_path = swiftshader_path_;
457 } else if ((IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL) ||
458 IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
459 IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)) &&
460 (use_gl == "any")) {
461 command_line->AppendSwitchASCII(
462 switches::kUseGL, gfx::kGLImplementationOSMesaName);
463 } else if (!use_gl.empty()) {
464 command_line->AppendSwitchASCII(switches::kUseGL, use_gl);
465 }
466 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
467 command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "true");
468 switch (gpu_switching_) {
469 case GPU_SWITCHING_OPTION_FORCE_DISCRETE:
470 command_line->AppendSwitchASCII(switches::kGpuSwitching,
471 switches::kGpuSwitchingOptionNameForceDiscrete);
472 break;
473 case GPU_SWITCHING_OPTION_FORCE_INTEGRATED:
474 command_line->AppendSwitchASCII(switches::kGpuSwitching,
475 switches::kGpuSwitchingOptionNameForceIntegrated);
476 break;
477 case GPU_SWITCHING_OPTION_AUTOMATIC:
478 case GPU_SWITCHING_OPTION_UNKNOWN:
479 break;
480 }
481 } else {
482 command_line->AppendSwitchASCII(switches::kSupportsDualGpus, "false");
483 }
484
485 if (!swiftshader_path.empty())
486 command_line->AppendSwitchPath(switches::kSwiftShaderPath,
487 swiftshader_path);
488
489 if (!gpu_driver_bugs_.empty()) {
490 command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
491 IntSetToString(gpu_driver_bugs_));
492 }
493
494 #if defined(OS_WIN)
495 // DisplayLink 7.1 and earlier can cause the GPU process to crash on startup.
496 // http://crbug.com/177611
497 // Thinkpad USB Port Replicator driver causes GPU process to crash when the
498 // sandbox is enabled. http://crbug.com/181665.
499 if ((gpu_info_.display_link_version.IsValid()
500 && gpu_info_.display_link_version.IsOlderThan("7.2")) ||
501 gpu_info_.lenovo_dcute) {
502 command_line->AppendSwitch(switches::kReduceGpuSandbox);
503 }
504 #endif
505
506 if (gpu_info_.optimus)
507 command_line->AppendSwitch(switches::kReduceGpuSandbox);
508 if (gpu_info_.amd_switchable) {
509 // The image transport surface currently doesn't work with AMD Dynamic
510 // Switchable graphics.
511 command_line->AppendSwitch(switches::kReduceGpuSandbox);
512 command_line->AppendSwitch(switches::kDisableImageTransportSurface);
513 }
514 // Pass GPU and driver information to GPU process. We try to avoid full GPU
515 // info collection at GPU process startup, but we need gpu vendor_id,
516 // device_id, driver_vendor, driver_version for deciding whether we need to
517 // collect full info (on Linux) and for crash reporting purpose.
518 command_line->AppendSwitchASCII(switches::kGpuVendorID,
519 base::StringPrintf("0x%04x", gpu_info_.gpu.vendor_id));
520 command_line->AppendSwitchASCII(switches::kGpuDeviceID,
521 base::StringPrintf("0x%04x", gpu_info_.gpu.device_id));
522 command_line->AppendSwitchASCII(switches::kGpuDriverVendor,
523 gpu_info_.driver_vendor);
524 command_line->AppendSwitchASCII(switches::kGpuDriverVersion,
525 gpu_info_.driver_version);
526 }
527
528 void GpuDataManagerImplPrivate::AppendPluginCommandLine(
529 CommandLine* command_line) const {
530 DCHECK(command_line);
531
532 #if defined(OS_MACOSX)
533 // TODO(jbauman): Add proper blacklist support for core animation plugins so
534 // special-casing this video card won't be necessary. See
535 // http://crbug.com/134015
536 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
537 CommandLine::ForCurrentProcess()->HasSwitch(
538 switches::kDisableAcceleratedCompositing)) {
539 if (!command_line->HasSwitch(
540 switches::kDisableCoreAnimationPlugins))
541 command_line->AppendSwitch(
542 switches::kDisableCoreAnimationPlugins);
543 }
544 #endif
545 }
546
547 void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
548 WebPreferences* prefs) const {
549 DCHECK(prefs);
550
551 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING))
552 prefs->accelerated_compositing_enabled = false;
553 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_WEBGL))
554 prefs->experimental_webgl_enabled = false;
555 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_FLASH3D))
556 prefs->flash_3d_enabled = false;
557 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_FLASH_STAGE3D)) {
558 prefs->flash_stage3d_enabled = false;
559 prefs->flash_stage3d_baseline_enabled = false;
560 }
561 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE))
562 prefs->flash_stage3d_baseline_enabled = false;
563 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS))
564 prefs->accelerated_2d_canvas_enabled = false;
565 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_MULTISAMPLING))
566 prefs->gl_multisampling_enabled = false;
567 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_3D_CSS)) {
568 prefs->accelerated_compositing_for_3d_transforms_enabled = false;
569 prefs->accelerated_compositing_for_animation_enabled = false;
570 }
571 if (IsFeatureBlacklisted(GPU_FEATURE_TYPE_ACCELERATED_VIDEO))
572 prefs->accelerated_compositing_for_video_enabled = false;
573
574 // Accelerated video and animation are slower than regular when using
575 // SwiftShader. 3D CSS may also be too slow to be worthwhile.
576 if (ShouldUseSwiftShader()) {
577 prefs->accelerated_compositing_for_video_enabled = false;
578 prefs->accelerated_compositing_for_animation_enabled = false;
579 prefs->accelerated_compositing_for_3d_transforms_enabled = false;
580 prefs->accelerated_compositing_for_plugins_enabled = false;
581 }
582 }
583
584 GpuSwitchingOption GpuDataManagerImplPrivate::GetGpuSwitchingOption() const {
585 if (!ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus())
586 return GPU_SWITCHING_OPTION_UNKNOWN;
587 return gpu_switching_;
588 }
589
590 void GpuDataManagerImplPrivate::DisableHardwareAcceleration() {
591 card_blacklisted_ = true;
592
593 for (int i = 0; i < NUMBER_OF_GPU_FEATURE_TYPES; ++i)
594 blacklisted_features_.insert(i);
595
596 EnableSwiftShaderIfNecessary();
597 NotifyGpuInfoUpdate();
598 }
599
600 std::string GpuDataManagerImplPrivate::GetBlacklistVersion() const {
601 if (gpu_blacklist_)
602 return gpu_blacklist_->version();
603 return "0";
604 }
605
606 base::ListValue* GpuDataManagerImplPrivate::GetBlacklistReasons() const {
607 ListValue* reasons = new ListValue();
608 if (gpu_blacklist_)
609 gpu_blacklist_->GetReasons(reasons);
610 return reasons;
611 }
612
613 void GpuDataManagerImplPrivate::AddLogMessage(
614 int level, const std::string& header, const std::string& message) {
615 DictionaryValue* dict = new DictionaryValue();
616 dict->SetInteger("level", level);
617 dict->SetString("header", header);
618 dict->SetString("message", message);
619 log_messages_.Append(dict);
620 }
621
622 void GpuDataManagerImplPrivate::ProcessCrashed(
623 base::TerminationStatus exit_code) {
624 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
625 // This is ok, because observer_list_ is thread-safe, thus
626 // ProcessCrashed is thread-safe.
627 BrowserThread::PostTask(
628 BrowserThread::UI,
629 FROM_HERE,
630 base::Bind(&GpuDataManagerImplPrivate::ProcessCrashed,
631 base::Unretained(this),
632 exit_code));
633 return;
634 }
635 observer_list_->Notify(&GpuDataManagerObserver::OnGpuProcessCrashed,
636 exit_code);
637 }
638
639 base::ListValue* GpuDataManagerImplPrivate::GetLogMessages() const {
640 base::ListValue* value;
641 value = log_messages_.DeepCopy();
642 return value;
643 }
644
645 void GpuDataManagerImplPrivate::HandleGpuSwitch() {
646 complete_gpu_info_already_requested_ = false;
647 gpu_info_.finalized = false;
648 for (size_t i = 0; i < gpu_switch_callbacks_.size(); ++i)
649 gpu_switch_callbacks_[i].Run();
650 }
651
652 #if defined(OS_WIN)
653 bool GpuDataManagerImplPrivate::IsUsingAcceleratedSurface() const {
654 if (base::win::GetVersion() < base::win::VERSION_VISTA)
655 return false;
656
657 if (gpu_info_.amd_switchable)
658 return false;
659 if (use_swiftshader_)
660 return false;
661 CommandLine* command_line = CommandLine::ForCurrentProcess();
662 if (command_line->HasSwitch(switches::kDisableImageTransportSurface))
663 return false;
664 return !IsFeatureBlacklisted(GPU_FEATURE_TYPE_TEXTURE_SHARING);
665 }
666 #endif
667
668 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIs(
669 const GURL& url, GpuDataManagerImpl::DomainGuilt guilt) {
670 BlockDomainFrom3DAPIsAtTime(url, guilt, base::Time::Now());
671 }
672
673 bool GpuDataManagerImplPrivate::Are3DAPIsBlocked(const GURL& url,
674 int render_process_id,
675 int render_view_id,
676 ThreeDAPIType requester) {
677 bool blocked = Are3DAPIsBlockedAtTime(url, base::Time::Now()) !=
678 GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
679 if (blocked) {
680 // This is ok, because observer_list_ is thread-safe, thus
681 // Notify3DAPIBlocked is thread-safe.
682 BrowserThread::PostTask(
683 BrowserThread::UI, FROM_HERE,
684 base::Bind(&GpuDataManagerImplPrivate::Notify3DAPIBlocked,
685 base::Unretained(this), url, render_process_id,
686 render_view_id, requester));
687 }
688
689 return blocked;
690 }
691
692 void GpuDataManagerImplPrivate::DisableDomainBlockingFor3DAPIsForTesting() {
693 domain_blocking_enabled_ = false;
694 }
695
696 GpuDataManagerImplPrivate::GpuDataManagerImplPrivate()
697 : complete_gpu_info_already_requested_(false),
698 gpu_switching_(GPU_SWITCHING_OPTION_AUTOMATIC),
699 observer_list_(new GpuDataManagerObserverList),
700 use_swiftshader_(false),
701 card_blacklisted_(false),
702 update_histograms_(true),
703 window_count_(0),
704 domain_blocking_enabled_(true) {
705 CommandLine* command_line = CommandLine::ForCurrentProcess();
706 if (command_line->HasSwitch(switches::kDisableAcceleratedCompositing)) {
707 command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
708 command_line->AppendSwitch(switches::kDisableAcceleratedLayers);
709 }
710 if (command_line->HasSwitch(switches::kDisableGpu))
711 DisableHardwareAcceleration();
712 if (command_line->HasSwitch(switches::kGpuSwitching)) {
713 std::string option_string = command_line->GetSwitchValueASCII(
714 switches::kGpuSwitching);
715 GpuSwitchingOption option = StringToGpuSwitchingOption(option_string);
716 if (option != GPU_SWITCHING_OPTION_UNKNOWN)
717 gpu_switching_ = option;
718 }
719
720 #if defined(OS_MACOSX)
721 CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback, this);
722 #endif // OS_MACOSX
723 }
724
725 GpuDataManagerImplPrivate::~GpuDataManagerImplPrivate() {
726 #if defined(OS_MACOSX)
727 CGDisplayRemoveReconfigurationCallback(DisplayReconfigCallback, this);
728 #endif
729 }
730
731 void GpuDataManagerImplPrivate::InitializeImpl(
732 const std::string& gpu_blacklist_json,
733 const std::string& gpu_switching_list_json,
734 const std::string& gpu_driver_bug_list_json,
735 const GPUInfo& gpu_info) {
736 std::string browser_version_string = ProcessVersionString(
737 GetContentClient()->GetProduct());
738 CHECK(!browser_version_string.empty());
739
740 if (!gpu_blacklist_json.empty()) {
741 gpu_blacklist_.reset(GpuBlacklist::Create());
742 gpu_blacklist_->LoadList(
743 browser_version_string, gpu_blacklist_json,
744 GpuControlList::kCurrentOsOnly);
745 }
746 if (!gpu_switching_list_json.empty()) {
747 gpu_switching_list_.reset(GpuSwitchingList::Create());
748 gpu_switching_list_->LoadList(
749 browser_version_string, gpu_switching_list_json,
750 GpuControlList::kCurrentOsOnly);
751 }
752 if (!gpu_driver_bug_list_json.empty()) {
753 gpu_driver_bug_list_.reset(GpuDriverBugList::Create());
754 gpu_driver_bug_list_->LoadList(
755 browser_version_string, gpu_driver_bug_list_json,
756 GpuControlList::kCurrentOsOnly);
757 }
758
759 gpu_info_ = gpu_info;
760 UpdateGpuInfo(gpu_info);
761 UpdateGpuSwitchingManager(gpu_info);
762 UpdatePreliminaryBlacklistedFeatures();
763 }
764
765 void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures(
766 const std::set<int>& features) {
767 CommandLine* command_line = CommandLine::ForCurrentProcess();
768 blacklisted_features_ = features;
769
770 // Force disable using the GPU for these features, even if they would
771 // otherwise be allowed.
772 if (card_blacklisted_ ||
773 command_line->HasSwitch(switches::kBlacklistAcceleratedCompositing)) {
774 blacklisted_features_.insert(GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING);
775 }
776 if (card_blacklisted_ ||
777 command_line->HasSwitch(switches::kBlacklistWebGL)) {
778 blacklisted_features_.insert(GPU_FEATURE_TYPE_WEBGL);
779 }
780
781 EnableSwiftShaderIfNecessary();
782 }
783
784 void GpuDataManagerImplPrivate::UpdatePreliminaryBlacklistedFeatures() {
785 preliminary_blacklisted_features_ = blacklisted_features_;
786 }
787
788 void GpuDataManagerImplPrivate::UpdateGpuSwitchingManager(
789 const GPUInfo& gpu_info) {
790 ui::GpuSwitchingManager::GetInstance()->SetGpuCount(
791 gpu_info.secondary_gpus.size() + 1);
792
793 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
794 switch (gpu_switching_) {
795 case GPU_SWITCHING_OPTION_FORCE_DISCRETE:
796 ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu();
797 break;
798 case GPU_SWITCHING_OPTION_FORCE_INTEGRATED:
799 ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu();
800 break;
801 case GPU_SWITCHING_OPTION_AUTOMATIC:
802 case GPU_SWITCHING_OPTION_UNKNOWN:
803 break;
804 }
805 }
806 }
807
808 void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() {
809 observer_list_->Notify(&GpuDataManagerObserver::OnGpuInfoUpdate);
810 }
811
812 void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() {
813 if (!GpuAccessAllowed(NULL) ||
814 blacklisted_features_.count(GPU_FEATURE_TYPE_WEBGL)) {
815 if (!swiftshader_path_.empty() &&
816 !CommandLine::ForCurrentProcess()->HasSwitch(
817 switches::kDisableSoftwareRasterizer))
818 use_swiftshader_ = true;
819 }
820 }
821
822 std::string GpuDataManagerImplPrivate::GetDomainFromURL(
823 const GURL& url) const {
824 // For the moment, we just use the host, or its IP address, as the
825 // entry in the set, rather than trying to figure out the top-level
826 // domain. This does mean that a.foo.com and b.foo.com will be
827 // treated independently in the blocking of a given domain, but it
828 // would require a third-party library to reliably figure out the
829 // top-level domain from a URL.
830 if (!url.has_host()) {
831 return std::string();
832 }
833
834 return url.host();
835 }
836
837 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIsAtTime(
838 const GURL& url,
839 GpuDataManagerImpl::DomainGuilt guilt,
840 base::Time at_time) {
841 if (!domain_blocking_enabled_)
842 return;
843
844 std::string domain = GetDomainFromURL(url);
845
846 DomainBlockEntry& entry = blocked_domains_[domain];
847 entry.last_guilt = guilt;
848 timestamps_of_gpu_resets_.push_back(at_time);
849 }
850
851 GpuDataManagerImpl::DomainBlockStatus
852 GpuDataManagerImplPrivate::Are3DAPIsBlockedAtTime(
853 const GURL& url, base::Time at_time) const {
854 if (!domain_blocking_enabled_)
855 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
856
857 // Note: adjusting the policies in this code will almost certainly
858 // require adjusting the associated unit tests.
859 std::string domain = GetDomainFromURL(url);
860
861 DomainBlockMap::const_iterator iter = blocked_domains_.find(domain);
862 if (iter != blocked_domains_.end()) {
863 // Err on the side of caution, and assume that if a particular
864 // domain shows up in the block map, it's there for a good
865 // reason and don't let its presence there automatically expire.
866
867 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
868 BLOCK_STATUS_SPECIFIC_DOMAIN_BLOCKED,
869 BLOCK_STATUS_MAX);
870
871 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_BLOCKED;
872 }
873
874 // Look at the timestamps of the recent GPU resets to see if there are
875 // enough within the threshold which would cause us to blacklist all
876 // domains. This doesn't need to be overly precise -- if time goes
877 // backward due to a system clock adjustment, that's fine.
878 //
879 // TODO(kbr): make this pay attention to the TDR thresholds in the
880 // Windows registry, but make sure it continues to be testable.
881 {
882 std::list<base::Time>::iterator iter = timestamps_of_gpu_resets_.begin();
883 int num_resets_within_timeframe = 0;
884 while (iter != timestamps_of_gpu_resets_.end()) {
885 base::Time time = *iter;
886 base::TimeDelta delta_t = at_time - time;
887
888 // If this entry has "expired", just remove it.
889 if (delta_t.InMilliseconds() > kBlockAllDomainsMs) {
890 iter = timestamps_of_gpu_resets_.erase(iter);
891 continue;
892 }
893
894 ++num_resets_within_timeframe;
895 ++iter;
896 }
897
898 if (num_resets_within_timeframe >= kNumResetsWithinDuration) {
899 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
900 BLOCK_STATUS_ALL_DOMAINS_BLOCKED,
901 BLOCK_STATUS_MAX);
902
903 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_ALL_DOMAINS_BLOCKED;
904 }
905 }
906
907 UMA_HISTOGRAM_ENUMERATION("GPU.BlockStatusForClient3DAPIs",
908 BLOCK_STATUS_NOT_BLOCKED,
909 BLOCK_STATUS_MAX);
910
911 return GpuDataManagerImpl::DOMAIN_BLOCK_STATUS_NOT_BLOCKED;
912 }
913
914 int64 GpuDataManagerImplPrivate::GetBlockAllDomainsDurationInMs() const {
915 return kBlockAllDomainsMs;
916 }
917
918 void GpuDataManagerImplPrivate::Notify3DAPIBlocked(const GURL& url,
919 int render_process_id,
920 int render_view_id,
921 ThreeDAPIType requester) {
922 observer_list_->Notify(&GpuDataManagerObserver::DidBlock3DAPIs,
923 url, render_process_id, render_view_id, requester);
924 }
925
926 } // namespace content
927
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698