1 // Copyright (c) 2011 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 "chrome/browser/gpu_data_manager.h"
6
7 #include "base/command_line.h"
8 #include "base/metrics/histogram.h"
9 #include "base/string_number_conversions.h"
10 #include "chrome/common/child_process_logging.h"
11 #include "chrome/common/chrome_switches.h"
12 #include "content/browser/browser_thread.h"
13 #include "content/browser/gpu_blacklist.h"
14 #include "content/browser/gpu_process_host.h"
15 #include "content/common/gpu_messages.h"
16 #include "content/gpu/gpu_info_collector.h"
17 #include "ui/gfx/gl/gl_implementation.h"
18 #include "ui/gfx/gl/gl_switches.h"
19
GpuDataManager()20 GpuDataManager::GpuDataManager()
21 : complete_gpu_info_already_requested_(false) {
22 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
23
24 GPUInfo gpu_info;
25 gpu_info_collector::CollectPreliminaryGraphicsInfo(&gpu_info);
26 UpdateGpuInfo(gpu_info);
27 }
28
~GpuDataManager()29 GpuDataManager::~GpuDataManager() { }
30
GetInstance()31 GpuDataManager* GpuDataManager::GetInstance() {
32 return Singleton<GpuDataManager>::get();
33 }
34
RequestCompleteGpuInfoIfNeeded()35 void GpuDataManager::RequestCompleteGpuInfoIfNeeded() {
36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
37 if (complete_gpu_info_already_requested_)
38 return;
39 complete_gpu_info_already_requested_ = true;
40
41 GpuProcessHost::SendOnIO(
42 0,
43 content::CAUSE_FOR_GPU_LAUNCH_GPUDATAMANAGER_REQUESTCOMPLETEGPUINFOIFNEEDED,
44 new GpuMsg_CollectGraphicsInfo());
45 }
46
UpdateGpuInfo(const GPUInfo & gpu_info)47 void GpuDataManager::UpdateGpuInfo(const GPUInfo& gpu_info) {
48 base::AutoLock auto_lock(gpu_info_lock_);
49 if (!gpu_info_.Merge(gpu_info))
50 return;
51 child_process_logging::SetGpuInfo(gpu_info_);
52 }
53
gpu_info() const54 const GPUInfo& GpuDataManager::gpu_info() const {
55 base::AutoLock auto_lock(gpu_info_lock_);
56 return gpu_info_;
57 }
58
GetFeatureStatus()59 Value* GpuDataManager::GetFeatureStatus() {
60 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
61 if (gpu_blacklist_.get())
62 return gpu_blacklist_->GetFeatureStatus(GpuAccessAllowed(),
63 browser_command_line.HasSwitch(switches::kDisableAcceleratedCompositing),
64 browser_command_line.HasSwitch(switches::kEnableAccelerated2dCanvas),
65 browser_command_line.HasSwitch(switches::kDisableExperimentalWebGL),
66 browser_command_line.HasSwitch(switches::kDisableGLMultisampling));
67 return NULL;
68 }
69
GetBlacklistVersion() const70 std::string GpuDataManager::GetBlacklistVersion() const {
71 if (gpu_blacklist_.get() != NULL) {
72 uint16 version_major, version_minor;
73 if (gpu_blacklist_->GetVersion(&version_major,
74 &version_minor)) {
75 std::string version_string =
76 base::UintToString(static_cast<unsigned>(version_major)) +
77 "." +
78 base::UintToString(static_cast<unsigned>(version_minor));
79 return version_string;
80 }
81 }
82 return "";
83 }
84
AddLogMessage(Value * msg)85 void GpuDataManager::AddLogMessage(Value* msg) {
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
87 log_messages_.Append(msg);
88 }
89
log_messages() const90 const ListValue& GpuDataManager::log_messages() const {
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
92 return log_messages_;
93 }
94
GetGpuFeatureFlags()95 GpuFeatureFlags GpuDataManager::GetGpuFeatureFlags() {
96 return gpu_feature_flags_;
97 }
98
GpuAccessAllowed()99 bool GpuDataManager::GpuAccessAllowed() {
100 uint32 flags = gpu_feature_flags_.flags();
101
102 // This will in effect block access to all GPU features if any of them
103 // is blacklisted.
104 // TODO(vangelis): Restructure the code to make it possible to selectively
105 // blaclist gpu features.
106 return !(flags & GpuFeatureFlags::kGpuFeatureAccelerated2dCanvas ||
107 flags & GpuFeatureFlags::kGpuFeatureAcceleratedCompositing ||
108 flags & GpuFeatureFlags::kGpuFeatureWebgl);
109 }
110
AddGpuInfoUpdateCallback(Callback0::Type * callback)111 void GpuDataManager::AddGpuInfoUpdateCallback(Callback0::Type* callback) {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
113 gpu_info_update_callbacks_.insert(callback);
114 }
115
RemoveGpuInfoUpdateCallback(Callback0::Type * callback)116 bool GpuDataManager::RemoveGpuInfoUpdateCallback(Callback0::Type* callback) {
117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
118 std::set<Callback0::Type*>::iterator i =
119 gpu_info_update_callbacks_.find(callback);
120 if (i != gpu_info_update_callbacks_.end()) {
121 gpu_info_update_callbacks_.erase(i);
122 return true;
123 }
124 return false;
125 }
126
AppendRendererCommandLine(CommandLine * command_line)127 void GpuDataManager::AppendRendererCommandLine(
128 CommandLine* command_line) {
129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
130 DCHECK(command_line);
131
132 uint32 flags = gpu_feature_flags_.flags();
133 if ((flags & GpuFeatureFlags::kGpuFeatureWebgl) &&
134 !command_line->HasSwitch(switches::kDisableExperimentalWebGL))
135 command_line->AppendSwitch(switches::kDisableExperimentalWebGL);
136 if ((flags & GpuFeatureFlags::kGpuFeatureMultisampling) &&
137 !command_line->HasSwitch(switches::kDisableGLMultisampling))
138 command_line->AppendSwitch(switches::kDisableGLMultisampling);
139 // If we have kGpuFeatureAcceleratedCompositing, we disable all GPU features.
140 if (flags & GpuFeatureFlags::kGpuFeatureAcceleratedCompositing) {
141 const char* switches[] = {
142 switches::kDisableAcceleratedCompositing,
143 switches::kDisableExperimentalWebGL
144 };
145 const int switch_count = sizeof(switches) / sizeof(char*);
146 for (int i = 0; i < switch_count; ++i) {
147 if (!command_line->HasSwitch(switches[i]))
148 command_line->AppendSwitch(switches[i]);
149 }
150 }
151 }
152
UpdateGpuBlacklist(GpuBlacklist * gpu_blacklist)153 void GpuDataManager::UpdateGpuBlacklist(GpuBlacklist* gpu_blacklist) {
154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
155 gpu_blacklist_.reset(gpu_blacklist);
156 UpdateGpuFeatureFlags();
157 }
158
RunGpuInfoUpdateCallbacks()159 void GpuDataManager::RunGpuInfoUpdateCallbacks() {
160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
161 std::set<Callback0::Type*>::iterator i = gpu_info_update_callbacks_.begin();
162 for (; i != gpu_info_update_callbacks_.end(); ++i) {
163 (*i)->Run();
164 }
165 }
166
UpdateGpuFeatureFlags()167 void GpuDataManager::UpdateGpuFeatureFlags() {
168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
169
170 GpuBlacklist* gpu_blacklist = GetGpuBlacklist();
171 if (gpu_blacklist == NULL)
172 return;
173
174 // We don't set a lock around modifying gpu_feature_flags_ since it's just an
175 // int.
176 if (!gpu_blacklist) {
177 gpu_feature_flags_.set_flags(0);
178 return;
179 }
180
181 {
182 base::AutoLock auto_lock(gpu_info_lock_);
183 gpu_feature_flags_ = gpu_blacklist->DetermineGpuFeatureFlags(
184 GpuBlacklist::kOsAny, NULL, gpu_info_);
185
186 // If gpu is blacklisted, no further GPUInfo will be collected.
187 gpu_info_.finalized = true;
188 }
189
190 uint32 max_entry_id = gpu_blacklist->max_entry_id();
191 if (!gpu_feature_flags_.flags()) {
192 UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
193 0, max_entry_id + 1);
194 return;
195 }
196
197 // Notify clients that GpuInfo state has changed
198 RunGpuInfoUpdateCallbacks();
199
200 // TODO(zmo): move histograming to GpuBlacklist::DetermineGpuFeatureFlags.
201 std::vector<uint32> flag_entries;
202 gpu_blacklist->GetGpuFeatureFlagEntries(
203 GpuFeatureFlags::kGpuFeatureAll, flag_entries);
204 DCHECK_GT(flag_entries.size(), 0u);
205 for (size_t i = 0; i < flag_entries.size(); ++i) {
206 UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry",
207 flag_entries[i], max_entry_id + 1);
208 }
209 }
210
GetGpuBlacklist()211 GpuBlacklist* GpuDataManager::GetGpuBlacklist() {
212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
213 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
214 if (browser_command_line.HasSwitch(switches::kIgnoreGpuBlacklist) ||
215 browser_command_line.GetSwitchValueASCII(
216 switches::kUseGL) == gfx::kGLImplementationOSMesaName)
217 return NULL;
218 // No need to return an empty blacklist.
219 if (gpu_blacklist_.get() != NULL && gpu_blacklist_->max_entry_id() == 0)
220 return NULL;
221 return gpu_blacklist_.get();
222 }
223