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

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

Powered by Google App Engine
This is Rietveld 408576698