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
34namespace content {
35namespace {
36
37struct GpuFeatureInfo {
38  std::string name;
39  uint32 blocked;
40  bool disabled;
41  std::string disabled_description;
42  bool fallback_to_software;
43};
44
45WebUIDataSource* 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
54base::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
62base::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
70base::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
79base::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
99std::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
110base::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.
197bool SupportsAccelerated2dCanvas() {
198  if (GpuDataManagerImpl::GetInstance()->GetGPUInfo().can_lose_context)
199    return false;
200  return true;
201}
202
203base::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.
474class 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
511GpuMessageHandler::GpuMessageHandler()
512    : observing_(false) {
513}
514
515GpuMessageHandler::~GpuMessageHandler() {
516  GpuDataManagerImpl::GetInstance()->RemoveObserver(this);
517}
518
519/* BrowserBridge.callAsync prepends a requestID to these messages. */
520void 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
531void 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
578void 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
596base::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
618base::Value* GpuMessageHandler::OnRequestLogMessages(const base::ListValue*) {
619  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
620
621  return GpuDataManagerImpl::GetInstance()->GetLogMessages();
622}
623
624void 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
638void GpuMessageHandler::OnGpuSwitching() {
639  GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded();
640}
641
642}  // namespace
643
644
645////////////////////////////////////////////////////////////////////////////////
646//
647// GpuInternalsUI
648//
649////////////////////////////////////////////////////////////////////////////////
650
651GpuInternalsUI::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