Home | History | Annotate | Download | only in gpu
      1 // Copyright (c) 2012 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 "content/browser/gpu/gpu_internals_ui.h"
      6 
      7 #include <string>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/command_line.h"
     12 #include "base/i18n/time_formatting.h"
     13 #include "base/strings/string_number_conversions.h"
     14 #include "base/strings/stringprintf.h"
     15 #include "base/sys_info.h"
     16 #include "base/values.h"
     17 #include "content/browser/gpu/compositor_util.h"
     18 #include "content/browser/gpu/gpu_data_manager_impl.h"
     19 #include "content/public/browser/browser_thread.h"
     20 #include "content/public/browser/gpu_data_manager_observer.h"
     21 #include "content/public/browser/web_contents.h"
     22 #include "content/public/browser/web_ui.h"
     23 #include "content/public/browser/web_ui_data_source.h"
     24 #include "content/public/browser/web_ui_message_handler.h"
     25 #include "content/public/common/content_client.h"
     26 #include "content/public/common/content_switches.h"
     27 #include "content/public/common/url_constants.h"
     28 #include "gpu/config/gpu_feature_type.h"
     29 #include "gpu/config/gpu_info.h"
     30 #include "grit/content_resources.h"
     31 #include "third_party/angle/src/common/version.h"
     32 
     33 #if defined(OS_WIN)
     34 #include "ui/base/win/shell.h"
     35 #endif
     36 
     37 namespace content {
     38 namespace {
     39 
     40 WebUIDataSource* CreateGpuHTMLSource() {
     41   WebUIDataSource* source = WebUIDataSource::Create(kChromeUIGpuHost);
     42 
     43   source->SetJsonPath("strings.js");
     44   source->AddResourcePath("gpu_internals.js", IDR_GPU_INTERNALS_JS);
     45   source->SetDefaultResource(IDR_GPU_INTERNALS_HTML);
     46   return source;
     47 }
     48 
     49 base::DictionaryValue* NewDescriptionValuePair(const std::string& desc,
     50     const std::string& value) {
     51   base::DictionaryValue* dict = new base::DictionaryValue();
     52   dict->SetString("description", desc);
     53   dict->SetString("value", value);
     54   return dict;
     55 }
     56 
     57 base::DictionaryValue* NewDescriptionValuePair(const std::string& desc,
     58     base::Value* value) {
     59   base::DictionaryValue* dict = new base::DictionaryValue();
     60   dict->SetString("description", desc);
     61   dict->Set("value", value);
     62   return dict;
     63 }
     64 
     65 #if defined(OS_WIN)
     66 // Output DxDiagNode tree as nested array of {description,value} pairs
     67 base::ListValue* DxDiagNodeToList(const gpu::DxDiagNode& node) {
     68   base::ListValue* list = new base::ListValue();
     69   for (std::map<std::string, std::string>::const_iterator it =
     70       node.values.begin();
     71       it != node.values.end();
     72       ++it) {
     73     list->Append(NewDescriptionValuePair(it->first, it->second));
     74   }
     75 
     76   for (std::map<std::string, gpu::DxDiagNode>::const_iterator it =
     77       node.children.begin();
     78       it != node.children.end();
     79       ++it) {
     80     base::ListValue* sublist = DxDiagNodeToList(it->second);
     81     list->Append(NewDescriptionValuePair(it->first, sublist));
     82   }
     83   return list;
     84 }
     85 #endif
     86 
     87 std::string GPUDeviceToString(const gpu::GPUInfo::GPUDevice& gpu) {
     88   std::string vendor = base::StringPrintf("0x%04x", gpu.vendor_id);
     89   if (!gpu.vendor_string.empty())
     90     vendor += " [" + gpu.vendor_string + "]";
     91   std::string device = base::StringPrintf("0x%04x", gpu.device_id);
     92   if (!gpu.device_string.empty())
     93     device += " [" + gpu.device_string + "]";
     94   return base::StringPrintf("VENDOR = %s, DEVICE= %s%s",
     95       vendor.c_str(), device.c_str(), gpu.active ? " *ACTIVE*" : "");
     96 }
     97 
     98 base::DictionaryValue* GpuInfoAsDictionaryValue() {
     99   gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
    100   base::ListValue* basic_info = new base::ListValue();
    101   basic_info->Append(NewDescriptionValuePair(
    102       "Initialization time",
    103       base::Int64ToString(gpu_info.initialization_time.InMilliseconds())));
    104   basic_info->Append(NewDescriptionValuePair(
    105       "Sandboxed", new base::FundamentalValue(gpu_info.sandboxed)));
    106   basic_info->Append(NewDescriptionValuePair(
    107       "GPU0", GPUDeviceToString(gpu_info.gpu)));
    108   for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) {
    109     basic_info->Append(NewDescriptionValuePair(
    110         base::StringPrintf("GPU%d", static_cast<int>(i + 1)),
    111         GPUDeviceToString(gpu_info.secondary_gpus[i])));
    112   }
    113   basic_info->Append(NewDescriptionValuePair(
    114       "Optimus", new base::FundamentalValue(gpu_info.optimus)));
    115   basic_info->Append(NewDescriptionValuePair(
    116       "AMD switchable", new base::FundamentalValue(gpu_info.amd_switchable)));
    117   if (gpu_info.lenovo_dcute) {
    118     basic_info->Append(NewDescriptionValuePair(
    119         "Lenovo dCute", new base::FundamentalValue(true)));
    120   }
    121   if (gpu_info.display_link_version.IsValid()) {
    122     basic_info->Append(NewDescriptionValuePair(
    123         "DisplayLink Version", gpu_info.display_link_version.GetString()));
    124   }
    125 #if defined(OS_WIN)
    126   std::string compositor =
    127       ui::win::IsAeroGlassEnabled() ? "Aero Glass" : "none";
    128   basic_info->Append(
    129       NewDescriptionValuePair("Desktop compositing", compositor));
    130 #endif
    131 
    132   basic_info->Append(
    133       NewDescriptionValuePair("Driver vendor", gpu_info.driver_vendor));
    134   basic_info->Append(NewDescriptionValuePair("Driver version",
    135                                              gpu_info.driver_version));
    136   basic_info->Append(NewDescriptionValuePair("Driver date",
    137                                              gpu_info.driver_date));
    138   basic_info->Append(NewDescriptionValuePair("Pixel shader version",
    139                                              gpu_info.pixel_shader_version));
    140   basic_info->Append(NewDescriptionValuePair("Vertex shader version",
    141                                              gpu_info.vertex_shader_version));
    142   basic_info->Append(NewDescriptionValuePair("Machine model name",
    143                                              gpu_info.machine_model_name));
    144   basic_info->Append(NewDescriptionValuePair("Machine model version",
    145                                              gpu_info.machine_model_version));
    146   basic_info->Append(NewDescriptionValuePair("GL_VENDOR",
    147                                              gpu_info.gl_vendor));
    148   basic_info->Append(NewDescriptionValuePair("GL_RENDERER",
    149                                              gpu_info.gl_renderer));
    150   basic_info->Append(NewDescriptionValuePair("GL_VERSION",
    151                                              gpu_info.gl_version));
    152   basic_info->Append(NewDescriptionValuePair("GL_EXTENSIONS",
    153                                              gpu_info.gl_extensions));
    154   basic_info->Append(NewDescriptionValuePair("Window system binding vendor",
    155                                              gpu_info.gl_ws_vendor));
    156   basic_info->Append(NewDescriptionValuePair("Window system binding version",
    157                                              gpu_info.gl_ws_version));
    158   basic_info->Append(NewDescriptionValuePair("Window system binding extensions",
    159                                              gpu_info.gl_ws_extensions));
    160   std::string direct_rendering = gpu_info.direct_rendering ? "Yes" : "No";
    161   basic_info->Append(
    162       NewDescriptionValuePair("Direct rendering", direct_rendering));
    163 
    164   std::string reset_strategy =
    165       base::StringPrintf("0x%04x", gpu_info.gl_reset_notification_strategy);
    166   basic_info->Append(NewDescriptionValuePair(
    167       "Reset notification strategy", reset_strategy));
    168 
    169   base::DictionaryValue* info = new base::DictionaryValue();
    170   info->Set("basic_info", basic_info);
    171 
    172 #if defined(OS_WIN)
    173   base::ListValue* perf_info = new base::ListValue();
    174   perf_info->Append(NewDescriptionValuePair(
    175       "Graphics",
    176       base::StringPrintf("%.1f", gpu_info.performance_stats.graphics)));
    177   perf_info->Append(NewDescriptionValuePair(
    178       "Gaming",
    179       base::StringPrintf("%.1f", gpu_info.performance_stats.gaming)));
    180   perf_info->Append(NewDescriptionValuePair(
    181       "Overall",
    182       base::StringPrintf("%.1f", gpu_info.performance_stats.overall)));
    183   info->Set("performance_info", perf_info);
    184 
    185   base::Value* dx_info = gpu_info.dx_diagnostics.children.size() ?
    186     DxDiagNodeToList(gpu_info.dx_diagnostics) :
    187     base::Value::CreateNullValue();
    188   info->Set("diagnostics", dx_info);
    189 #endif
    190 
    191   return info;
    192 }
    193 
    194 // This class receives javascript messages from the renderer.
    195 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
    196 // this class's methods are expected to run on the UI thread.
    197 class GpuMessageHandler
    198     : public WebUIMessageHandler,
    199       public base::SupportsWeakPtr<GpuMessageHandler>,
    200       public GpuDataManagerObserver {
    201  public:
    202   GpuMessageHandler();
    203   virtual ~GpuMessageHandler();
    204 
    205   // WebUIMessageHandler implementation.
    206   virtual void RegisterMessages() OVERRIDE;
    207 
    208   // GpuDataManagerObserver implementation.
    209   virtual void OnGpuInfoUpdate() OVERRIDE;
    210   virtual void OnGpuSwitching() OVERRIDE;
    211 
    212   // Messages
    213   void OnBrowserBridgeInitialized(const base::ListValue* list);
    214   void OnCallAsync(const base::ListValue* list);
    215 
    216   // Submessages dispatched from OnCallAsync
    217   base::Value* OnRequestClientInfo(const base::ListValue* list);
    218   base::Value* OnRequestLogMessages(const base::ListValue* list);
    219 
    220  private:
    221   // True if observing the GpuDataManager (re-attaching as observer would
    222   // DCHECK).
    223   bool observing_;
    224 
    225   DISALLOW_COPY_AND_ASSIGN(GpuMessageHandler);
    226 };
    227 
    228 ////////////////////////////////////////////////////////////////////////////////
    229 //
    230 // GpuMessageHandler
    231 //
    232 ////////////////////////////////////////////////////////////////////////////////
    233 
    234 GpuMessageHandler::GpuMessageHandler()
    235     : observing_(false) {
    236 }
    237 
    238 GpuMessageHandler::~GpuMessageHandler() {
    239   GpuDataManagerImpl::GetInstance()->RemoveObserver(this);
    240 }
    241 
    242 /* BrowserBridge.callAsync prepends a requestID to these messages. */
    243 void GpuMessageHandler::RegisterMessages() {
    244   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    245 
    246   web_ui()->RegisterMessageCallback("browserBridgeInitialized",
    247       base::Bind(&GpuMessageHandler::OnBrowserBridgeInitialized,
    248                  base::Unretained(this)));
    249   web_ui()->RegisterMessageCallback("callAsync",
    250       base::Bind(&GpuMessageHandler::OnCallAsync,
    251                  base::Unretained(this)));
    252 }
    253 
    254 void GpuMessageHandler::OnCallAsync(const base::ListValue* args) {
    255   DCHECK_GE(args->GetSize(), static_cast<size_t>(2));
    256   // unpack args into requestId, submessage and submessageArgs
    257   bool ok;
    258   const base::Value* requestId;
    259   ok = args->Get(0, &requestId);
    260   DCHECK(ok);
    261 
    262   std::string submessage;
    263   ok = args->GetString(1, &submessage);
    264   DCHECK(ok);
    265 
    266   base::ListValue* submessageArgs = new base::ListValue();
    267   for (size_t i = 2; i < args->GetSize(); ++i) {
    268     const base::Value* arg;
    269     ok = args->Get(i, &arg);
    270     DCHECK(ok);
    271 
    272     base::Value* argCopy = arg->DeepCopy();
    273     submessageArgs->Append(argCopy);
    274   }
    275 
    276   // call the submessage handler
    277   base::Value* ret = NULL;
    278   if (submessage == "requestClientInfo") {
    279     ret = OnRequestClientInfo(submessageArgs);
    280   } else if (submessage == "requestLogMessages") {
    281     ret = OnRequestLogMessages(submessageArgs);
    282   } else {  // unrecognized submessage
    283     NOTREACHED();
    284     delete submessageArgs;
    285     return;
    286   }
    287   delete submessageArgs;
    288 
    289   // call BrowserBridge.onCallAsyncReply with result
    290   if (ret) {
    291     web_ui()->CallJavascriptFunction("browserBridge.onCallAsyncReply",
    292         *requestId,
    293         *ret);
    294     delete ret;
    295   } else {
    296     web_ui()->CallJavascriptFunction("browserBridge.onCallAsyncReply",
    297         *requestId);
    298   }
    299 }
    300 
    301 void GpuMessageHandler::OnBrowserBridgeInitialized(
    302     const base::ListValue* args) {
    303   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    304 
    305   // Watch for changes in GPUInfo
    306   if (!observing_)
    307     GpuDataManagerImpl::GetInstance()->AddObserver(this);
    308   observing_ = true;
    309 
    310   // Tell GpuDataManager it should have full GpuInfo. If the
    311   // Gpu process has not run yet, this will trigger its launch.
    312   GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded();
    313 
    314   // Run callback immediately in case the info is ready and no update in the
    315   // future.
    316   OnGpuInfoUpdate();
    317 }
    318 
    319 base::Value* GpuMessageHandler::OnRequestClientInfo(
    320     const base::ListValue* list) {
    321   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    322 
    323   base::DictionaryValue* dict = new base::DictionaryValue();
    324 
    325   dict->SetString("version", GetContentClient()->GetProduct());
    326   dict->SetString("command_line",
    327       CommandLine::ForCurrentProcess()->GetCommandLineString());
    328   dict->SetString("operating_system",
    329                   base::SysInfo::OperatingSystemName() + " " +
    330                   base::SysInfo::OperatingSystemVersion());
    331   dict->SetString("angle_commit_id", ANGLE_COMMIT_HASH);
    332   dict->SetString("graphics_backend", "Skia");
    333   dict->SetString("blacklist_version",
    334       GpuDataManagerImpl::GetInstance()->GetBlacklistVersion());
    335   dict->SetString("driver_bug_list_version",
    336       GpuDataManagerImpl::GetInstance()->GetDriverBugListVersion());
    337 
    338   return dict;
    339 }
    340 
    341 base::Value* GpuMessageHandler::OnRequestLogMessages(const base::ListValue*) {
    342   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    343 
    344   return GpuDataManagerImpl::GetInstance()->GetLogMessages();
    345 }
    346 
    347 void GpuMessageHandler::OnGpuInfoUpdate() {
    348   // Get GPU Info.
    349   scoped_ptr<base::DictionaryValue> gpu_info_val(GpuInfoAsDictionaryValue());
    350 
    351   // Add in blacklisting features
    352   base::DictionaryValue* feature_status = new base::DictionaryValue;
    353   feature_status->Set("featureStatus", GetFeatureStatus());
    354   feature_status->Set("problems", GetProblems());
    355   feature_status->Set("workarounds", GetDriverBugWorkarounds());
    356   if (feature_status)
    357     gpu_info_val->Set("featureStatus", feature_status);
    358 
    359   // Send GPU Info to javascript.
    360   web_ui()->CallJavascriptFunction("browserBridge.onGpuInfoUpdate",
    361       *(gpu_info_val.get()));
    362 }
    363 
    364 void GpuMessageHandler::OnGpuSwitching() {
    365   GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded();
    366 }
    367 
    368 }  // namespace
    369 
    370 
    371 ////////////////////////////////////////////////////////////////////////////////
    372 //
    373 // GpuInternalsUI
    374 //
    375 ////////////////////////////////////////////////////////////////////////////////
    376 
    377 GpuInternalsUI::GpuInternalsUI(WebUI* web_ui)
    378     : WebUIController(web_ui) {
    379   web_ui->AddMessageHandler(new GpuMessageHandler());
    380 
    381   // Set up the chrome://gpu/ source.
    382   BrowserContext* browser_context =
    383       web_ui->GetWebContents()->GetBrowserContext();
    384   WebUIDataSource::Add(browser_context, CreateGpuHTMLSource());
    385 }
    386 
    387 }  // namespace content
    388