// 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(); }