| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/gpu_data_manager.h" |
| |
| #include "base/command_line.h" |
| #include "base/metrics/histogram.h" |
| #include "base/string_number_conversions.h" |
| #include "chrome/common/child_process_logging.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "content/browser/browser_thread.h" |
| #include "content/browser/gpu_blacklist.h" |
| #include "content/browser/gpu_process_host.h" |
| #include "content/common/gpu_messages.h" |
| #include "content/gpu/gpu_info_collector.h" |
| #include "ui/gfx/gl/gl_implementation.h" |
| #include "ui/gfx/gl/gl_switches.h" |
| |
| GpuDataManager::GpuDataManager() |
| : complete_gpu_info_already_requested_(false) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| GPUInfo gpu_info; |
| gpu_info_collector::CollectPreliminaryGraphicsInfo(&gpu_info); |
| UpdateGpuInfo(gpu_info); |
| } |
| |
| GpuDataManager::~GpuDataManager() { } |
| |
| GpuDataManager* GpuDataManager::GetInstance() { |
| return Singleton<GpuDataManager>::get(); |
| } |
| |
| void GpuDataManager::RequestCompleteGpuInfoIfNeeded() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| if (complete_gpu_info_already_requested_) |
| return; |
| complete_gpu_info_already_requested_ = true; |
| |
| GpuProcessHost::SendOnIO( |
| 0, |
| content::CAUSE_FOR_GPU_LAUNCH_GPUDATAMANAGER_REQUESTCOMPLETEGPUINFOIFNEEDED, |
| new GpuMsg_CollectGraphicsInfo()); |
| } |
| |
| void GpuDataManager::UpdateGpuInfo(const GPUInfo& gpu_info) { |
| base::AutoLock auto_lock(gpu_info_lock_); |
| if (!gpu_info_.Merge(gpu_info)) |
| return; |
| child_process_logging::SetGpuInfo(gpu_info_); |
| } |
| |
| const GPUInfo& GpuDataManager::gpu_info() const { |
| base::AutoLock auto_lock(gpu_info_lock_); |
| return gpu_info_; |
| } |
| |
| Value* GpuDataManager::GetFeatureStatus() { |
| const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); |
| if (gpu_blacklist_.get()) |
| return gpu_blacklist_->GetFeatureStatus(GpuAccessAllowed(), |
| browser_command_line.HasSwitch(switches::kDisableAcceleratedCompositing), |
| browser_command_line.HasSwitch(switches::kEnableAccelerated2dCanvas), |
| browser_command_line.HasSwitch(switches::kDisableExperimentalWebGL), |
| browser_command_line.HasSwitch(switches::kDisableGLMultisampling)); |
| return NULL; |
| } |
| |
| std::string GpuDataManager::GetBlacklistVersion() const { |
| if (gpu_blacklist_.get() != NULL) { |
| uint16 version_major, version_minor; |
| if (gpu_blacklist_->GetVersion(&version_major, |
| &version_minor)) { |
| std::string version_string = |
| base::UintToString(static_cast<unsigned>(version_major)) + |
| "." + |
| base::UintToString(static_cast<unsigned>(version_minor)); |
| return version_string; |
| } |
| } |
| return ""; |
| } |
| |
| void GpuDataManager::AddLogMessage(Value* msg) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| log_messages_.Append(msg); |
| } |
| |
| const ListValue& GpuDataManager::log_messages() const { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| return log_messages_; |
| } |
| |
| GpuFeatureFlags GpuDataManager::GetGpuFeatureFlags() { |
| return gpu_feature_flags_; |
| } |
| |
| bool GpuDataManager::GpuAccessAllowed() { |
| uint32 flags = gpu_feature_flags_.flags(); |
| |
| // This will in effect block access to all GPU features if any of them |
| // is blacklisted. |
| // TODO(vangelis): Restructure the code to make it possible to selectively |
| // blaclist gpu features. |
| return !(flags & GpuFeatureFlags::kGpuFeatureAccelerated2dCanvas || |
| flags & GpuFeatureFlags::kGpuFeatureAcceleratedCompositing || |
| flags & GpuFeatureFlags::kGpuFeatureWebgl); |
| } |
| |
| void GpuDataManager::AddGpuInfoUpdateCallback(Callback0::Type* callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| gpu_info_update_callbacks_.insert(callback); |
| } |
| |
| bool GpuDataManager::RemoveGpuInfoUpdateCallback(Callback0::Type* callback) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| std::set<Callback0::Type*>::iterator i = |
| gpu_info_update_callbacks_.find(callback); |
| if (i != gpu_info_update_callbacks_.end()) { |
| gpu_info_update_callbacks_.erase(i); |
| return true; |
| } |
| return false; |
| } |
| |
| void GpuDataManager::AppendRendererCommandLine( |
| CommandLine* command_line) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(command_line); |
| |
| uint32 flags = gpu_feature_flags_.flags(); |
| if ((flags & GpuFeatureFlags::kGpuFeatureWebgl) && |
| !command_line->HasSwitch(switches::kDisableExperimentalWebGL)) |
| command_line->AppendSwitch(switches::kDisableExperimentalWebGL); |
| if ((flags & GpuFeatureFlags::kGpuFeatureMultisampling) && |
| !command_line->HasSwitch(switches::kDisableGLMultisampling)) |
| command_line->AppendSwitch(switches::kDisableGLMultisampling); |
| // If we have kGpuFeatureAcceleratedCompositing, we disable all GPU features. |
| if (flags & GpuFeatureFlags::kGpuFeatureAcceleratedCompositing) { |
| const char* switches[] = { |
| switches::kDisableAcceleratedCompositing, |
| switches::kDisableExperimentalWebGL |
| }; |
| const int switch_count = sizeof(switches) / sizeof(char*); |
| for (int i = 0; i < switch_count; ++i) { |
| if (!command_line->HasSwitch(switches[i])) |
| command_line->AppendSwitch(switches[i]); |
| } |
| } |
| } |
| |
| void GpuDataManager::UpdateGpuBlacklist(GpuBlacklist* gpu_blacklist) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| gpu_blacklist_.reset(gpu_blacklist); |
| UpdateGpuFeatureFlags(); |
| } |
| |
| void GpuDataManager::RunGpuInfoUpdateCallbacks() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| std::set<Callback0::Type*>::iterator i = gpu_info_update_callbacks_.begin(); |
| for (; i != gpu_info_update_callbacks_.end(); ++i) { |
| (*i)->Run(); |
| } |
| } |
| |
| void GpuDataManager::UpdateGpuFeatureFlags() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| GpuBlacklist* gpu_blacklist = GetGpuBlacklist(); |
| if (gpu_blacklist == NULL) |
| return; |
| |
| // We don't set a lock around modifying gpu_feature_flags_ since it's just an |
| // int. |
| if (!gpu_blacklist) { |
| gpu_feature_flags_.set_flags(0); |
| return; |
| } |
| |
| { |
| base::AutoLock auto_lock(gpu_info_lock_); |
| gpu_feature_flags_ = gpu_blacklist->DetermineGpuFeatureFlags( |
| GpuBlacklist::kOsAny, NULL, gpu_info_); |
| |
| // If gpu is blacklisted, no further GPUInfo will be collected. |
| gpu_info_.finalized = true; |
| } |
| |
| uint32 max_entry_id = gpu_blacklist->max_entry_id(); |
| if (!gpu_feature_flags_.flags()) { |
| UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry", |
| 0, max_entry_id + 1); |
| return; |
| } |
| |
| // Notify clients that GpuInfo state has changed |
| RunGpuInfoUpdateCallbacks(); |
| |
| // TODO(zmo): move histograming to GpuBlacklist::DetermineGpuFeatureFlags. |
| std::vector<uint32> flag_entries; |
| gpu_blacklist->GetGpuFeatureFlagEntries( |
| GpuFeatureFlags::kGpuFeatureAll, flag_entries); |
| DCHECK_GT(flag_entries.size(), 0u); |
| for (size_t i = 0; i < flag_entries.size(); ++i) { |
| UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerEntry", |
| flag_entries[i], max_entry_id + 1); |
| } |
| } |
| |
| GpuBlacklist* GpuDataManager::GetGpuBlacklist() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); |
| if (browser_command_line.HasSwitch(switches::kIgnoreGpuBlacklist) || |
| browser_command_line.GetSwitchValueASCII( |
| switches::kUseGL) == gfx::kGLImplementationOSMesaName) |
| return NULL; |
| // No need to return an empty blacklist. |
| if (gpu_blacklist_.get() != NULL && gpu_blacklist_->max_entry_id() == 0) |
| return NULL; |
| return gpu_blacklist_.get(); |
| } |