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

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

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

Powered by Google App Engine
This is Rietveld 408576698