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 "cc/base/switches.h"
     18 #include "content/browser/gpu/gpu_data_manager_impl.h"
     19 #include "content/public/browser/browser_thread.h"
     20 #include "content/public/browser/compositor_util.h"
     21 #include "content/public/browser/gpu_data_manager_observer.h"
     22 #include "content/public/browser/web_contents.h"
     23 #include "content/public/browser/web_ui.h"
     24 #include "content/public/browser/web_ui_data_source.h"
     25 #include "content/public/browser/web_ui_message_handler.h"
     26 #include "content/public/common/content_client.h"
     27 #include "content/public/common/content_switches.h"
     28 #include "content/public/common/url_constants.h"
     29 #include "gpu/config/gpu_feature_type.h"
     30 #include "gpu/config/gpu_info.h"
     31 #include "grit/content_resources.h"
     32 #include "third_party/angle_dx11/src/common/version.h"
     33 
     34 namespace content {
     35 namespace {
     36 
     37 struct GpuFeatureInfo {
     38   std::string name;
     39   uint32 blocked;
     40   bool disabled;
     41   std::string disabled_description;
     42   bool fallback_to_software;
     43 };
     44 
     45 WebUIDataSource* CreateGpuHTMLSource() {
     46   WebUIDataSource* source = WebUIDataSource::Create(kChromeUIGpuHost);
     47 
     48   source->SetJsonPath("strings.js");
     49   source->AddResourcePath("gpu_internals.js", IDR_GPU_INTERNALS_JS);
     50   source->SetDefaultResource(IDR_GPU_INTERNALS_HTML);
     51   return source;
     52 }
     53 
     54 base::DictionaryValue* NewDescriptionValuePair(const std::string& desc,
     55     const std::string& value) {
     56   base::DictionaryValue* dict = new base::DictionaryValue();
     57   dict->SetString("description", desc);
     58   dict->SetString("value", value);
     59   return dict;
     60 }
     61 
     62 base::DictionaryValue* NewDescriptionValuePair(const std::string& desc,
     63     base::Value* value) {
     64   base::DictionaryValue* dict = new base::DictionaryValue();
     65   dict->SetString("description", desc);
     66   dict->Set("value", value);
     67   return dict;
     68 }
     69 
     70 base::Value* NewStatusValue(const char* name, const char* status) {
     71   base::DictionaryValue* value = new base::DictionaryValue();
     72   value->SetString("name", name);
     73   value->SetString("status", status);
     74   return value;
     75 }
     76 
     77 #if defined(OS_WIN)
     78 // Output DxDiagNode tree as nested array of {description,value} pairs
     79 base::ListValue* DxDiagNodeToList(const gpu::DxDiagNode& node) {
     80   base::ListValue* list = new base::ListValue();
     81   for (std::map<std::string, std::string>::const_iterator it =
     82       node.values.begin();
     83       it != node.values.end();
     84       ++it) {
     85     list->Append(NewDescriptionValuePair(it->first, it->second));
     86   }
     87 
     88   for (std::map<std::string, gpu::DxDiagNode>::const_iterator it =
     89       node.children.begin();
     90       it != node.children.end();
     91       ++it) {
     92     base::ListValue* sublist = DxDiagNodeToList(it->second);
     93     list->Append(NewDescriptionValuePair(it->first, sublist));
     94   }
     95   return list;
     96 }
     97 #endif
     98 
     99 std::string GPUDeviceToString(const gpu::GPUInfo::GPUDevice& gpu) {
    100   std::string vendor = base::StringPrintf("0x%04x", gpu.vendor_id);
    101   if (!gpu.vendor_string.empty())
    102     vendor += " [" + gpu.vendor_string + "]";
    103   std::string device = base::StringPrintf("0x%04x", gpu.device_id);
    104   if (!gpu.device_string.empty())
    105     device += " [" + gpu.device_string + "]";
    106   return base::StringPrintf(
    107       "VENDOR = %s, DEVICE= %s", vendor.c_str(), device.c_str());
    108 }
    109 
    110 base::DictionaryValue* GpuInfoAsDictionaryValue() {
    111   gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
    112   base::ListValue* basic_info = new base::ListValue();
    113   basic_info->Append(NewDescriptionValuePair(
    114       "Initialization time",
    115       base::Int64ToString(gpu_info.initialization_time.InMilliseconds())));
    116   basic_info->Append(NewDescriptionValuePair(
    117       "Sandboxed", new base::FundamentalValue(gpu_info.sandboxed)));
    118   basic_info->Append(NewDescriptionValuePair(
    119       "GPU0", GPUDeviceToString(gpu_info.gpu)));
    120   for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) {
    121     basic_info->Append(NewDescriptionValuePair(
    122         base::StringPrintf("GPU%d", static_cast<int>(i + 1)),
    123         GPUDeviceToString(gpu_info.secondary_gpus[i])));
    124   }
    125   basic_info->Append(NewDescriptionValuePair(
    126       "Optimus", new base::FundamentalValue(gpu_info.optimus)));
    127   basic_info->Append(NewDescriptionValuePair(
    128       "AMD switchable", new base::FundamentalValue(gpu_info.amd_switchable)));
    129   if (gpu_info.lenovo_dcute) {
    130     basic_info->Append(NewDescriptionValuePair(
    131         "Lenovo dCute", new base::FundamentalValue(true)));
    132   }
    133   if (gpu_info.display_link_version.IsValid()) {
    134     basic_info->Append(NewDescriptionValuePair(
    135         "DisplayLink Version", gpu_info.display_link_version.GetString()));
    136   }
    137   basic_info->Append(NewDescriptionValuePair("Driver vendor",
    138                                              gpu_info.driver_vendor));
    139   basic_info->Append(NewDescriptionValuePair("Driver version",
    140                                              gpu_info.driver_version));
    141   basic_info->Append(NewDescriptionValuePair("Driver date",
    142                                              gpu_info.driver_date));
    143   basic_info->Append(NewDescriptionValuePair("Pixel shader version",
    144                                              gpu_info.pixel_shader_version));
    145   basic_info->Append(NewDescriptionValuePair("Vertex shader version",
    146                                              gpu_info.vertex_shader_version));
    147   basic_info->Append(NewDescriptionValuePair("Machine model",
    148                                              gpu_info.machine_model));
    149   basic_info->Append(NewDescriptionValuePair("GL version",
    150                                              gpu_info.gl_version));
    151   basic_info->Append(NewDescriptionValuePair("GL_VENDOR",
    152                                              gpu_info.gl_vendor));
    153   basic_info->Append(NewDescriptionValuePair("GL_RENDERER",
    154                                              gpu_info.gl_renderer));
    155   basic_info->Append(NewDescriptionValuePair("GL_VERSION",
    156                                              gpu_info.gl_version_string));
    157   basic_info->Append(NewDescriptionValuePair("GL_EXTENSIONS",
    158                                              gpu_info.gl_extensions));
    159   basic_info->Append(NewDescriptionValuePair("Window system binding vendor",
    160                                              gpu_info.gl_ws_vendor));
    161   basic_info->Append(NewDescriptionValuePair("Window system binding version",
    162                                              gpu_info.gl_ws_version));
    163   basic_info->Append(NewDescriptionValuePair("Window system binding extensions",
    164                                              gpu_info.gl_ws_extensions));
    165   std::string reset_strategy =
    166       base::StringPrintf("0x%04x", gpu_info.gl_reset_notification_strategy);
    167   basic_info->Append(NewDescriptionValuePair(
    168       "Reset notification strategy", reset_strategy));
    169 
    170   base::DictionaryValue* info = new base::DictionaryValue();
    171   info->Set("basic_info", basic_info);
    172 
    173 #if defined(OS_WIN)
    174   base::ListValue* perf_info = new base::ListValue();
    175   perf_info->Append(NewDescriptionValuePair(
    176       "Graphics",
    177       base::StringPrintf("%.1f", gpu_info.performance_stats.graphics)));
    178   perf_info->Append(NewDescriptionValuePair(
    179       "Gaming",
    180       base::StringPrintf("%.1f", gpu_info.performance_stats.gaming)));
    181   perf_info->Append(NewDescriptionValuePair(
    182       "Overall",
    183       base::StringPrintf("%.1f", gpu_info.performance_stats.overall)));
    184   info->Set("performance_info", perf_info);
    185 
    186   base::Value* dx_info = gpu_info.dx_diagnostics.children.size() ?
    187     DxDiagNodeToList(gpu_info.dx_diagnostics) :
    188     base::Value::CreateNullValue();
    189   info->Set("diagnostics", dx_info);
    190 #endif
    191 
    192   return info;
    193 }
    194 
    195 // Determine if accelerated-2d-canvas is supported, which depends on whether
    196 // lose_context could happen.
    197 bool SupportsAccelerated2dCanvas() {
    198   if (GpuDataManagerImpl::GetInstance()->GetGPUInfo().can_lose_context)
    199     return false;
    200   return true;
    201 }
    202 
    203 base::Value* GetFeatureStatus() {
    204   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    205   GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
    206   std::string gpu_access_blocked_reason;
    207   bool gpu_access_blocked =
    208       !manager->GpuAccessAllowed(&gpu_access_blocked_reason);
    209 
    210   base::DictionaryValue* status = new base::DictionaryValue();
    211 
    212   const GpuFeatureInfo kGpuFeatureInfo[] = {
    213       {
    214           "2d_canvas",
    215           manager->IsFeatureBlacklisted(
    216               gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS),
    217           command_line.HasSwitch(switches::kDisableAccelerated2dCanvas) ||
    218           !SupportsAccelerated2dCanvas(),
    219           "Accelerated 2D canvas is unavailable: either disabled at the command"
    220           " line or not supported by the current system.",
    221           true
    222       },
    223       {
    224           "compositing",
    225           manager->IsFeatureBlacklisted(
    226               gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING),
    227           command_line.HasSwitch(switches::kDisableAcceleratedCompositing),
    228           "Accelerated compositing has been disabled, either via about:flags or"
    229           " command line. This adversely affects performance of all hardware"
    230           " accelerated features.",
    231           true
    232       },
    233       {
    234           "3d_css",
    235           manager->IsFeatureBlacklisted(
    236               gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
    237           manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_3D_CSS),
    238           command_line.HasSwitch(switches::kDisableAcceleratedLayers),
    239           "Accelerated layers have been disabled at the command line.",
    240           false
    241       },
    242       {
    243           "css_animation",
    244           manager->IsFeatureBlacklisted(
    245               gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING) ||
    246           manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_3D_CSS),
    247           command_line.HasSwitch(cc::switches::kDisableThreadedAnimation) ||
    248           command_line.HasSwitch(switches::kDisableAcceleratedCompositing) ||
    249           command_line.HasSwitch(switches::kDisableAcceleratedLayers),
    250           "Accelerated CSS animation has been disabled at the command line.",
    251           true
    252       },
    253       {
    254           "webgl",
    255           manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL),
    256           command_line.HasSwitch(switches::kDisableExperimentalWebGL),
    257           "WebGL has been disabled, either via about:flags or command line.",
    258           false
    259       },
    260       {
    261           "multisampling",
    262           manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_MULTISAMPLING),
    263           command_line.HasSwitch(switches::kDisableGLMultisampling),
    264           "Multisampling has been disabled, either via about:flags or command"
    265           " line.",
    266           false
    267       },
    268       {
    269           "flash_3d",
    270           manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH3D),
    271           command_line.HasSwitch(switches::kDisableFlash3d),
    272           "Using 3d in flash has been disabled, either via about:flags or"
    273           " command line.",
    274           false
    275       },
    276       {
    277           "flash_stage3d",
    278           manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D),
    279           command_line.HasSwitch(switches::kDisableFlashStage3d),
    280           "Using Stage3d in Flash has been disabled, either via about:flags or"
    281           " command line.",
    282           false
    283       },
    284       {
    285           "flash_stage3d_baseline",
    286           manager->IsFeatureBlacklisted(
    287               gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE) ||
    288           manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D),
    289           command_line.HasSwitch(switches::kDisableFlashStage3d),
    290           "Using Stage3d Baseline profile in Flash has been disabled, either"
    291           " via about:flags or command line.",
    292           false
    293       },
    294       {
    295           "texture_sharing",
    296           manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_TEXTURE_SHARING),
    297           command_line.HasSwitch(switches::kDisableImageTransportSurface),
    298           "Sharing textures between processes has been disabled, either via"
    299           " about:flags or command line.",
    300           false
    301       },
    302       {
    303           "video_decode",
    304           manager->IsFeatureBlacklisted(
    305               gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE),
    306           command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode),
    307           "Accelerated video decode has been disabled, either via about:flags"
    308           " or command line.",
    309           true
    310       },
    311       {
    312           "video",
    313           manager->IsFeatureBlacklisted(
    314               gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO),
    315           command_line.HasSwitch(switches::kDisableAcceleratedVideo) ||
    316           command_line.HasSwitch(switches::kDisableAcceleratedCompositing),
    317           "Accelerated video presentation has been disabled, either via"
    318           " about:flags or command line.",
    319           true
    320       },
    321 #if defined(OS_CHROMEOS)
    322       {
    323           "panel_fitting",
    324           manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_PANEL_FITTING),
    325           command_line.HasSwitch(switches::kDisablePanelFitting),
    326           "Panel fitting has been disabled, either via about:flags or command"
    327           " line.",
    328           false
    329       },
    330 #endif
    331       {
    332           "force_compositing_mode",
    333           manager->IsFeatureBlacklisted(
    334               gpu::GPU_FEATURE_TYPE_FORCE_COMPOSITING_MODE) &&
    335           !IsForceCompositingModeEnabled(),
    336           !IsForceCompositingModeEnabled() &&
    337           !manager->IsFeatureBlacklisted(
    338               gpu::GPU_FEATURE_TYPE_FORCE_COMPOSITING_MODE),
    339           "Force compositing mode is off, either disabled at the command"
    340           " line or not supported by the current system.",
    341           false
    342       },
    343   };
    344   const size_t kNumFeatures = sizeof(kGpuFeatureInfo) / sizeof(GpuFeatureInfo);
    345 
    346   // Build the feature_status field.
    347   {
    348     base::ListValue* feature_status_list = new base::ListValue();
    349 
    350     for (size_t i = 0; i < kNumFeatures; ++i) {
    351       // force_compositing_mode status is part of the compositing status.
    352       if (kGpuFeatureInfo[i].name == "force_compositing_mode")
    353         continue;
    354 
    355       std::string status;
    356       if (kGpuFeatureInfo[i].disabled) {
    357         status = "disabled";
    358         if (kGpuFeatureInfo[i].name == "css_animation") {
    359           status += "_software_animated";
    360         } else if (kGpuFeatureInfo[i].name == "raster") {
    361           if (cc::switches::IsImplSidePaintingEnabled())
    362             status += "_software_multithreaded";
    363           else
    364             status += "_software";
    365         } else {
    366           if (kGpuFeatureInfo[i].fallback_to_software)
    367             status += "_software";
    368           else
    369             status += "_off";
    370         }
    371       } else if (GpuDataManagerImpl::GetInstance()->ShouldUseSwiftShader()) {
    372         status = "unavailable_software";
    373       } else if (kGpuFeatureInfo[i].blocked ||
    374                  gpu_access_blocked) {
    375         status = "unavailable";
    376         if (kGpuFeatureInfo[i].fallback_to_software)
    377           status += "_software";
    378         else
    379           status += "_off";
    380       } else {
    381         status = "enabled";
    382         if (kGpuFeatureInfo[i].name == "webgl" &&
    383             (command_line.HasSwitch(switches::kDisableAcceleratedCompositing) ||
    384              manager->IsFeatureBlacklisted(
    385                  gpu::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING)))
    386           status += "_readback";
    387         bool has_thread = IsThreadedCompositingEnabled();
    388         if (kGpuFeatureInfo[i].name == "compositing") {
    389           bool force_compositing = IsForceCompositingModeEnabled();
    390           if (force_compositing)
    391             status += "_force";
    392           if (has_thread)
    393             status += "_threaded";
    394         }
    395         if (kGpuFeatureInfo[i].name == "css_animation") {
    396           if (has_thread)
    397             status = "accelerated_threaded";
    398           else
    399             status = "accelerated";
    400         }
    401       }
    402       // TODO(reveman): Remove this when crbug.com/223286 has been fixed.
    403       if (kGpuFeatureInfo[i].name == "raster" &&
    404           cc::switches::IsImplSidePaintingEnabled()) {
    405         status = "disabled_software_multithreaded";
    406       }
    407       feature_status_list->Append(
    408           NewStatusValue(kGpuFeatureInfo[i].name.c_str(), status.c_str()));
    409     }
    410     gpu::GpuSwitchingOption gpu_switching_option =
    411         GpuDataManagerImpl::GetInstance()->GetGpuSwitchingOption();
    412     if (gpu_switching_option != gpu::GPU_SWITCHING_OPTION_UNKNOWN) {
    413       std::string gpu_switching;
    414       switch (gpu_switching_option) {
    415       case gpu::GPU_SWITCHING_OPTION_AUTOMATIC:
    416           gpu_switching = "gpu_switching_automatic";
    417           break;
    418       case gpu::GPU_SWITCHING_OPTION_FORCE_DISCRETE:
    419           gpu_switching = "gpu_switching_force_discrete";
    420           break;
    421       case gpu::GPU_SWITCHING_OPTION_FORCE_INTEGRATED:
    422           gpu_switching = "gpu_switching_force_integrated";
    423           break;
    424         default:
    425           break;
    426       }
    427       feature_status_list->Append(
    428           NewStatusValue("gpu_switching", gpu_switching.c_str()));
    429     }
    430     status->Set("featureStatus", feature_status_list);
    431   }
    432 
    433   // Build the problems list.
    434   {
    435     base::ListValue* problem_list = new base::ListValue();
    436     GpuDataManagerImpl::GetInstance()->GetBlacklistReasons(problem_list);
    437 
    438     if (gpu_access_blocked) {
    439       base::DictionaryValue* problem = new base::DictionaryValue();
    440       problem->SetString("description",
    441           "GPU process was unable to boot: " + gpu_access_blocked_reason);
    442       problem->Set("crBugs", new base::ListValue());
    443       problem->Set("webkitBugs", new base::ListValue());
    444       problem_list->Insert(0, problem);
    445     }
    446 
    447     for (size_t i = 0; i < kNumFeatures; ++i) {
    448       if (kGpuFeatureInfo[i].disabled) {
    449         base::DictionaryValue* problem = new base::DictionaryValue();
    450         problem->SetString(
    451             "description", kGpuFeatureInfo[i].disabled_description);
    452         problem->Set("crBugs", new base::ListValue());
    453         problem->Set("webkitBugs", new base::ListValue());
    454         problem_list->Append(problem);
    455       }
    456     }
    457 
    458     status->Set("problems", problem_list);
    459   }
    460 
    461   // Build driver bug workaround list.
    462   {
    463     base::ListValue* workaround_list = new base::ListValue();
    464     GpuDataManagerImpl::GetInstance()->GetDriverBugWorkarounds(workaround_list);
    465     status->Set("workarounds", workaround_list);
    466   }
    467 
    468   return status;
    469 }
    470 
    471 // This class receives javascript messages from the renderer.
    472 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
    473 // this class's methods are expected to run on the UI thread.
    474 class GpuMessageHandler
    475     : public WebUIMessageHandler,
    476       public base::SupportsWeakPtr<GpuMessageHandler>,
    477       public GpuDataManagerObserver {
    478  public:
    479   GpuMessageHandler();
    480   virtual ~GpuMessageHandler();
    481 
    482   // WebUIMessageHandler implementation.
    483   virtual void RegisterMessages() OVERRIDE;
    484 
    485   // GpuDataManagerObserver implementation.
    486   virtual void OnGpuInfoUpdate() OVERRIDE;
    487   virtual void OnGpuSwitching() OVERRIDE;
    488 
    489   // Messages
    490   void OnBrowserBridgeInitialized(const base::ListValue* list);
    491   void OnCallAsync(const base::ListValue* list);
    492 
    493   // Submessages dispatched from OnCallAsync
    494   base::Value* OnRequestClientInfo(const base::ListValue* list);
    495   base::Value* OnRequestLogMessages(const base::ListValue* list);
    496 
    497  private:
    498   // True if observing the GpuDataManager (re-attaching as observer would
    499   // DCHECK).
    500   bool observing_;
    501 
    502   DISALLOW_COPY_AND_ASSIGN(GpuMessageHandler);
    503 };
    504 
    505 ////////////////////////////////////////////////////////////////////////////////
    506 //
    507 // GpuMessageHandler
    508 //
    509 ////////////////////////////////////////////////////////////////////////////////
    510 
    511 GpuMessageHandler::GpuMessageHandler()
    512     : observing_(false) {
    513 }
    514 
    515 GpuMessageHandler::~GpuMessageHandler() {
    516   GpuDataManagerImpl::GetInstance()->RemoveObserver(this);
    517 }
    518 
    519 /* BrowserBridge.callAsync prepends a requestID to these messages. */
    520 void GpuMessageHandler::RegisterMessages() {
    521   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    522 
    523   web_ui()->RegisterMessageCallback("browserBridgeInitialized",
    524       base::Bind(&GpuMessageHandler::OnBrowserBridgeInitialized,
    525                  base::Unretained(this)));
    526   web_ui()->RegisterMessageCallback("callAsync",
    527       base::Bind(&GpuMessageHandler::OnCallAsync,
    528                  base::Unretained(this)));
    529 }
    530 
    531 void GpuMessageHandler::OnCallAsync(const base::ListValue* args) {
    532   DCHECK_GE(args->GetSize(), static_cast<size_t>(2));
    533   // unpack args into requestId, submessage and submessageArgs
    534   bool ok;
    535   const base::Value* requestId;
    536   ok = args->Get(0, &requestId);
    537   DCHECK(ok);
    538 
    539   std::string submessage;
    540   ok = args->GetString(1, &submessage);
    541   DCHECK(ok);
    542 
    543   base::ListValue* submessageArgs = new base::ListValue();
    544   for (size_t i = 2; i < args->GetSize(); ++i) {
    545     const base::Value* arg;
    546     ok = args->Get(i, &arg);
    547     DCHECK(ok);
    548 
    549     base::Value* argCopy = arg->DeepCopy();
    550     submessageArgs->Append(argCopy);
    551   }
    552 
    553   // call the submessage handler
    554   base::Value* ret = NULL;
    555   if (submessage == "requestClientInfo") {
    556     ret = OnRequestClientInfo(submessageArgs);
    557   } else if (submessage == "requestLogMessages") {
    558     ret = OnRequestLogMessages(submessageArgs);
    559   } else {  // unrecognized submessage
    560     NOTREACHED();
    561     delete submessageArgs;
    562     return;
    563   }
    564   delete submessageArgs;
    565 
    566   // call BrowserBridge.onCallAsyncReply with result
    567   if (ret) {
    568     web_ui()->CallJavascriptFunction("browserBridge.onCallAsyncReply",
    569         *requestId,
    570         *ret);
    571     delete ret;
    572   } else {
    573     web_ui()->CallJavascriptFunction("browserBridge.onCallAsyncReply",
    574         *requestId);
    575   }
    576 }
    577 
    578 void GpuMessageHandler::OnBrowserBridgeInitialized(
    579     const base::ListValue* args) {
    580   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    581 
    582   // Watch for changes in GPUInfo
    583   if (!observing_)
    584     GpuDataManagerImpl::GetInstance()->AddObserver(this);
    585   observing_ = true;
    586 
    587   // Tell GpuDataManager it should have full GpuInfo. If the
    588   // Gpu process has not run yet, this will trigger its launch.
    589   GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded();
    590 
    591   // Run callback immediately in case the info is ready and no update in the
    592   // future.
    593   OnGpuInfoUpdate();
    594 }
    595 
    596 base::Value* GpuMessageHandler::OnRequestClientInfo(
    597     const base::ListValue* list) {
    598   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    599 
    600   base::DictionaryValue* dict = new base::DictionaryValue();
    601 
    602   dict->SetString("version", GetContentClient()->GetProduct());
    603   dict->SetString("command_line",
    604       CommandLine::ForCurrentProcess()->GetCommandLineString());
    605   dict->SetString("operating_system",
    606                   base::SysInfo::OperatingSystemName() + " " +
    607                   base::SysInfo::OperatingSystemVersion());
    608   dict->SetString("angle_revision", base::UintToString(BUILD_REVISION));
    609   dict->SetString("graphics_backend", "Skia");
    610   dict->SetString("blacklist_version",
    611       GpuDataManagerImpl::GetInstance()->GetBlacklistVersion());
    612   dict->SetString("driver_bug_list_version",
    613       GpuDataManagerImpl::GetInstance()->GetDriverBugListVersion());
    614 
    615   return dict;
    616 }
    617 
    618 base::Value* GpuMessageHandler::OnRequestLogMessages(const base::ListValue*) {
    619   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    620 
    621   return GpuDataManagerImpl::GetInstance()->GetLogMessages();
    622 }
    623 
    624 void GpuMessageHandler::OnGpuInfoUpdate() {
    625   // Get GPU Info.
    626   scoped_ptr<base::DictionaryValue> gpu_info_val(GpuInfoAsDictionaryValue());
    627 
    628   // Add in blacklisting features
    629   base::Value* feature_status = GetFeatureStatus();
    630   if (feature_status)
    631     gpu_info_val->Set("featureStatus", feature_status);
    632 
    633   // Send GPU Info to javascript.
    634   web_ui()->CallJavascriptFunction("browserBridge.onGpuInfoUpdate",
    635       *(gpu_info_val.get()));
    636 }
    637 
    638 void GpuMessageHandler::OnGpuSwitching() {
    639   GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded();
    640 }
    641 
    642 }  // namespace
    643 
    644 
    645 ////////////////////////////////////////////////////////////////////////////////
    646 //
    647 // GpuInternalsUI
    648 //
    649 ////////////////////////////////////////////////////////////////////////////////
    650 
    651 GpuInternalsUI::GpuInternalsUI(WebUI* web_ui)
    652     : WebUIController(web_ui) {
    653   web_ui->AddMessageHandler(new GpuMessageHandler());
    654 
    655   // Set up the chrome://gpu/ source.
    656   BrowserContext* browser_context =
    657       web_ui->GetWebContents()->GetBrowserContext();
    658   WebUIDataSource::Add(browser_context, CreateGpuHTMLSource());
    659 }
    660 
    661 }  // namespace content
    662