Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / gpu / gpu_internals_ui.cc
blobc338e02530e943fc01289897160d0a1a8776941a
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.
5 #include "content/browser/gpu/gpu_internals_ui.h"
7 #include <string>
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/grit/content_resources.h"
20 #include "content/public/browser/browser_thread.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 "third_party/angle/src/common/version.h"
33 #if defined(OS_WIN)
34 #include "ui/base/win/shell.h"
35 #endif
37 namespace content {
38 namespace {
40 WebUIDataSource* CreateGpuHTMLSource() {
41 WebUIDataSource* source = WebUIDataSource::Create(kChromeUIGpuHost);
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;
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;
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;
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));
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));
83 return list;
85 #endif
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*" : "");
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])));
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)));
121 if (gpu_info.display_link_version.IsValid()) {
122 basic_info->Append(NewDescriptionValuePair(
123 "DisplayLink Version", gpu_info.display_link_version.GetString()));
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
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));
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));
169 basic_info->Append(NewDescriptionValuePair(
170 "GPU process crash count",
171 new base::FundamentalValue(gpu_info.process_crash_count)));
173 base::DictionaryValue* info = new base::DictionaryValue();
174 info->Set("basic_info", basic_info);
176 #if defined(OS_WIN)
177 base::ListValue* perf_info = new base::ListValue();
178 perf_info->Append(NewDescriptionValuePair(
179 "Graphics",
180 base::StringPrintf("%.1f", gpu_info.performance_stats.graphics)));
181 perf_info->Append(NewDescriptionValuePair(
182 "Gaming",
183 base::StringPrintf("%.1f", gpu_info.performance_stats.gaming)));
184 perf_info->Append(NewDescriptionValuePair(
185 "Overall",
186 base::StringPrintf("%.1f", gpu_info.performance_stats.overall)));
187 info->Set("performance_info", perf_info);
189 base::Value* dx_info = gpu_info.dx_diagnostics.children.size() ?
190 DxDiagNodeToList(gpu_info.dx_diagnostics) :
191 base::Value::CreateNullValue();
192 info->Set("diagnostics", dx_info);
193 #endif
195 return info;
198 // This class receives javascript messages from the renderer.
199 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
200 // this class's methods are expected to run on the UI thread.
201 class GpuMessageHandler
202 : public WebUIMessageHandler,
203 public base::SupportsWeakPtr<GpuMessageHandler>,
204 public GpuDataManagerObserver {
205 public:
206 GpuMessageHandler();
207 virtual ~GpuMessageHandler();
209 // WebUIMessageHandler implementation.
210 virtual void RegisterMessages() OVERRIDE;
212 // GpuDataManagerObserver implementation.
213 virtual void OnGpuInfoUpdate() OVERRIDE;
214 virtual void OnGpuSwitching() OVERRIDE;
216 // Messages
217 void OnBrowserBridgeInitialized(const base::ListValue* list);
218 void OnCallAsync(const base::ListValue* list);
220 // Submessages dispatched from OnCallAsync
221 base::Value* OnRequestClientInfo(const base::ListValue* list);
222 base::Value* OnRequestLogMessages(const base::ListValue* list);
224 private:
225 // True if observing the GpuDataManager (re-attaching as observer would
226 // DCHECK).
227 bool observing_;
229 DISALLOW_COPY_AND_ASSIGN(GpuMessageHandler);
232 ////////////////////////////////////////////////////////////////////////////////
234 // GpuMessageHandler
236 ////////////////////////////////////////////////////////////////////////////////
238 GpuMessageHandler::GpuMessageHandler()
239 : observing_(false) {
242 GpuMessageHandler::~GpuMessageHandler() {
243 GpuDataManagerImpl::GetInstance()->RemoveObserver(this);
246 /* BrowserBridge.callAsync prepends a requestID to these messages. */
247 void GpuMessageHandler::RegisterMessages() {
248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
250 web_ui()->RegisterMessageCallback("browserBridgeInitialized",
251 base::Bind(&GpuMessageHandler::OnBrowserBridgeInitialized,
252 base::Unretained(this)));
253 web_ui()->RegisterMessageCallback("callAsync",
254 base::Bind(&GpuMessageHandler::OnCallAsync,
255 base::Unretained(this)));
258 void GpuMessageHandler::OnCallAsync(const base::ListValue* args) {
259 DCHECK_GE(args->GetSize(), static_cast<size_t>(2));
260 // unpack args into requestId, submessage and submessageArgs
261 bool ok;
262 const base::Value* requestId;
263 ok = args->Get(0, &requestId);
264 DCHECK(ok);
266 std::string submessage;
267 ok = args->GetString(1, &submessage);
268 DCHECK(ok);
270 base::ListValue* submessageArgs = new base::ListValue();
271 for (size_t i = 2; i < args->GetSize(); ++i) {
272 const base::Value* arg;
273 ok = args->Get(i, &arg);
274 DCHECK(ok);
276 base::Value* argCopy = arg->DeepCopy();
277 submessageArgs->Append(argCopy);
280 // call the submessage handler
281 base::Value* ret = NULL;
282 if (submessage == "requestClientInfo") {
283 ret = OnRequestClientInfo(submessageArgs);
284 } else if (submessage == "requestLogMessages") {
285 ret = OnRequestLogMessages(submessageArgs);
286 } else { // unrecognized submessage
287 NOTREACHED();
288 delete submessageArgs;
289 return;
291 delete submessageArgs;
293 // call BrowserBridge.onCallAsyncReply with result
294 if (ret) {
295 web_ui()->CallJavascriptFunction("browserBridge.onCallAsyncReply",
296 *requestId,
297 *ret);
298 delete ret;
299 } else {
300 web_ui()->CallJavascriptFunction("browserBridge.onCallAsyncReply",
301 *requestId);
305 void GpuMessageHandler::OnBrowserBridgeInitialized(
306 const base::ListValue* args) {
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
309 // Watch for changes in GPUInfo
310 if (!observing_)
311 GpuDataManagerImpl::GetInstance()->AddObserver(this);
312 observing_ = true;
314 // Tell GpuDataManager it should have full GpuInfo. If the
315 // Gpu process has not run yet, this will trigger its launch.
316 GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded();
318 // Run callback immediately in case the info is ready and no update in the
319 // future.
320 OnGpuInfoUpdate();
323 base::Value* GpuMessageHandler::OnRequestClientInfo(
324 const base::ListValue* list) {
325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
327 base::DictionaryValue* dict = new base::DictionaryValue();
329 dict->SetString("version", GetContentClient()->GetProduct());
330 dict->SetString("command_line",
331 base::CommandLine::ForCurrentProcess()->GetCommandLineString());
332 dict->SetString("operating_system",
333 base::SysInfo::OperatingSystemName() + " " +
334 base::SysInfo::OperatingSystemVersion());
335 dict->SetString("angle_commit_id", ANGLE_COMMIT_HASH);
336 dict->SetString("graphics_backend", "Skia");
337 dict->SetString("blacklist_version",
338 GpuDataManagerImpl::GetInstance()->GetBlacklistVersion());
339 dict->SetString("driver_bug_list_version",
340 GpuDataManagerImpl::GetInstance()->GetDriverBugListVersion());
342 return dict;
345 base::Value* GpuMessageHandler::OnRequestLogMessages(const base::ListValue*) {
346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
348 return GpuDataManagerImpl::GetInstance()->GetLogMessages();
351 void GpuMessageHandler::OnGpuInfoUpdate() {
352 // Get GPU Info.
353 scoped_ptr<base::DictionaryValue> gpu_info_val(GpuInfoAsDictionaryValue());
355 // Add in blacklisting features
356 base::DictionaryValue* feature_status = new base::DictionaryValue;
357 feature_status->Set("featureStatus", GetFeatureStatus());
358 feature_status->Set("problems", GetProblems());
359 feature_status->Set("workarounds", GetDriverBugWorkarounds());
360 if (feature_status)
361 gpu_info_val->Set("featureStatus", feature_status);
363 // Send GPU Info to javascript.
364 web_ui()->CallJavascriptFunction("browserBridge.onGpuInfoUpdate",
365 *(gpu_info_val.get()));
368 void GpuMessageHandler::OnGpuSwitching() {
369 GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded();
372 } // namespace
375 ////////////////////////////////////////////////////////////////////////////////
377 // GpuInternalsUI
379 ////////////////////////////////////////////////////////////////////////////////
381 GpuInternalsUI::GpuInternalsUI(WebUI* web_ui)
382 : WebUIController(web_ui) {
383 web_ui->AddMessageHandler(new GpuMessageHandler());
385 // Set up the chrome://gpu/ source.
386 BrowserContext* browser_context =
387 web_ui->GetWebContents()->GetBrowserContext();
388 WebUIDataSource::Add(browser_context, CreateGpuHTMLSource());
391 } // namespace content