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