• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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