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 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 29 GpuDataManager::~GpuDataManager() { } 30 31 GpuDataManager* GpuDataManager::GetInstance() { 32 return Singleton<GpuDataManager>::get(); 33 } 34 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 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 54 const GPUInfo& GpuDataManager::gpu_info() const { 55 base::AutoLock auto_lock(gpu_info_lock_); 56 return gpu_info_; 57 } 58 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 70 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 85 void GpuDataManager::AddLogMessage(Value* msg) { 86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 87 log_messages_.Append(msg); 88 } 89 90 const ListValue& GpuDataManager::log_messages() const { 91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 92 return log_messages_; 93 } 94 95 GpuFeatureFlags GpuDataManager::GetGpuFeatureFlags() { 96 return gpu_feature_flags_; 97 } 98 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 111 void GpuDataManager::AddGpuInfoUpdateCallback(Callback0::Type* callback) { 112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 113 gpu_info_update_callbacks_.insert(callback); 114 } 115 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 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 153 void GpuDataManager::UpdateGpuBlacklist(GpuBlacklist* gpu_blacklist) { 154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 155 gpu_blacklist_.reset(gpu_blacklist); 156 UpdateGpuFeatureFlags(); 157 } 158 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 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 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