a2b11bbda10a795c9e507c67674240062ac6f4ad
[platform/framework/web/crosswalk.git] / src / content / browser / gpu / gpu_internals_ui.cc
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(
95       "VENDOR = %s, DEVICE= %s", vendor.c_str(), device.c_str());
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",
143                                              gpu_info.machine_model));
144   basic_info->Append(NewDescriptionValuePair("GL version",
145                                              gpu_info.gl_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_string));
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