Home | History | Annotate | Download | only in browser
      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