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