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 <stddef.h>
8
9 #include <memory>
10 #include <string>
11 #include <utility>
12
13 #include "base/base64.h"
14 #include "base/bind.h"
15 #include "base/callback_helpers.h"
16 #include "base/command_line.h"
17 #include "base/environment.h"
18 #include "base/i18n/time_formatting.h"
19 #include "base/macros.h"
20 #include "base/stl_util.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/stringize_macros.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/system/sys_info.h"
25 #include "base/values.h"
26 #include "build/build_config.h"
27 #include "content/browser/gpu/compositor_util.h"
28 #include "content/browser/gpu/gpu_data_manager_impl.h"
29 #include "content/browser/gpu/gpu_process_host.h"
30 #include "content/grit/content_resources.h"
31 #include "content/grit/dev_ui_content_resources.h"
32 #include "content/public/browser/browser_thread.h"
33 #include "content/public/browser/content_browser_client.h"
34 #include "content/public/browser/gpu_data_manager_observer.h"
35 #include "content/public/browser/web_contents.h"
36 #include "content/public/browser/web_ui.h"
37 #include "content/public/browser/web_ui_data_source.h"
38 #include "content/public/browser/web_ui_message_handler.h"
39 #include "content/public/common/content_client.h"
40 #include "content/public/common/content_switches.h"
41 #include "content/public/common/url_constants.h"
42 #include "gpu/config/device_perf_info.h"
43 #include "gpu/config/gpu_feature_type.h"
44 #include "gpu/config/gpu_info.h"
45 #include "gpu/config/gpu_lists_version.h"
46 #include "gpu/config/gpu_util.h"
47 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
48 #include "gpu/ipc/host/gpu_memory_buffer_support.h"
49 #include "services/network/public/mojom/content_security_policy.mojom.h"
50 #include "skia/ext/skia_commit_hash.h"
51 #include "third_party/angle/src/common/version.h"
52 #include "third_party/skia/include/core/SkMilestone.h"
53 #include "ui/display/display.h"
54 #include "ui/display/screen.h"
55 #include "ui/gfx/buffer_format_util.h"
56 #include "ui/gfx/buffer_usage_util.h"
57 #include "ui/gfx/gpu_extra_info.h"
58 #include "ui/gl/gpu_switching_manager.h"
59
60 #if defined(OS_WIN)
61 #include "ui/base/win/shell.h"
62 #include "ui/gfx/win/physical_size.h"
63 #endif
64
65 #if defined(USE_X11)
66 #include "ui/base/x/x11_util.h" // nogncheck
67 #include "ui/gfx/x/x11_atom_cache.h" // nogncheck
68 #endif
69
70 #if defined(USE_OZONE)
71 #include "ui/base/ui_base_features.h"
72 #endif
73
74 namespace content {
75 namespace {
76
CreateGpuHTMLSource()77 WebUIDataSource* CreateGpuHTMLSource() {
78 WebUIDataSource* source = WebUIDataSource::Create(kChromeUIGpuHost);
79 source->OverrideContentSecurityPolicy(
80 network::mojom::CSPDirectiveName::ScriptSrc,
81 "script-src chrome://resources 'self' 'unsafe-eval';");
82 source->OverrideContentSecurityPolicy(
83 network::mojom::CSPDirectiveName::TrustedTypes,
84 "trusted-types jstemplate;");
85
86 source->UseStringsJs();
87 source->AddResourcePath("gpu_internals.js", IDR_GPU_INTERNALS_JS);
88 source->AddResourcePath("vulkan_info.mojom.js", IDR_VULKAN_INFO_MOJO_JS);
89 source->AddResourcePath("vulkan_types.mojom.js", IDR_VULKAN_TYPES_MOJO_JS);
90 source->SetDefaultResource(IDR_GPU_INTERNALS_HTML);
91 return source;
92 }
93
94 // Must be in sync with the copy in //ui/base/x/x11_util.cc.
NewDescriptionValuePair(base::StringPiece desc,base::StringPiece value)95 std::unique_ptr<base::DictionaryValue> NewDescriptionValuePair(
96 base::StringPiece desc,
97 base::StringPiece value) {
98 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
99 dict->SetString("description", desc);
100 dict->SetString("value", value);
101 return dict;
102 }
103
NewDescriptionValuePair(base::StringPiece desc,std::unique_ptr<base::Value> value)104 std::unique_ptr<base::DictionaryValue> NewDescriptionValuePair(
105 base::StringPiece desc,
106 std::unique_ptr<base::Value> value) {
107 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
108 dict->SetString("description", desc);
109 dict->Set("value", std::move(value));
110 return dict;
111 }
112
113 #if defined(OS_WIN)
114 // Output DxDiagNode tree as nested array of {description,value} pairs
DxDiagNodeToList(const gpu::DxDiagNode & node)115 std::unique_ptr<base::ListValue> DxDiagNodeToList(const gpu::DxDiagNode& node) {
116 auto list = std::make_unique<base::ListValue>();
117 for (std::map<std::string, std::string>::const_iterator it =
118 node.values.begin();
119 it != node.values.end();
120 ++it) {
121 list->Append(NewDescriptionValuePair(it->first, it->second));
122 }
123
124 for (std::map<std::string, gpu::DxDiagNode>::const_iterator it =
125 node.children.begin();
126 it != node.children.end();
127 ++it) {
128 std::unique_ptr<base::ListValue> sublist = DxDiagNodeToList(it->second);
129 list->Append(NewDescriptionValuePair(it->first, std::move(sublist)));
130 }
131 return list;
132 }
133 #endif // OS_WIN
134
GPUDeviceToString(const gpu::GPUInfo::GPUDevice & gpu)135 std::string GPUDeviceToString(const gpu::GPUInfo::GPUDevice& gpu) {
136 std::string vendor = base::StringPrintf("0x%04x", gpu.vendor_id);
137 if (!gpu.vendor_string.empty())
138 vendor += " [" + gpu.vendor_string + "]";
139 std::string device = base::StringPrintf("0x%04x", gpu.device_id);
140 if (!gpu.device_string.empty())
141 device += " [" + gpu.device_string + "]";
142 std::string rt = base::StringPrintf("VENDOR= %s, DEVICE=%s", vendor.c_str(),
143 device.c_str());
144 #if defined(OS_WIN)
145 if (gpu.sub_sys_id || gpu.revision) {
146 rt += base::StringPrintf(", SUBSYS=0x%08x, REV=%u", gpu.sub_sys_id,
147 gpu.revision);
148 }
149
150 rt += base::StringPrintf(", LUID={%ld,%lu}", gpu.luid.HighPart,
151 gpu.luid.LowPart);
152 #endif
153 if (gpu.active)
154 rt += " *ACTIVE*";
155 return rt;
156 }
157
GpuExtraInfoToListValue(const gfx::GpuExtraInfo & gpu_extra_info)158 base::Value GpuExtraInfoToListValue(const gfx::GpuExtraInfo& gpu_extra_info) {
159 base::Value gpu_info_lines(base::Value::Type::LIST);
160 #if defined(USE_OZONE)
161 if (features::IsUsingOzonePlatform()) {
162 return display::Screen::GetScreen()->GetGpuExtraInfoAsListValue(
163 gpu_extra_info);
164 }
165 #endif
166 #if defined(USE_X11)
167 gpu_info_lines = ui::GpuExtraInfoAsListValue(gpu_extra_info.system_visual,
168 gpu_extra_info.rgba_visual);
169 #endif
170 return gpu_info_lines;
171 }
172
BasicGpuInfoAsListValue(const gpu::GPUInfo & gpu_info,const gpu::GpuFeatureInfo & gpu_feature_info,const gfx::GpuExtraInfo & gpu_extra_info)173 std::unique_ptr<base::ListValue> BasicGpuInfoAsListValue(
174 const gpu::GPUInfo& gpu_info,
175 const gpu::GpuFeatureInfo& gpu_feature_info,
176 const gfx::GpuExtraInfo& gpu_extra_info) {
177 const gpu::GPUInfo::GPUDevice& active_gpu = gpu_info.active_gpu();
178 auto basic_info = std::make_unique<base::ListValue>();
179 basic_info->Append(NewDescriptionValuePair(
180 "Initialization time",
181 base::NumberToString(gpu_info.initialization_time.InMilliseconds())));
182 basic_info->Append(NewDescriptionValuePair(
183 "In-process GPU",
184 std::make_unique<base::Value>(gpu_info.in_process_gpu)));
185 basic_info->Append(NewDescriptionValuePair(
186 "Passthrough Command Decoder",
187 std::make_unique<base::Value>(gpu_info.passthrough_cmd_decoder)));
188 basic_info->Append(NewDescriptionValuePair(
189 "Sandboxed", std::make_unique<base::Value>(gpu_info.sandboxed)));
190 basic_info->Append(
191 NewDescriptionValuePair("GPU0", GPUDeviceToString(gpu_info.gpu)));
192 for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) {
193 basic_info->Append(NewDescriptionValuePair(
194 base::StringPrintf("GPU%d", static_cast<int>(i + 1)),
195 GPUDeviceToString(gpu_info.secondary_gpus[i])));
196 }
197 basic_info->Append(NewDescriptionValuePair(
198 "Optimus", std::make_unique<base::Value>(gpu_info.optimus)));
199 basic_info->Append(NewDescriptionValuePair(
200 "AMD switchable",
201 std::make_unique<base::Value>(gpu_info.amd_switchable)));
202 #if defined(OS_WIN)
203 std::string compositor =
204 ui::win::IsAeroGlassEnabled() ? "Aero Glass" : "none";
205 basic_info->Append(
206 NewDescriptionValuePair("Desktop compositing", compositor));
207
208 basic_info->Append(NewDescriptionValuePair(
209 "Direct composition",
210 std::make_unique<base::Value>(gpu_info.overlay_info.direct_composition)));
211 basic_info->Append(NewDescriptionValuePair(
212 "Supports overlays",
213 std::make_unique<base::Value>(gpu_info.overlay_info.supports_overlays)));
214 basic_info->Append(NewDescriptionValuePair(
215 "YUY2 overlay support",
216 gpu::OverlaySupportToString(gpu_info.overlay_info.yuy2_overlay_support)));
217 basic_info->Append(NewDescriptionValuePair(
218 "NV12 overlay support",
219 gpu::OverlaySupportToString(gpu_info.overlay_info.nv12_overlay_support)));
220 basic_info->Append(NewDescriptionValuePair(
221 "BGRA8 overlay support",
222 gpu::OverlaySupportToString(
223 gpu_info.overlay_info.bgra8_overlay_support)));
224 basic_info->Append(NewDescriptionValuePair(
225 "RGB10A2 overlay support",
226 gpu::OverlaySupportToString(
227 gpu_info.overlay_info.rgb10a2_overlay_support)));
228
229 std::vector<gfx::PhysicalDisplaySize> display_sizes =
230 gfx::GetPhysicalSizeForDisplays();
231 for (const auto& display_size : display_sizes) {
232 const int w = display_size.width_mm;
233 const int h = display_size.height_mm;
234 const double size_mm = sqrt(w * w + h * h);
235 const double size_inches = 0.0393701 * size_mm;
236 const double rounded_size_inches = floor(10.0 * size_inches) / 10.0;
237 std::string size_string = base::StringPrintf("%.1f\"", rounded_size_inches);
238 std::string description_string = base::StringPrintf(
239 "Diagonal Monitor Size of %s", display_size.display_name.c_str());
240 basic_info->Append(
241 NewDescriptionValuePair(description_string, size_string));
242 }
243
244 basic_info->Append(NewDescriptionValuePair(
245 "Driver D3D12 feature level",
246 gpu::D3DFeatureLevelToString(gpu_info.d3d12_feature_level)));
247
248 basic_info->Append(NewDescriptionValuePair(
249 "Driver Vulkan API version",
250 gpu::VulkanVersionToString(gpu_info.vulkan_version)));
251 #endif
252
253 basic_info->Append(
254 NewDescriptionValuePair("Driver vendor", active_gpu.driver_vendor));
255 basic_info->Append(
256 NewDescriptionValuePair("Driver version", active_gpu.driver_version));
257 basic_info->Append(NewDescriptionValuePair(
258 "GPU CUDA compute capability major version",
259 std::make_unique<base::Value>(active_gpu.cuda_compute_capability_major)));
260 basic_info->Append(NewDescriptionValuePair("Pixel shader version",
261 gpu_info.pixel_shader_version));
262 basic_info->Append(NewDescriptionValuePair("Vertex shader version",
263 gpu_info.vertex_shader_version));
264 basic_info->Append(
265 NewDescriptionValuePair("Max. MSAA samples", gpu_info.max_msaa_samples));
266 basic_info->Append(NewDescriptionValuePair("Machine model name",
267 gpu_info.machine_model_name));
268 basic_info->Append(NewDescriptionValuePair("Machine model version",
269 gpu_info.machine_model_version));
270 basic_info->Append(NewDescriptionValuePair("GL_VENDOR", gpu_info.gl_vendor));
271 basic_info->Append(
272 NewDescriptionValuePair("GL_RENDERER", gpu_info.gl_renderer));
273 basic_info->Append(
274 NewDescriptionValuePair("GL_VERSION", gpu_info.gl_version));
275 basic_info->Append(
276 NewDescriptionValuePair("GL_EXTENSIONS", gpu_info.gl_extensions));
277 basic_info->Append(NewDescriptionValuePair(
278 "Disabled Extensions", gpu_feature_info.disabled_extensions));
279 basic_info->Append(NewDescriptionValuePair(
280 "Disabled WebGL Extensions", gpu_feature_info.disabled_webgl_extensions));
281 basic_info->Append(NewDescriptionValuePair("Window system binding vendor",
282 gpu_info.gl_ws_vendor));
283 basic_info->Append(NewDescriptionValuePair("Window system binding version",
284 gpu_info.gl_ws_version));
285 basic_info->Append(NewDescriptionValuePair("Window system binding extensions",
286 gpu_info.gl_ws_extensions));
287
288 {
289 base::Value gpu_extra_info_as_list_value =
290 GpuExtraInfoToListValue(gpu_extra_info);
291 DCHECK(gpu_extra_info_as_list_value.is_list());
292 {
293 auto pairs = gpu_extra_info_as_list_value.TakeList();
294 for (auto& pair : pairs) {
295 if (pair.FindStringKey("description") == nullptr ||
296 pair.FindKey("value") == nullptr) {
297 LOG(WARNING) << "Unexpected item format: should have a string "
298 "description and a value.";
299 }
300 basic_info->Append(std::move(pair));
301 }
302 }
303 }
304
305 std::string direct_rendering_version;
306 if (gpu_info.direct_rendering_version == "1") {
307 direct_rendering_version = "indirect";
308 } else if (gpu_info.direct_rendering_version == "2") {
309 direct_rendering_version = "direct but version unknown";
310 } else if (base::StartsWith(gpu_info.direct_rendering_version, "2.",
311 base::CompareCase::INSENSITIVE_ASCII)) {
312 direct_rendering_version = gpu_info.direct_rendering_version;
313 base::ReplaceFirstSubstringAfterOffset(&direct_rendering_version, 0, "2.",
314 "DRI");
315 } else {
316 direct_rendering_version = "unknown";
317 }
318 basic_info->Append(NewDescriptionValuePair("Direct rendering version",
319 direct_rendering_version));
320
321 std::string reset_strategy =
322 base::StringPrintf("0x%04x", gpu_info.gl_reset_notification_strategy);
323 basic_info->Append(
324 NewDescriptionValuePair("Reset notification strategy", reset_strategy));
325
326 basic_info->Append(NewDescriptionValuePair(
327 "GPU process crash count",
328 std::make_unique<base::Value>(GpuProcessHost::GetGpuCrashCount())));
329
330 std::string buffer_formats;
331 for (int i = 0; i <= static_cast<int>(gfx::BufferFormat::LAST); ++i) {
332 const gfx::BufferFormat buffer_format = static_cast<gfx::BufferFormat>(i);
333 if (i > 0)
334 buffer_formats += ", ";
335 buffer_formats += gfx::BufferFormatToString(buffer_format);
336 const bool supported = base::Contains(
337 gpu_feature_info.supported_buffer_formats_for_allocation_and_texturing,
338 buffer_format);
339 buffer_formats += supported ? ": supported" : ": not supported";
340 }
341 basic_info->Append(NewDescriptionValuePair(
342 "gfx::BufferFormats supported for allocation and texturing",
343 buffer_formats));
344
345 return basic_info;
346 }
347
GpuInfoAsDictionaryValue()348 std::unique_ptr<base::DictionaryValue> GpuInfoAsDictionaryValue() {
349 auto info = std::make_unique<base::DictionaryValue>();
350
351 const gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
352 const gpu::GpuFeatureInfo gpu_feature_info =
353 GpuDataManagerImpl::GetInstance()->GetGpuFeatureInfo();
354 const gfx::GpuExtraInfo gpu_extra_info =
355 GpuDataManagerImpl::GetInstance()->GetGpuExtraInfo();
356 auto basic_info =
357 BasicGpuInfoAsListValue(gpu_info, gpu_feature_info, gpu_extra_info);
358 info->Set("basicInfo", std::move(basic_info));
359
360 #if defined(OS_WIN)
361 auto dx_info = std::make_unique<base::Value>();
362 if (gpu_info.dx_diagnostics.children.size())
363 dx_info = DxDiagNodeToList(gpu_info.dx_diagnostics);
364 info->Set("diagnostics", std::move(dx_info));
365 #endif
366
367 #if BUILDFLAG(ENABLE_VULKAN)
368 if (gpu_info.vulkan_info) {
369 auto blob = gpu_info.vulkan_info->Serialize();
370 info->SetString("vulkanInfo", base::Base64Encode(blob));
371 }
372 #endif
373
374 return info;
375 }
376
CompositorInfo()377 std::unique_ptr<base::ListValue> CompositorInfo() {
378 auto compositor_info = std::make_unique<base::ListValue>();
379
380 compositor_info->Append(NewDescriptionValuePair(
381 "Tile Update Mode",
382 IsZeroCopyUploadEnabled() ? "Zero-copy" : "One-copy"));
383
384 compositor_info->Append(NewDescriptionValuePair(
385 "Partial Raster", IsPartialRasterEnabled() ? "Enabled" : "Disabled"));
386 return compositor_info;
387 }
388
GpuMemoryBufferInfo(const gfx::GpuExtraInfo & gpu_extra_info)389 std::unique_ptr<base::ListValue> GpuMemoryBufferInfo(
390 const gfx::GpuExtraInfo& gpu_extra_info) {
391 auto gpu_memory_buffer_info = std::make_unique<base::ListValue>();
392
393 gpu::GpuMemoryBufferSupport gpu_memory_buffer_support;
394
395 gpu::GpuMemoryBufferConfigurationSet native_config;
396 #if defined(USE_X11)
397 if (!features::IsUsingOzonePlatform()) {
398 for (const auto& config : gpu_extra_info.gpu_memory_buffer_support_x11) {
399 native_config.emplace(config);
400 }
401 }
402 #endif
403 if (native_config.empty()) {
404 native_config =
405 gpu::GetNativeGpuMemoryBufferConfigurations(&gpu_memory_buffer_support);
406 }
407 for (size_t format = 0;
408 format < static_cast<size_t>(gfx::BufferFormat::LAST) + 1; format++) {
409 std::string native_usage_support;
410 for (size_t usage = 0;
411 usage < static_cast<size_t>(gfx::BufferUsage::LAST) + 1; usage++) {
412 gfx::BufferUsageAndFormat element{static_cast<gfx::BufferUsage>(usage),
413 static_cast<gfx::BufferFormat>(format)};
414 if (base::Contains(native_config, element)) {
415 native_usage_support = base::StringPrintf(
416 "%s%s %s", native_usage_support.c_str(),
417 native_usage_support.empty() ? "" : ",",
418 gfx::BufferUsageToString(static_cast<gfx::BufferUsage>(usage)));
419 }
420 }
421 if (native_usage_support.empty())
422 native_usage_support = base::StringPrintf("Software only");
423
424 gpu_memory_buffer_info->Append(NewDescriptionValuePair(
425 gfx::BufferFormatToString(static_cast<gfx::BufferFormat>(format)),
426 native_usage_support));
427 }
428 return gpu_memory_buffer_info;
429 }
430
GetDisplayInfo()431 std::unique_ptr<base::ListValue> GetDisplayInfo() {
432 auto display_info = std::make_unique<base::ListValue>();
433 const std::vector<display::Display> displays =
434 display::Screen::GetScreen()->GetAllDisplays();
435 for (const auto& display : displays) {
436 display_info->Append(NewDescriptionValuePair("Info ", display.ToString()));
437 {
438 std::vector<std::string> names;
439 std::vector<gfx::ColorSpace> color_spaces;
440 std::vector<gfx::BufferFormat> buffer_formats;
441 display.color_spaces().ToStrings(&names, &color_spaces, &buffer_formats);
442 for (size_t i = 0; i < names.size(); ++i) {
443 display_info->Append(NewDescriptionValuePair(
444 base::StringPrintf("Color space (%s)", names[i].c_str()),
445 color_spaces[i].ToString()));
446 display_info->Append(NewDescriptionValuePair(
447 base::StringPrintf("Buffer format (%s)", names[i].c_str()),
448 gfx::BufferFormatToString(buffer_formats[i])));
449 }
450 }
451 display_info->Append(NewDescriptionValuePair(
452 "SDR white level in nits",
453 base::NumberToString(display.color_spaces().GetSDRWhiteLevel())));
454 display_info->Append(NewDescriptionValuePair(
455 "Bits per color component",
456 base::NumberToString(display.depth_per_component())));
457 display_info->Append(NewDescriptionValuePair(
458 "Bits per pixel", base::NumberToString(display.color_depth())));
459 if (display.display_frequency()) {
460 display_info->Append(NewDescriptionValuePair(
461 "Refresh Rate in Hz",
462 base::NumberToString(display.display_frequency())));
463 }
464 }
465 return display_info;
466 }
467
468 #if defined(OS_WIN)
D3dFeatureLevelToString(D3D_FEATURE_LEVEL level)469 const char* D3dFeatureLevelToString(D3D_FEATURE_LEVEL level) {
470 switch (level) {
471 case D3D_FEATURE_LEVEL_1_0_CORE:
472 return "Unknown";
473 case D3D_FEATURE_LEVEL_9_1:
474 return "9_1";
475 case D3D_FEATURE_LEVEL_9_2:
476 return "9_2";
477 case D3D_FEATURE_LEVEL_9_3:
478 return "9_3";
479 case D3D_FEATURE_LEVEL_10_0:
480 return "10_0";
481 case D3D_FEATURE_LEVEL_10_1:
482 return "10_1";
483 case D3D_FEATURE_LEVEL_11_0:
484 return "11_0";
485 case D3D_FEATURE_LEVEL_11_1:
486 return "11_1";
487 case D3D_FEATURE_LEVEL_12_0:
488 return "12_0";
489 case D3D_FEATURE_LEVEL_12_1:
490 return "12_1";
491 default:
492 NOTREACHED();
493 return "";
494 }
495 }
496
HasDiscreteGpuToString(gpu::HasDiscreteGpu has_discrete_gpu)497 const char* HasDiscreteGpuToString(gpu::HasDiscreteGpu has_discrete_gpu) {
498 switch (has_discrete_gpu) {
499 case gpu::HasDiscreteGpu::kUnknown:
500 return "unknown";
501 case gpu::HasDiscreteGpu::kNo:
502 return "no";
503 case gpu::HasDiscreteGpu::kYes:
504 return "yes";
505 }
506 NOTREACHED();
507 return "";
508 }
509 #endif // OS_WIN
510
GetDevicePerfInfo()511 std::unique_ptr<base::ListValue> GetDevicePerfInfo() {
512 auto list = std::make_unique<base::ListValue>();
513 const base::Optional<gpu::DevicePerfInfo> device_perf_info =
514 gpu::GetDevicePerfInfo();
515 if (device_perf_info.has_value()) {
516 list->Append(NewDescriptionValuePair(
517 "Total Physical Memory (Gb)",
518 base::NumberToString(device_perf_info->total_physical_memory_mb /
519 1024)));
520 list->Append(NewDescriptionValuePair(
521 "Total Disk Space (Gb)",
522 base::NumberToString(device_perf_info->total_disk_space_mb / 1024)));
523 list->Append(NewDescriptionValuePair(
524 "Hardware Concurrency",
525 base::NumberToString(device_perf_info->hardware_concurrency)));
526
527 #if defined(OS_WIN)
528 list->Append(NewDescriptionValuePair(
529 "System Commit Limit (Gb)",
530 base::NumberToString(device_perf_info->system_commit_limit_mb / 1024)));
531 list->Append(NewDescriptionValuePair(
532 "D3D11 Feature Level",
533 D3dFeatureLevelToString(device_perf_info->d3d11_feature_level)));
534 list->Append(NewDescriptionValuePair(
535 "Has Discrete GPU",
536 HasDiscreteGpuToString(device_perf_info->has_discrete_gpu)));
537 #endif // OS_WIN
538
539 if (device_perf_info->intel_gpu_generation !=
540 gpu::IntelGpuGeneration::kNonIntel) {
541 std::string intel_gpu_gen;
542 if (device_perf_info->intel_gpu_generation ==
543 gpu::IntelGpuGeneration::kUnknownIntel) {
544 intel_gpu_gen = "unknown";
545 } else {
546 intel_gpu_gen = base::NumberToString(
547 static_cast<int>(device_perf_info->intel_gpu_generation));
548 }
549 list->Append(
550 NewDescriptionValuePair("Intel GPU Generation", intel_gpu_gen));
551 }
552 list->Append(NewDescriptionValuePair(
553 "Software Rendering",
554 device_perf_info->software_rendering ? "Yes" : "No"));
555 }
556 return list;
557 }
558
GetProfileName(gpu::VideoCodecProfile profile)559 const char* GetProfileName(gpu::VideoCodecProfile profile) {
560 switch (profile) {
561 case gpu::VIDEO_CODEC_PROFILE_UNKNOWN:
562 return "unknown";
563 case gpu::H264PROFILE_BASELINE:
564 return "h264 baseline";
565 case gpu::H264PROFILE_MAIN:
566 return "h264 main";
567 case gpu::H264PROFILE_EXTENDED:
568 return "h264 extended";
569 case gpu::H264PROFILE_HIGH:
570 return "h264 high";
571 case gpu::H264PROFILE_HIGH10PROFILE:
572 return "h264 high 10";
573 case gpu::H264PROFILE_HIGH422PROFILE:
574 return "h264 high 4:2:2";
575 case gpu::H264PROFILE_HIGH444PREDICTIVEPROFILE:
576 return "h264 high 4:4:4 predictive";
577 case gpu::H264PROFILE_SCALABLEBASELINE:
578 return "h264 scalable baseline";
579 case gpu::H264PROFILE_SCALABLEHIGH:
580 return "h264 scalable high";
581 case gpu::H264PROFILE_STEREOHIGH:
582 return "h264 stereo high";
583 case gpu::H264PROFILE_MULTIVIEWHIGH:
584 return "h264 multiview high";
585 case gpu::HEVCPROFILE_MAIN:
586 return "hevc main";
587 case gpu::HEVCPROFILE_MAIN10:
588 return "hevc main 10";
589 case gpu::HEVCPROFILE_MAIN_STILL_PICTURE:
590 return "hevc main still-picture";
591 case gpu::VP8PROFILE_ANY:
592 return "vp8";
593 case gpu::VP9PROFILE_PROFILE0:
594 return "vp9 profile0";
595 case gpu::VP9PROFILE_PROFILE1:
596 return "vp9 profile1";
597 case gpu::VP9PROFILE_PROFILE2:
598 return "vp9 profile2";
599 case gpu::VP9PROFILE_PROFILE3:
600 return "vp9 profile3";
601 case gpu::DOLBYVISION_PROFILE0:
602 return "dolby vision profile 0";
603 case gpu::DOLBYVISION_PROFILE4:
604 return "dolby vision profile 4";
605 case gpu::DOLBYVISION_PROFILE5:
606 return "dolby vision profile 5";
607 case gpu::DOLBYVISION_PROFILE7:
608 return "dolby vision profile 7";
609 case gpu::DOLBYVISION_PROFILE8:
610 return "dolby vision profile 8";
611 case gpu::DOLBYVISION_PROFILE9:
612 return "dolby vision profile 9";
613 case gpu::THEORAPROFILE_ANY:
614 return "theora";
615 case gpu::AV1PROFILE_PROFILE_MAIN:
616 return "av1 profile main";
617 case gpu::AV1PROFILE_PROFILE_HIGH:
618 return "av1 profile high";
619 case gpu::AV1PROFILE_PROFILE_PRO:
620 return "av1 profile pro";
621 }
622 NOTREACHED();
623 return "";
624 }
625
GetVideoAcceleratorsInfo()626 std::unique_ptr<base::ListValue> GetVideoAcceleratorsInfo() {
627 gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
628 auto info = std::make_unique<base::ListValue>();
629
630 for (const auto& profile :
631 gpu_info.video_decode_accelerator_capabilities.supported_profiles) {
632 std::string codec_string =
633 base::StringPrintf("Decode %s", GetProfileName(profile.profile));
634 std::string resolution_string = base::StringPrintf(
635 "%s to %s pixels%s", profile.min_resolution.ToString().c_str(),
636 profile.max_resolution.ToString().c_str(),
637 profile.encrypted_only ? " (encrypted)" : "");
638 info->Append(NewDescriptionValuePair(codec_string, resolution_string));
639 }
640
641 for (const auto& profile :
642 gpu_info.video_encode_accelerator_supported_profiles) {
643 std::string codec_string =
644 base::StringPrintf("Encode %s", GetProfileName(profile.profile));
645 std::string resolution_string = base::StringPrintf(
646 "%s to %s pixels, and/or %.3f fps",
647 profile.min_resolution.ToString().c_str(),
648 profile.max_resolution.ToString().c_str(),
649 static_cast<double>(profile.max_framerate_numerator) /
650 profile.max_framerate_denominator);
651 info->Append(NewDescriptionValuePair(codec_string, resolution_string));
652 }
653 return info;
654 }
655
GetANGLEFeatures()656 std::unique_ptr<base::ListValue> GetANGLEFeatures() {
657 gfx::GpuExtraInfo gpu_extra_info =
658 GpuDataManagerImpl::GetInstance()->GetGpuExtraInfo();
659 auto angle_features_list = std::make_unique<base::ListValue>();
660 for (const auto& feature : gpu_extra_info.angle_features) {
661 auto angle_feature = std::make_unique<base::DictionaryValue>();
662 angle_feature->SetString("name", feature.name);
663 angle_feature->SetString("category", feature.category);
664 angle_feature->SetString("description", feature.description);
665 angle_feature->SetString("bug", feature.bug);
666 angle_feature->SetString("status", feature.status);
667 angle_feature->SetString("condition", feature.condition);
668 angle_features_list->Append(std::move(angle_feature));
669 }
670
671 return angle_features_list;
672 }
673
674 // This class receives javascript messages from the renderer.
675 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
676 // this class's methods are expected to run on the UI thread.
677 class GpuMessageHandler
678 : public WebUIMessageHandler,
679 public base::SupportsWeakPtr<GpuMessageHandler>,
680 public GpuDataManagerObserver,
681 public ui::GpuSwitchingObserver {
682 public:
683 GpuMessageHandler();
684 ~GpuMessageHandler() override;
685
686 // WebUIMessageHandler implementation.
687 void RegisterMessages() override;
688
689 // GpuDataManagerObserver implementation.
690 void OnGpuInfoUpdate() override;
691
692 // ui::GpuSwitchingObserver implementation.
693 void OnGpuSwitched(gl::GpuPreference) override;
694
695 // Messages
696 void OnBrowserBridgeInitialized(const base::ListValue* list);
697 void OnCallAsync(const base::ListValue* list);
698
699 // Submessages dispatched from OnCallAsync
700 std::unique_ptr<base::DictionaryValue> OnRequestClientInfo(
701 const base::ListValue* list);
702 std::unique_ptr<base::ListValue> OnRequestLogMessages(
703 const base::ListValue* list);
704
705 private:
706 // True if observing the GpuDataManager (re-attaching as observer would
707 // DCHECK).
708 bool observing_;
709
710 DISALLOW_COPY_AND_ASSIGN(GpuMessageHandler);
711 };
712
713 ////////////////////////////////////////////////////////////////////////////////
714 //
715 // GpuMessageHandler
716 //
717 ////////////////////////////////////////////////////////////////////////////////
718
GpuMessageHandler()719 GpuMessageHandler::GpuMessageHandler()
720 : observing_(false) {
721 }
722
~GpuMessageHandler()723 GpuMessageHandler::~GpuMessageHandler() {
724 ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
725 GpuDataManagerImpl::GetInstance()->RemoveObserver(this);
726 }
727
728 /* BrowserBridge.callAsync prepends a requestID to these messages. */
RegisterMessages()729 void GpuMessageHandler::RegisterMessages() {
730 DCHECK_CURRENTLY_ON(BrowserThread::UI);
731
732 web_ui()->RegisterMessageCallback(
733 "browserBridgeInitialized",
734 base::BindRepeating(&GpuMessageHandler::OnBrowserBridgeInitialized,
735 base::Unretained(this)));
736 web_ui()->RegisterMessageCallback(
737 "callAsync", base::BindRepeating(&GpuMessageHandler::OnCallAsync,
738 base::Unretained(this)));
739 }
740
OnCallAsync(const base::ListValue * args)741 void GpuMessageHandler::OnCallAsync(const base::ListValue* args) {
742 DCHECK_GE(args->GetSize(), static_cast<size_t>(2));
743 // unpack args into requestId, submessage and submessageArgs
744 bool ok;
745 const base::Value* requestId;
746 ok = args->Get(0, &requestId);
747 DCHECK(ok);
748
749 std::string submessage;
750 ok = args->GetString(1, &submessage);
751 DCHECK(ok);
752
753 auto submessageArgs = std::make_unique<base::ListValue>();
754 for (size_t i = 2; i < args->GetSize(); ++i) {
755 const base::Value* arg;
756 ok = args->Get(i, &arg);
757 DCHECK(ok);
758
759 submessageArgs->Append(arg->CreateDeepCopy());
760 }
761
762 // call the submessage handler
763 std::unique_ptr<base::Value> ret;
764 if (submessage == "requestClientInfo") {
765 ret = OnRequestClientInfo(submessageArgs.get());
766 } else if (submessage == "requestLogMessages") {
767 ret = OnRequestLogMessages(submessageArgs.get());
768 } else { // unrecognized submessage
769 NOTREACHED();
770 return;
771 }
772
773 // call BrowserBridge.onCallAsyncReply with result
774 if (ret) {
775 web_ui()->CallJavascriptFunctionUnsafe("browserBridge.onCallAsyncReply",
776 *requestId, *ret);
777 } else {
778 web_ui()->CallJavascriptFunctionUnsafe("browserBridge.onCallAsyncReply",
779 *requestId);
780 }
781 }
782
OnBrowserBridgeInitialized(const base::ListValue * args)783 void GpuMessageHandler::OnBrowserBridgeInitialized(
784 const base::ListValue* args) {
785 DCHECK_CURRENTLY_ON(BrowserThread::UI);
786
787 // Watch for changes in GPUInfo
788 if (!observing_) {
789 GpuDataManagerImpl::GetInstance()->AddObserver(this);
790 ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
791 }
792 observing_ = true;
793
794 // Tell GpuDataManager it should have full GpuInfo. If the
795 // Gpu process has not run yet, this will trigger its launch.
796 GpuDataManagerImpl::GetInstance()->RequestDxdiagDx12VulkanGpuInfoIfNeeded(
797 kGpuInfoRequestAll, /*delayed=*/false);
798
799 // Run callback immediately in case the info is ready and no update in the
800 // future.
801 OnGpuInfoUpdate();
802 }
803
OnRequestClientInfo(const base::ListValue * list)804 std::unique_ptr<base::DictionaryValue> GpuMessageHandler::OnRequestClientInfo(
805 const base::ListValue* list) {
806 DCHECK_CURRENTLY_ON(BrowserThread::UI);
807
808 auto dict = std::make_unique<base::DictionaryValue>();
809
810 dict->SetString("version", GetContentClient()->browser()->GetProduct());
811 dict->SetString("command_line",
812 base::CommandLine::ForCurrentProcess()->GetCommandLineString());
813 dict->SetString("operating_system",
814 base::SysInfo::OperatingSystemName() + " " +
815 base::SysInfo::OperatingSystemVersion());
816 dict->SetString("angle_commit_id", ANGLE_COMMIT_HASH);
817 dict->SetString("graphics_backend",
818 std::string("Skia/" STRINGIZE(SK_MILESTONE)
819 " " SKIA_COMMIT_HASH));
820 dict->SetString("revision_identifier", GPU_LISTS_VERSION);
821
822 return dict;
823 }
824
OnRequestLogMessages(const base::ListValue *)825 std::unique_ptr<base::ListValue> GpuMessageHandler::OnRequestLogMessages(
826 const base::ListValue*) {
827 DCHECK_CURRENTLY_ON(BrowserThread::UI);
828
829 return GpuDataManagerImpl::GetInstance()->GetLogMessages();
830 }
831
OnGpuInfoUpdate()832 void GpuMessageHandler::OnGpuInfoUpdate() {
833 // Get GPU Info.
834 const gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
835 const gfx::GpuExtraInfo gpu_extra_info =
836 GpuDataManagerImpl::GetInstance()->GetGpuExtraInfo();
837 auto gpu_info_val = GpuInfoAsDictionaryValue();
838
839 // Add in blocklisting features
840 auto feature_status = std::make_unique<base::DictionaryValue>();
841 feature_status->Set("featureStatus", GetFeatureStatus());
842 feature_status->Set("problems", GetProblems());
843 auto workarounds = std::make_unique<base::ListValue>();
844 for (const auto& workaround : GetDriverBugWorkarounds())
845 workarounds->AppendString(workaround);
846 feature_status->Set("workarounds", std::move(workarounds));
847 gpu_info_val->Set("featureStatus", std::move(feature_status));
848 if (!GpuDataManagerImpl::GetInstance()->IsGpuProcessUsingHardwareGpu()) {
849 auto feature_status_for_hardware_gpu =
850 std::make_unique<base::DictionaryValue>();
851 feature_status_for_hardware_gpu->Set("featureStatus",
852 GetFeatureStatusForHardwareGpu());
853 feature_status_for_hardware_gpu->Set("problems",
854 GetProblemsForHardwareGpu());
855 auto workarounds_for_hardware_gpu = std::make_unique<base::ListValue>();
856 for (const auto& workaround : GetDriverBugWorkaroundsForHardwareGpu())
857 workarounds_for_hardware_gpu->AppendString(workaround);
858 feature_status_for_hardware_gpu->Set(
859 "workarounds", std::move(workarounds_for_hardware_gpu));
860 gpu_info_val->Set("featureStatusForHardwareGpu",
861 std::move(feature_status_for_hardware_gpu));
862 const gpu::GPUInfo gpu_info_for_hardware_gpu =
863 GpuDataManagerImpl::GetInstance()->GetGPUInfoForHardwareGpu();
864 const gpu::GpuFeatureInfo gpu_feature_info_for_hardware_gpu =
865 GpuDataManagerImpl::GetInstance()->GetGpuFeatureInfoForHardwareGpu();
866 auto gpu_info_for_hardware_gpu_val = BasicGpuInfoAsListValue(
867 gpu_info_for_hardware_gpu, gpu_feature_info_for_hardware_gpu,
868 gfx::GpuExtraInfo{});
869 gpu_info_val->Set("basicInfoForHardwareGpu",
870 std::move(gpu_info_for_hardware_gpu_val));
871 }
872 gpu_info_val->Set("compositorInfo", CompositorInfo());
873 gpu_info_val->Set("gpuMemoryBufferInfo", GpuMemoryBufferInfo(gpu_extra_info));
874 gpu_info_val->Set("displayInfo", GetDisplayInfo());
875 gpu_info_val->Set("videoAcceleratorsInfo", GetVideoAcceleratorsInfo());
876 gpu_info_val->Set("ANGLEFeatures", GetANGLEFeatures());
877 gpu_info_val->Set("devicePerfInfo", GetDevicePerfInfo());
878
879 // Send GPU Info to javascript.
880 web_ui()->CallJavascriptFunctionUnsafe("browserBridge.onGpuInfoUpdate",
881 *(gpu_info_val.get()));
882 }
883
OnGpuSwitched(gl::GpuPreference active_gpu_heuristic)884 void GpuMessageHandler::OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) {
885 // Currently, about:gpu page does not update GPU info after the GPU switch.
886 // If there is something to be updated, the code should be added here.
887 }
888
889 } // namespace
890
891
892 ////////////////////////////////////////////////////////////////////////////////
893 //
894 // GpuInternalsUI
895 //
896 ////////////////////////////////////////////////////////////////////////////////
897
GpuInternalsUI(WebUI * web_ui)898 GpuInternalsUI::GpuInternalsUI(WebUI* web_ui)
899 : WebUIController(web_ui) {
900 web_ui->AddMessageHandler(std::make_unique<GpuMessageHandler>());
901
902 // Set up the chrome://gpu/ source.
903 BrowserContext* browser_context =
904 web_ui->GetWebContents()->GetBrowserContext();
905 WebUIDataSource::Add(browser_context, CreateGpuHTMLSource());
906 }
907
908 } // namespace content
909