|  | // Copyright 2012 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "content/browser/gpu/gpu_internals_ui.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  |  | 
|  | #include <memory> | 
|  | #include <string> | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/base64.h" | 
|  | #include "base/command_line.h" | 
|  | #include "base/containers/contains.h" | 
|  | #include "base/environment.h" | 
|  | #include "base/functional/bind.h" | 
|  | #include "base/functional/callback_helpers.h" | 
|  | #include "base/i18n/time_formatting.h" | 
|  | #include "base/memory/raw_ref.h" | 
|  | #include "base/strings/string_number_conversions.h" | 
|  | #include "base/strings/string_util.h" | 
|  | #include "base/strings/stringize_macros.h" | 
|  | #include "base/strings/stringprintf.h" | 
|  | #include "base/strings/utf_string_conversions.h" | 
|  | #include "base/system/sys_info.h" | 
|  | #include "base/values.h" | 
|  | #include "build/build_config.h" | 
|  | #include "content/browser/gpu/compositor_util.h" | 
|  | #include "content/browser/gpu/gpu_data_manager_impl.h" | 
|  | #include "content/browser/gpu/gpu_process_host.h" | 
|  | #include "content/grit/gpu_resources.h" | 
|  | #include "content/grit/gpu_resources_map.h" | 
|  | #include "content/public/browser/browser_thread.h" | 
|  | #include "content/public/browser/content_browser_client.h" | 
|  | #include "content/public/browser/gpu_data_manager_observer.h" | 
|  | #include "content/public/browser/web_contents.h" | 
|  | #include "content/public/browser/web_ui.h" | 
|  | #include "content/public/browser/web_ui_data_source.h" | 
|  | #include "content/public/browser/web_ui_message_handler.h" | 
|  | #include "content/public/common/content_client.h" | 
|  | #include "content/public/common/content_switches.h" | 
|  | #include "content/public/common/url_constants.h" | 
|  | #include "gpu/config/device_perf_info.h" | 
|  | #include "gpu/config/gpu_feature_type.h" | 
|  | #include "gpu/config/gpu_info.h" | 
|  | #include "gpu/config/gpu_lists_version.h" | 
|  | #include "gpu/config/gpu_preferences.h" | 
|  | #include "gpu/config/gpu_util.h" | 
|  | #include "gpu/ipc/common/gpu_memory_buffer_support.h" | 
|  | #include "services/network/public/mojom/content_security_policy.mojom.h" | 
|  | #include "skia/ext/skia_commit_hash.h" | 
|  | #include "third_party/angle/src/common/angle_version_info.h" | 
|  | #include "third_party/skia/include/core/SkMilestone.h" | 
|  | #include "ui/base/ozone_buildflags.h" | 
|  | #include "ui/display/display.h" | 
|  | #include "ui/display/screen.h" | 
|  | #include "ui/display/util/gpu_info_util.h" | 
|  | #include "ui/gfx/buffer_format_util.h" | 
|  | #include "ui/gfx/buffer_usage_util.h" | 
|  | #include "ui/gfx/gpu_extra_info.h" | 
|  | #include "ui/gl/gpu_switching_manager.h" | 
|  |  | 
|  | #if BUILDFLAG(IS_WIN) | 
|  | #include "base/win/windows_version.h" | 
|  | #include "ui/gfx/win/physical_size.h" | 
|  | #endif | 
|  |  | 
|  | #if BUILDFLAG(IS_OZONE) | 
|  | #include "ui/ozone/public/ozone_platform.h" | 
|  | #endif  // BUILDFLAG(IS_OZONE) | 
|  |  | 
|  | namespace content { | 
|  | namespace { | 
|  |  | 
|  | void CreateAndAddGpuHTMLSource(BrowserContext* browser_context) { | 
|  | WebUIDataSource* source = | 
|  | WebUIDataSource::CreateAndAdd(browser_context, kChromeUIGpuHost); | 
|  | source->OverrideContentSecurityPolicy( | 
|  | network::mojom::CSPDirectiveName::ScriptSrc, | 
|  | "script-src chrome://resources chrome://webui-test 'self';"); | 
|  | source->OverrideContentSecurityPolicy( | 
|  | network::mojom::CSPDirectiveName::TrustedTypes, | 
|  | "trusted-types static-types;"); | 
|  |  | 
|  | source->UseStringsJs(); | 
|  | source->AddResourcePaths(kGpuResources); | 
|  | source->AddResourcePath("", IDR_GPU_GPU_INTERNALS_HTML); | 
|  | } | 
|  |  | 
|  | std::string GPUDeviceToString(const gpu::GPUInfo::GPUDevice& gpu) { | 
|  | std::string vendor = base::StringPrintf("0x%04x", gpu.vendor_id); | 
|  | if (!gpu.vendor_string.empty()) | 
|  | vendor += " [" + gpu.vendor_string + "]"; | 
|  | std::string device = base::StringPrintf("0x%04x", gpu.device_id); | 
|  | if (!gpu.device_string.empty()) | 
|  | device += " [" + gpu.device_string + "]"; | 
|  | std::string rt = base::StringPrintf("VENDOR= %s, DEVICE=%s", vendor.c_str(), | 
|  | device.c_str()); | 
|  | #if BUILDFLAG(IS_WIN) | 
|  | if (gpu.sub_sys_id) | 
|  | rt += base::StringPrintf(", SUBSYS=0x%08x", gpu.sub_sys_id); | 
|  | #endif | 
|  | #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) | 
|  | if (gpu.revision) | 
|  | rt += base::StringPrintf(", REV=%u", gpu.revision); | 
|  | #endif | 
|  | #if BUILDFLAG(IS_WIN) | 
|  | rt += base::StringPrintf(", LUID={%ld,%lu}", gpu.luid.HighPart, | 
|  | gpu.luid.LowPart); | 
|  | #endif | 
|  | if (!gpu.driver_vendor.empty()) | 
|  | rt += ", DRIVER_VENDOR=" + gpu.driver_vendor; | 
|  | if (!gpu.driver_version.empty()) | 
|  | rt += ", DRIVER_VERSION=" + gpu.driver_version; | 
|  | if (gpu.active) | 
|  | rt += " *ACTIVE*"; | 
|  | return rt; | 
|  | } | 
|  |  | 
|  | base::Value::List GetBasicGpuInfo(const gpu::GPUInfo& gpu_info, | 
|  | const gpu::GpuFeatureInfo& gpu_feature_info, | 
|  | const gfx::GpuExtraInfo& gpu_extra_info) { | 
|  | base::Value::List basic_info; | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "Initialization time", | 
|  | base::NumberToString(gpu_info.initialization_time.InMilliseconds()))); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "In-process GPU", base::Value(gpu_info.in_process_gpu))); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "Skia Backend", | 
|  | gpu::SkiaBackendTypeToString(gpu_info.skia_backend_type))); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "Passthrough Command Decoder", | 
|  | base::Value(gpu_info.passthrough_cmd_decoder))); | 
|  | basic_info.Append( | 
|  | display::BuildGpuInfoEntry("Sandboxed", base::Value(gpu_info.sandboxed))); | 
|  | basic_info.Append( | 
|  | display::BuildGpuInfoEntry("GPU0", GPUDeviceToString(gpu_info.gpu))); | 
|  | for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) { | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | base::StringPrintf("GPU%d", static_cast<int>(i + 1)), | 
|  | GPUDeviceToString(gpu_info.secondary_gpus[i]))); | 
|  | } | 
|  | for (size_t i = 0; i < gpu_info.npus.size(); ++i) { | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | base::StringPrintf("NPU%d", static_cast<int>(i)), | 
|  | GPUDeviceToString(gpu_info.npus[i]))); | 
|  | } | 
|  | basic_info.Append( | 
|  | display::BuildGpuInfoEntry("Optimus", base::Value(gpu_info.optimus))); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "AMD switchable", base::Value(gpu_info.amd_switchable))); | 
|  | #if BUILDFLAG(IS_WIN) | 
|  | basic_info.Append( | 
|  | display::BuildGpuInfoEntry("Desktop compositing", "Aero Glass")); | 
|  |  | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "Direct composition", | 
|  | base::Value(gpu_info.overlay_info.direct_composition))); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "Supports overlays", | 
|  | base::Value(gpu_info.overlay_info.supports_overlays))); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "YUY2 overlay support", | 
|  | gpu::OverlaySupportToString(gpu_info.overlay_info.yuy2_overlay_support))); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "NV12 overlay support", | 
|  | gpu::OverlaySupportToString(gpu_info.overlay_info.nv12_overlay_support))); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "BGRA8 overlay support", | 
|  | gpu::OverlaySupportToString( | 
|  | gpu_info.overlay_info.bgra8_overlay_support))); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "RGB10A2 overlay support", | 
|  | gpu::OverlaySupportToString( | 
|  | gpu_info.overlay_info.rgb10a2_overlay_support))); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "P010 overlay support", | 
|  | gpu::OverlaySupportToString(gpu_info.overlay_info.p010_overlay_support))); | 
|  |  | 
|  | std::vector<gfx::PhysicalDisplaySize> display_sizes = | 
|  | gfx::GetPhysicalSizeForDisplays(); | 
|  | for (const auto& display_size : display_sizes) { | 
|  | const int w = display_size.width_mm; | 
|  | const int h = display_size.height_mm; | 
|  | const double size_mm = sqrt(w * w + h * h); | 
|  | const double size_inches = 0.0393701 * size_mm; | 
|  | const double rounded_size_inches = floor(10.0 * size_inches) / 10.0; | 
|  | std::string size_string = base::StringPrintf("%.1f\"", rounded_size_inches); | 
|  | std::string description_string = base::StringPrintf( | 
|  | "Diagonal Monitor Size of %s", display_size.display_name.c_str()); | 
|  | basic_info.Append( | 
|  | display::BuildGpuInfoEntry(description_string, size_string)); | 
|  | } | 
|  |  | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "DirectML feature level", | 
|  | gpu::DirectMLFeatureLevelToString(gpu_info.directml_feature_level))); | 
|  |  | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "Driver D3D12 feature level", | 
|  | gpu::D3DFeatureLevelToString(gpu_info.d3d12_feature_level))); | 
|  |  | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "Driver Vulkan API version", | 
|  | gpu::VulkanVersionToString(gpu_info.vulkan_version))); | 
|  | #endif | 
|  |  | 
|  | basic_info.Append(display::BuildGpuInfoEntry("Pixel shader version", | 
|  | gpu_info.pixel_shader_version)); | 
|  | basic_info.Append(display::BuildGpuInfoEntry("Vertex shader version", | 
|  | gpu_info.vertex_shader_version)); | 
|  | basic_info.Append(display::BuildGpuInfoEntry("Max. MSAA samples", | 
|  | gpu_info.max_msaa_samples)); | 
|  | basic_info.Append(display::BuildGpuInfoEntry("Machine model name", | 
|  | gpu_info.machine_model_name)); | 
|  | basic_info.Append(display::BuildGpuInfoEntry("Machine model version", | 
|  | gpu_info.machine_model_version)); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "GL implementation parts", gpu_info.gl_implementation_parts.ToString())); | 
|  | basic_info.Append( | 
|  | display::BuildGpuInfoEntry("Display type", gpu_info.display_type)); | 
|  | basic_info.Append( | 
|  | display::BuildGpuInfoEntry("GL_VENDOR", gpu_info.gl_vendor)); | 
|  | basic_info.Append( | 
|  | display::BuildGpuInfoEntry("GL_RENDERER", gpu_info.gl_renderer)); | 
|  | basic_info.Append( | 
|  | display::BuildGpuInfoEntry("GL_VERSION", gpu_info.gl_version)); | 
|  | basic_info.Append( | 
|  | display::BuildGpuInfoEntry("GL_EXTENSIONS", gpu_info.gl_extensions)); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "Disabled Extensions", gpu_feature_info.disabled_extensions)); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "Disabled WebGL Extensions", gpu_feature_info.disabled_webgl_extensions)); | 
|  | basic_info.Append(display::BuildGpuInfoEntry("Window system binding vendor", | 
|  | gpu_info.gl_ws_vendor)); | 
|  | basic_info.Append(display::BuildGpuInfoEntry("Window system binding version", | 
|  | gpu_info.gl_ws_version)); | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "Window system binding extensions", gpu_info.gl_ws_extensions)); | 
|  |  | 
|  | { | 
|  | base::Value::List gpu_extra_info_values = | 
|  | display::Screen::Get()->GetGpuExtraInfo(gpu_extra_info); | 
|  | for (auto& pair : gpu_extra_info_values) { | 
|  | if (!pair.GetDict().FindString("description") || | 
|  | !pair.GetDict().contains("value")) { | 
|  | LOG(WARNING) << "Unexpected item format: should have a string " | 
|  | << "description and a value."; | 
|  | } | 
|  | basic_info.Append(base::Value(std::move(pair))); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::string direct_rendering_version; | 
|  | if (gpu_info.direct_rendering_version == "1") { | 
|  | direct_rendering_version = "indirect"; | 
|  | } else if (gpu_info.direct_rendering_version == "2") { | 
|  | direct_rendering_version = "direct but version unknown"; | 
|  | } else if (base::StartsWith(gpu_info.direct_rendering_version, "2.", | 
|  | base::CompareCase::INSENSITIVE_ASCII)) { | 
|  | direct_rendering_version = gpu_info.direct_rendering_version; | 
|  | base::ReplaceFirstSubstringAfterOffset(&direct_rendering_version, 0, "2.", | 
|  | "DRI"); | 
|  | } else { | 
|  | direct_rendering_version = "unknown"; | 
|  | } | 
|  | basic_info.Append(display::BuildGpuInfoEntry("Direct rendering version", | 
|  | direct_rendering_version)); | 
|  |  | 
|  | std::string reset_strategy = | 
|  | base::StringPrintf("0x%04x", gpu_info.gl_reset_notification_strategy); | 
|  | basic_info.Append(display::BuildGpuInfoEntry("Reset notification strategy", | 
|  | reset_strategy)); | 
|  |  | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "GPU process crash count", | 
|  | base::Value(GpuProcessHost::GetGpuCrashCount()))); | 
|  |  | 
|  | std::string buffer_formats; | 
|  | for (int i = 0; i <= static_cast<int>(gfx::BufferFormat::LAST); ++i) { | 
|  | const gfx::BufferFormat buffer_format = static_cast<gfx::BufferFormat>(i); | 
|  | if (i > 0) | 
|  | buffer_formats += ",  "; | 
|  | buffer_formats += gfx::BufferFormatToString(buffer_format); | 
|  | const bool supported = base::Contains( | 
|  | gpu_feature_info.supported_buffer_formats_for_allocation_and_texturing, | 
|  | buffer_format); | 
|  | buffer_formats += supported ? ": supported" : ": not supported"; | 
|  | } | 
|  | basic_info.Append(display::BuildGpuInfoEntry( | 
|  | "gfx::BufferFormats supported for allocation and texturing", | 
|  | buffer_formats)); | 
|  |  | 
|  | return basic_info; | 
|  | } | 
|  |  | 
|  | base::Value::Dict GetGpuInfo() { | 
|  | base::Value::Dict info; | 
|  |  | 
|  | const gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo(); | 
|  | const gpu::GpuFeatureInfo gpu_feature_info = | 
|  | GpuDataManagerImpl::GetInstance()->GetGpuFeatureInfo(); | 
|  | const gfx::GpuExtraInfo gpu_extra_info = | 
|  | GpuDataManagerImpl::GetInstance()->GetGpuExtraInfo(); | 
|  | base::Value::List basic_info = | 
|  | GetBasicGpuInfo(gpu_info, gpu_feature_info, gpu_extra_info); | 
|  | info.Set("basicInfo", std::move(basic_info)); | 
|  |  | 
|  | #if BUILDFLAG(ENABLE_VULKAN) | 
|  | if (gpu_info.vulkan_info) { | 
|  | auto blob = gpu_info.SerializeVulkanInfo(); | 
|  | info.Set("vulkanInfo", base::Base64Encode(blob)); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | return info; | 
|  | } | 
|  |  | 
|  | base::Value::List CompositorInfo() { | 
|  | base::Value::List compositor_info; | 
|  |  | 
|  | compositor_info.Append(display::BuildGpuInfoEntry( | 
|  | "Tile Update Mode", | 
|  | IsZeroCopyUploadEnabled() ? "Zero-copy" : "One-copy")); | 
|  |  | 
|  | compositor_info.Append(display::BuildGpuInfoEntry( | 
|  | "Partial Raster", IsPartialRasterEnabled() ? "Enabled" : "Disabled")); | 
|  | return compositor_info; | 
|  | } | 
|  |  | 
|  | base::Value::List GpuMemoryBufferInfo(const gfx::GpuExtraInfo& gpu_extra_info) { | 
|  | base::Value::List gpu_memory_buffer_info; | 
|  |  | 
|  | gpu::GpuMemoryBufferConfigurationSet native_config; | 
|  | #if BUILDFLAG(IS_OZONE_X11) | 
|  | if (ui::OzonePlatform::GetInstance() | 
|  | ->GetPlatformProperties() | 
|  | .fetch_buffer_formats_for_gmb_on_gpu) { | 
|  | for (const auto& config : gpu_extra_info.gpu_memory_buffer_support_x11) { | 
|  | native_config.emplace(config); | 
|  | } | 
|  | } | 
|  | #endif  // BUILDFLAG(IS_OZONE_X11) | 
|  | if (native_config.empty()) { | 
|  | native_config = | 
|  | gpu::GpuMemoryBufferSupport::GetNativeGpuMemoryBufferConfigurations(); | 
|  | } | 
|  | for (size_t format = 0; | 
|  | format < static_cast<size_t>(gfx::BufferFormat::LAST) + 1; format++) { | 
|  | std::string native_usage_support; | 
|  | for (size_t usage = 0; | 
|  | usage < static_cast<size_t>(gfx::BufferUsage::LAST) + 1; usage++) { | 
|  | gfx::BufferUsageAndFormat element{static_cast<gfx::BufferUsage>(usage), | 
|  | static_cast<gfx::BufferFormat>(format)}; | 
|  | if (base::Contains(native_config, element)) { | 
|  | native_usage_support = base::StringPrintf( | 
|  | "%s%s %s", native_usage_support.c_str(), | 
|  | native_usage_support.empty() ? "" : ",", | 
|  | gfx::BufferUsageToString(static_cast<gfx::BufferUsage>(usage))); | 
|  | } | 
|  | } | 
|  | if (native_usage_support.empty()) | 
|  | native_usage_support = base::StringPrintf("Software only"); | 
|  |  | 
|  | gpu_memory_buffer_info.Append(display::BuildGpuInfoEntry( | 
|  | gfx::BufferFormatToString(static_cast<gfx::BufferFormat>(format)), | 
|  | native_usage_support)); | 
|  | } | 
|  | return gpu_memory_buffer_info; | 
|  | } | 
|  |  | 
|  | base::Value::List GetDisplayInfo() { | 
|  | base::Value::List display_info; | 
|  | const std::vector<display::Display> displays = | 
|  | display::Screen::Get()->GetAllDisplays(); | 
|  | for (const auto& display : displays) { | 
|  | display_info.Append( | 
|  | display::BuildGpuInfoEntry("Info ", display.ToString())); | 
|  | auto& display_color_spaces = display.GetColorSpaces(); | 
|  | { | 
|  | std::vector<std::string> names; | 
|  | std::vector<gfx::ColorSpace> color_spaces; | 
|  | std::vector<gfx::BufferFormat> buffer_formats; | 
|  | display_color_spaces.ToStrings(&names, &color_spaces, &buffer_formats); | 
|  | for (size_t i = 0; i < names.size(); ++i) { | 
|  | display_info.Append(display::BuildGpuInfoEntry( | 
|  | base::StringPrintf("Color space (%s)", names[i].c_str()), | 
|  | color_spaces[i] | 
|  | .GetWithSdrWhiteLevel( | 
|  | display_color_spaces.GetSDRMaxLuminanceNits()) | 
|  | .ToString())); | 
|  | display_info.Append(display::BuildGpuInfoEntry( | 
|  | base::StringPrintf("Buffer format (%s)", names[i].c_str()), | 
|  | gfx::BufferFormatToString(buffer_formats[i]))); | 
|  | } | 
|  | } | 
|  | display_info.Append(display::BuildGpuInfoEntry( | 
|  | "Color volume", skia::SkColorSpacePrimariesToString( | 
|  | display_color_spaces.GetPrimaries()))); | 
|  | display_info.Append(display::BuildGpuInfoEntry( | 
|  | "SDR white level in nits", | 
|  | base::NumberToString(display_color_spaces.GetSDRMaxLuminanceNits()))); | 
|  | display_info.Append(display::BuildGpuInfoEntry( | 
|  | "HDR relative maximum luminance", | 
|  | base::NumberToString( | 
|  | display_color_spaces.GetHDRMaxLuminanceRelative()))); | 
|  | display_info.Append(display::BuildGpuInfoEntry( | 
|  | "Bits per color component", | 
|  | base::NumberToString(display.depth_per_component()))); | 
|  | display_info.Append(display::BuildGpuInfoEntry( | 
|  | "Bits per pixel", base::NumberToString(display.color_depth()))); | 
|  | if (display.display_frequency()) { | 
|  | display_info.Append(display::BuildGpuInfoEntry( | 
|  | "Refresh Rate in Hz", | 
|  | base::NumberToString(display.display_frequency()))); | 
|  | } | 
|  | } | 
|  | return display_info; | 
|  | } | 
|  |  | 
|  | #if BUILDFLAG(IS_WIN) | 
|  | const char* D3dFeatureLevelToString(D3D_FEATURE_LEVEL level) { | 
|  | switch (level) { | 
|  | case D3D_FEATURE_LEVEL_1_0_CORE: | 
|  | return "Unknown"; | 
|  | case D3D_FEATURE_LEVEL_9_1: | 
|  | return "9_1"; | 
|  | case D3D_FEATURE_LEVEL_9_2: | 
|  | return "9_2"; | 
|  | case D3D_FEATURE_LEVEL_9_3: | 
|  | return "9_3"; | 
|  | case D3D_FEATURE_LEVEL_10_0: | 
|  | return "10_0"; | 
|  | case D3D_FEATURE_LEVEL_10_1: | 
|  | return "10_1"; | 
|  | case D3D_FEATURE_LEVEL_11_0: | 
|  | return "11_0"; | 
|  | case D3D_FEATURE_LEVEL_11_1: | 
|  | return "11_1"; | 
|  | case D3D_FEATURE_LEVEL_12_0: | 
|  | return "12_0"; | 
|  | case D3D_FEATURE_LEVEL_12_1: | 
|  | return "12_1"; | 
|  | case D3D_FEATURE_LEVEL_12_2: | 
|  | return "12_2"; | 
|  | default: | 
|  | NOTREACHED(); | 
|  | } | 
|  | } | 
|  |  | 
|  | const char* HasDiscreteGpuToString(gpu::HasDiscreteGpu has_discrete_gpu) { | 
|  | switch (has_discrete_gpu) { | 
|  | case gpu::HasDiscreteGpu::kUnknown: | 
|  | return "unknown"; | 
|  | case gpu::HasDiscreteGpu::kNo: | 
|  | return "no"; | 
|  | case gpu::HasDiscreteGpu::kYes: | 
|  | return "yes"; | 
|  | } | 
|  | NOTREACHED(); | 
|  | } | 
|  | #endif  // BUILDFLAG(IS_WIN) | 
|  |  | 
|  | base::Value::List GetDevicePerfInfo() { | 
|  | base::Value::List list; | 
|  | const std::optional<gpu::DevicePerfInfo> device_perf_info = | 
|  | gpu::GetDevicePerfInfo(); | 
|  | if (device_perf_info.has_value()) { | 
|  | list.Append(display::BuildGpuInfoEntry( | 
|  | "Total Physical Memory (Gb)", | 
|  | base::NumberToString(device_perf_info->total_physical_memory_mb / | 
|  | 1024))); | 
|  | list.Append(display::BuildGpuInfoEntry( | 
|  | "Total Disk Space (Gb)", | 
|  | base::NumberToString(device_perf_info->total_disk_space_mb / 1024))); | 
|  | list.Append(display::BuildGpuInfoEntry( | 
|  | "Hardware Concurrency", | 
|  | base::NumberToString(device_perf_info->hardware_concurrency))); | 
|  |  | 
|  | #if BUILDFLAG(IS_WIN) | 
|  | list.Append(display::BuildGpuInfoEntry( | 
|  | "System Commit Limit (Gb)", | 
|  | base::NumberToString(device_perf_info->system_commit_limit_mb / 1024))); | 
|  | list.Append(display::BuildGpuInfoEntry( | 
|  | "D3D11 Feature Level", | 
|  | D3dFeatureLevelToString(device_perf_info->d3d11_feature_level))); | 
|  | list.Append(display::BuildGpuInfoEntry( | 
|  | "Has Discrete GPU", | 
|  | HasDiscreteGpuToString(device_perf_info->has_discrete_gpu))); | 
|  | #endif  // BUILDFLAG(IS_WIN) | 
|  |  | 
|  | if (device_perf_info->intel_gpu_generation != | 
|  | gpu::IntelGpuGeneration::kNonIntel) { | 
|  | std::string intel_gpu_gen; | 
|  | if (device_perf_info->intel_gpu_generation == | 
|  | gpu::IntelGpuGeneration::kUnknownIntel) { | 
|  | intel_gpu_gen = "unknown"; | 
|  | } else { | 
|  | intel_gpu_gen = base::NumberToString( | 
|  | static_cast<int>(device_perf_info->intel_gpu_generation)); | 
|  | } | 
|  | list.Append( | 
|  | display::BuildGpuInfoEntry("Intel GPU Generation", intel_gpu_gen)); | 
|  | } | 
|  | list.Append(display::BuildGpuInfoEntry( | 
|  | "Software Rendering", | 
|  | device_perf_info->software_rendering ? "Yes" : "No")); | 
|  | } | 
|  | return list; | 
|  | } | 
|  |  | 
|  | const char* GetProfileName(gpu::VideoCodecProfile profile) { | 
|  | switch (profile) { | 
|  | case gpu::VIDEO_CODEC_PROFILE_UNKNOWN: | 
|  | return "unknown"; | 
|  | case gpu::H264PROFILE_BASELINE: | 
|  | return "h264 baseline"; | 
|  | case gpu::H264PROFILE_MAIN: | 
|  | return "h264 main"; | 
|  | case gpu::H264PROFILE_EXTENDED: | 
|  | return "h264 extended"; | 
|  | case gpu::H264PROFILE_HIGH: | 
|  | return "h264 high"; | 
|  | case gpu::H264PROFILE_HIGH10PROFILE: | 
|  | return "h264 high 10"; | 
|  | case gpu::H264PROFILE_HIGH422PROFILE: | 
|  | return "h264 high 4:2:2"; | 
|  | case gpu::H264PROFILE_HIGH444PREDICTIVEPROFILE: | 
|  | return "h264 high 4:4:4 predictive"; | 
|  | case gpu::H264PROFILE_SCALABLEBASELINE: | 
|  | return "h264 scalable baseline"; | 
|  | case gpu::H264PROFILE_SCALABLEHIGH: | 
|  | return "h264 scalable high"; | 
|  | case gpu::H264PROFILE_STEREOHIGH: | 
|  | return "h264 stereo high"; | 
|  | case gpu::H264PROFILE_MULTIVIEWHIGH: | 
|  | return "h264 multiview high"; | 
|  | case gpu::HEVCPROFILE_MAIN: | 
|  | return "hevc main"; | 
|  | case gpu::HEVCPROFILE_MAIN10: | 
|  | return "hevc main 10"; | 
|  | case gpu::HEVCPROFILE_MAIN_STILL_PICTURE: | 
|  | return "hevc main still-picture"; | 
|  | case gpu::HEVCPROFILE_REXT: | 
|  | return "hevc range extensions"; | 
|  | case gpu::HEVCPROFILE_HIGH_THROUGHPUT: | 
|  | return "hevc high throughput"; | 
|  | case gpu::HEVCPROFILE_MULTIVIEW_MAIN: | 
|  | return "hevc multiview main"; | 
|  | case gpu::HEVCPROFILE_SCALABLE_MAIN: | 
|  | return "hevc scalable main"; | 
|  | case gpu::HEVCPROFILE_3D_MAIN: | 
|  | return "hevc 3d main"; | 
|  | case gpu::HEVCPROFILE_SCREEN_EXTENDED: | 
|  | return "hevc screen extended"; | 
|  | case gpu::HEVCPROFILE_SCALABLE_REXT: | 
|  | return "hevc scalable range extensions"; | 
|  | case gpu::HEVCPROFILE_HIGH_THROUGHPUT_SCREEN_EXTENDED: | 
|  | return "hevc high throughput screen extended"; | 
|  | case gpu::VP8PROFILE_ANY: | 
|  | return "vp8"; | 
|  | case gpu::VP9PROFILE_PROFILE0: | 
|  | return "vp9 profile0"; | 
|  | case gpu::VP9PROFILE_PROFILE1: | 
|  | return "vp9 profile1"; | 
|  | case gpu::VP9PROFILE_PROFILE2: | 
|  | return "vp9 profile2"; | 
|  | case gpu::VP9PROFILE_PROFILE3: | 
|  | return "vp9 profile3"; | 
|  | case gpu::DOLBYVISION_PROFILE0: | 
|  | return "dolby vision profile 0"; | 
|  | case gpu::DOLBYVISION_PROFILE5: | 
|  | return "dolby vision profile 5"; | 
|  | case gpu::DOLBYVISION_PROFILE7: | 
|  | return "dolby vision profile 7"; | 
|  | case gpu::DOLBYVISION_PROFILE8: | 
|  | return "dolby vision profile 8"; | 
|  | case gpu::DOLBYVISION_PROFILE9: | 
|  | return "dolby vision profile 9"; | 
|  | case gpu::THEORAPROFILE_ANY: | 
|  | return "theora"; | 
|  | case gpu::AV1PROFILE_PROFILE_MAIN: | 
|  | return "av1 profile main"; | 
|  | case gpu::AV1PROFILE_PROFILE_HIGH: | 
|  | return "av1 profile high"; | 
|  | case gpu::AV1PROFILE_PROFILE_PRO: | 
|  | return "av1 profile pro"; | 
|  | case gpu::VVCPROFILE_MAIN10: | 
|  | return "vvc profile main10"; | 
|  | case gpu::VVCPROFILE_MAIN12: | 
|  | return "vvc profile main12"; | 
|  | case gpu::VVCPROFILE_MAIN12_INTRA: | 
|  | return "vvc profile main12 intra"; | 
|  | case gpu::VVCPROIFLE_MULTILAYER_MAIN10: | 
|  | return "vvc profile multilayer main10"; | 
|  | case gpu::VVCPROFILE_MAIN10_444: | 
|  | return "vvc profile main10 444"; | 
|  | case gpu::VVCPROFILE_MAIN12_444: | 
|  | return "vvc profile main12 444"; | 
|  | case gpu::VVCPROFILE_MAIN16_444: | 
|  | return "vvc profile main16 444"; | 
|  | case gpu::VVCPROFILE_MAIN12_444_INTRA: | 
|  | return "vvc profile main12 444 intra"; | 
|  | case gpu::VVCPROFILE_MAIN16_444_INTRA: | 
|  | return "vvc profile main16 444 intra"; | 
|  | case gpu::VVCPROFILE_MULTILAYER_MAIN10_444: | 
|  | return "vvc profile multilayer main10 444"; | 
|  | case gpu::VVCPROFILE_MAIN10_STILL_PICTURE: | 
|  | return "vvc profile main10 stillpicture"; | 
|  | case gpu::VVCPROFILE_MAIN12_STILL_PICTURE: | 
|  | return "vvc profile main12 stillpicture"; | 
|  | case gpu::VVCPROFILE_MAIN10_444_STILL_PICTURE: | 
|  | return "vvc profile main10 444 stillpicture"; | 
|  | case gpu::VVCPROFILE_MAIN12_444_STILL_PICTURE: | 
|  | return "vvc profile main12 444 stillpicture"; | 
|  | case gpu::VVCPROFILE_MAIN16_444_STILL_PICTURE: | 
|  | return "vvc profile main16 444 stillpicture"; | 
|  | } | 
|  | NOTREACHED(); | 
|  | } | 
|  |  | 
|  | base::Value::List GetVideoAcceleratorsInfo() { | 
|  | gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo(); | 
|  | base::Value::List info; | 
|  |  | 
|  | struct { | 
|  | const raw_ref<const gpu::VideoDecodeAcceleratorSupportedProfiles> | 
|  | capabilities; | 
|  | std::string name; | 
|  | } kVideoDecoderImplementations[] = { | 
|  | {raw_ref(gpu_info.video_decode_accelerator_supported_profiles), | 
|  | "Decoding"}, | 
|  | }; | 
|  |  | 
|  | info.Append(display::BuildGpuInfoEntry("Decoding", "")); | 
|  | for (const auto& profile : | 
|  | gpu_info.video_decode_accelerator_supported_profiles) { | 
|  | std::string codec_string = | 
|  | base::StringPrintf("Decode %s", GetProfileName(profile.profile)); | 
|  | std::string resolution_string = base::StringPrintf( | 
|  | "%s to %s pixels%s", profile.min_resolution.ToString().c_str(), | 
|  | profile.max_resolution.ToString().c_str(), | 
|  | profile.encrypted_only ? " (encrypted)" : ""); | 
|  | info.Append(display::BuildGpuInfoEntry(codec_string, resolution_string)); | 
|  | } | 
|  |  | 
|  | info.Append(display::BuildGpuInfoEntry("Encoding", "")); | 
|  | for (const auto& profile : | 
|  | gpu_info.video_encode_accelerator_supported_profiles) { | 
|  | std::string codec_string = | 
|  | base::StringPrintf("Encode %s", GetProfileName(profile.profile)); | 
|  | std::string resolution_string = base::StringPrintf( | 
|  | "%s to %s pixels, and/or %.3f fps%s.", | 
|  | profile.min_resolution.ToString().c_str(), | 
|  | profile.max_resolution.ToString().c_str(), | 
|  | static_cast<double>(profile.max_framerate_numerator) / | 
|  | profile.max_framerate_denominator, | 
|  | profile.is_software_codec ? " (software codec)" : ""); | 
|  | info.Append(display::BuildGpuInfoEntry(codec_string, resolution_string)); | 
|  | } | 
|  | return info; | 
|  | } | 
|  |  | 
|  | base::Value GetANGLEFeatures() { | 
|  | gfx::GpuExtraInfo gpu_extra_info = | 
|  | GpuDataManagerImpl::GetInstance()->GetGpuExtraInfo(); | 
|  | base::Value::List angle_features_list; | 
|  | for (const auto& feature : gpu_extra_info.angle_features) { | 
|  | base::Value::Dict angle_feature; | 
|  | angle_feature.Set("name", feature.name); | 
|  | angle_feature.Set("category", feature.category); | 
|  | angle_feature.Set("status", feature.status); | 
|  | angle_features_list.Append(std::move(angle_feature)); | 
|  | } | 
|  |  | 
|  | return base::Value(std::move(angle_features_list)); | 
|  | } | 
|  |  | 
|  | base::Value GetDawnInfo() { | 
|  | const std::vector<std::string> info_list_collected = | 
|  | GpuDataManagerImpl::GetInstance()->GetDawnInfoList(); | 
|  | base::Value::List dawn_info_list; | 
|  |  | 
|  | for (const auto& info : info_list_collected) { | 
|  | dawn_info_list.Append(info); | 
|  | } | 
|  |  | 
|  | return base::Value(std::move(dawn_info_list)); | 
|  | } | 
|  |  | 
|  | // This class receives javascript messages from the renderer. | 
|  | // Note that the WebUI infrastructure runs on the UI thread, therefore all of | 
|  | // this class's methods are expected to run on the UI thread. | 
|  | class GpuMessageHandler | 
|  | : public WebUIMessageHandler, | 
|  | public GpuDataManagerObserver, | 
|  | public ui::GpuSwitchingObserver { | 
|  | public: | 
|  | GpuMessageHandler(); | 
|  |  | 
|  | GpuMessageHandler(const GpuMessageHandler&) = delete; | 
|  | GpuMessageHandler& operator=(const GpuMessageHandler&) = delete; | 
|  |  | 
|  | ~GpuMessageHandler() override; | 
|  |  | 
|  | // WebUIMessageHandler implementation. | 
|  | void RegisterMessages() override; | 
|  | void OnJavascriptAllowed() override; | 
|  | void OnJavascriptDisallowed() override; | 
|  |  | 
|  | // GpuDataManagerObserver implementation. | 
|  | void OnGpuInfoUpdate() override; | 
|  |  | 
|  | // Messages | 
|  | void HandleGetGpuInfo(const base::Value::List& list); | 
|  | void HandleGetClientInfo(const base::Value::List& list); | 
|  | void HandleGetLogMessages(const base::Value::List& list); | 
|  |  | 
|  | base::Value::Dict GetClientInfo(); | 
|  | base::Value::List GetLogMessages(); | 
|  | base::Value::Dict GetGpuInfoDict(); | 
|  | }; | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // | 
|  | // GpuMessageHandler | 
|  | // | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | GpuMessageHandler::GpuMessageHandler() = default; | 
|  |  | 
|  | GpuMessageHandler::~GpuMessageHandler() { | 
|  | OnJavascriptDisallowed(); | 
|  | } | 
|  |  | 
|  | /* BrowserBridge.callAsync prepends a requestID to these messages. */ | 
|  | void GpuMessageHandler::RegisterMessages() { | 
|  | DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
|  |  | 
|  | web_ui()->RegisterMessageCallback( | 
|  | "getGpuInfo", base::BindRepeating(&GpuMessageHandler::HandleGetGpuInfo, | 
|  | base::Unretained(this))); | 
|  | web_ui()->RegisterMessageCallback( | 
|  | "getClientInfo", | 
|  | base::BindRepeating(&GpuMessageHandler::HandleGetClientInfo, | 
|  | base::Unretained(this))); | 
|  | web_ui()->RegisterMessageCallback( | 
|  | "getLogMessages", | 
|  | base::BindRepeating(&GpuMessageHandler::HandleGetLogMessages, | 
|  | base::Unretained(this))); | 
|  | } | 
|  |  | 
|  | void GpuMessageHandler::OnJavascriptAllowed() { | 
|  | GpuDataManagerImpl::GetInstance()->AddObserver(this); | 
|  | } | 
|  |  | 
|  | void GpuMessageHandler::OnJavascriptDisallowed() { | 
|  | GpuDataManagerImpl::GetInstance()->RemoveObserver(this); | 
|  | } | 
|  |  | 
|  | void GpuMessageHandler::HandleGetClientInfo(const base::Value::List& args) { | 
|  | CHECK_EQ(1U, args.size()); | 
|  | AllowJavascript(); | 
|  | const base::Value& callback_id = args[0]; | 
|  | ResolveJavascriptCallback(callback_id, GetClientInfo()); | 
|  | } | 
|  |  | 
|  | void GpuMessageHandler::HandleGetLogMessages(const base::Value::List& args) { | 
|  | CHECK_EQ(1U, args.size()); | 
|  | AllowJavascript(); | 
|  | const base::Value& callback_id = args[0]; | 
|  | ResolveJavascriptCallback(callback_id, GetLogMessages()); | 
|  | } | 
|  |  | 
|  | void GpuMessageHandler::HandleGetGpuInfo(const base::Value::List& args) { | 
|  | CHECK_EQ(1U, args.size()); | 
|  | DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
|  | AllowJavascript(); | 
|  |  | 
|  | // Tell GpuDataManager it should have full GpuInfo. If the | 
|  | // Gpu process has not run yet, this will trigger its launch. | 
|  | GpuDataManagerImpl::GetInstance()->RequestDx12VulkanVideoGpuInfoIfNeeded( | 
|  | GpuDataManagerImpl::kGpuInfoRequestAll, | 
|  | /*delayed=*/false); | 
|  |  | 
|  | // Send current snapshot of gpu info. Any future updates will be communicated | 
|  | // via the OnGpuInfoUpdate() callback. | 
|  | const base::Value& callback_id = args[0]; | 
|  | ResolveJavascriptCallback(callback_id, GetGpuInfoDict()); | 
|  | } | 
|  |  | 
|  | base::Value::Dict GpuMessageHandler::GetClientInfo() { | 
|  | DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
|  |  | 
|  | base::Value::Dict dict; | 
|  |  | 
|  | dict.Set("version", GetContentClient()->browser()->GetProduct()); | 
|  | base::CommandLine::StringType command_line = | 
|  | base::CommandLine::ForCurrentProcess()->GetCommandLineString(); | 
|  | #if BUILDFLAG(IS_WIN) | 
|  | dict.Set("command_line", base::WideToUTF8(command_line)); | 
|  | #else | 
|  | dict.Set("command_line", command_line); | 
|  | #endif | 
|  | #if BUILDFLAG(IS_WIN) | 
|  | const base::win::OSInfo& os_info = *base::win::OSInfo::GetInstance(); | 
|  | const base::win::OSInfo::VersionNumber os_version = os_info.version_number(); | 
|  | base::win::OSInfo::VersionNumber kernel32_version = | 
|  | os_info.Kernel32VersionNumber(); | 
|  | dict.Set( | 
|  | "operating_system", | 
|  | base::StringPrintf("%s %u.%u.%u.%u (kernel32 %u.%u.%u.%u)", | 
|  | base::SysInfo::OperatingSystemName(), os_version.major, | 
|  | os_version.minor, os_version.build, os_version.patch, | 
|  | kernel32_version.major, kernel32_version.minor, | 
|  | kernel32_version.build, kernel32_version.patch)); | 
|  | #elif BUILDFLAG(IS_ANDROID) | 
|  | dict.Set("operating_system", | 
|  | base::StringPrintf("%s %s %s", base::SysInfo::OperatingSystemName(), | 
|  | base::SysInfo::OperatingSystemVersion(), | 
|  | base::SysInfo::GetAndroidBuildID())); | 
|  |  | 
|  | #else | 
|  | dict.Set("operating_system", base::SysInfo::OperatingSystemName() + " " + | 
|  | base::SysInfo::OperatingSystemVersion()); | 
|  | #endif | 
|  | dict.Set("angle_commit_id", angle::GetANGLECommitHash()); | 
|  | dict.Set("graphics_backend", | 
|  | std::string("Skia/" STRINGIZE(SK_MILESTONE) " " SKIA_COMMIT_HASH)); | 
|  | dict.Set("revision_identifier", GPU_LISTS_VERSION); | 
|  |  | 
|  | return dict; | 
|  | } | 
|  |  | 
|  | base::Value::List GpuMessageHandler::GetLogMessages() { | 
|  | DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
|  |  | 
|  | return GpuDataManagerImpl::GetInstance()->GetLogMessages(); | 
|  | } | 
|  |  | 
|  | base::Value::Dict GpuMessageHandler::GetGpuInfoDict() { | 
|  | // Get GPU Info. | 
|  | const gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo(); | 
|  | const gfx::GpuExtraInfo gpu_extra_info = | 
|  | GpuDataManagerImpl::GetInstance()->GetGpuExtraInfo(); | 
|  | base::Value::Dict gpu_info_val = GetGpuInfo(); | 
|  |  | 
|  | // Add in blocklisting features | 
|  | base::Value::Dict feature_status; | 
|  | feature_status.Set("featureStatus", GetFeatureStatus()); | 
|  | feature_status.Set("problems", GetProblems()); | 
|  | base::Value::List workarounds; | 
|  | for (const auto& workaround : GetDriverBugWorkarounds()) | 
|  | workarounds.Append(workaround); | 
|  | feature_status.Set("workarounds", std::move(workarounds)); | 
|  | gpu_info_val.Set("featureStatus", std::move(feature_status)); | 
|  | if (!GpuDataManagerImpl::GetInstance()->IsGpuProcessUsingHardwareGpu()) { | 
|  | const gpu::GPUInfo gpu_info_for_hardware_gpu = | 
|  | GpuDataManagerImpl::GetInstance()->GetGPUInfoForHardwareGpu(); | 
|  | if (gpu_info_for_hardware_gpu.IsInitialized()) { | 
|  | base::Value::Dict feature_status_for_hardware_gpu; | 
|  | feature_status_for_hardware_gpu.Set("featureStatus", | 
|  | GetFeatureStatusForHardwareGpu()); | 
|  | feature_status_for_hardware_gpu.Set("problems", | 
|  | GetProblemsForHardwareGpu()); | 
|  | base::Value::List workarounds_for_hardware_gpu; | 
|  | for (const auto& workaround : GetDriverBugWorkaroundsForHardwareGpu()) | 
|  | workarounds_for_hardware_gpu.Append(workaround); | 
|  | feature_status_for_hardware_gpu.Set( | 
|  | "workarounds", std::move(workarounds_for_hardware_gpu)); | 
|  | gpu_info_val.Set("featureStatusForHardwareGpu", | 
|  | std::move(feature_status_for_hardware_gpu)); | 
|  | const gpu::GpuFeatureInfo gpu_feature_info_for_hardware_gpu = | 
|  | GpuDataManagerImpl::GetInstance()->GetGpuFeatureInfoForHardwareGpu(); | 
|  | base::Value::List gpu_info_for_hardware_gpu_val = GetBasicGpuInfo( | 
|  | gpu_info_for_hardware_gpu, gpu_feature_info_for_hardware_gpu, | 
|  | gfx::GpuExtraInfo{}); | 
|  | gpu_info_val.Set("basicInfoForHardwareGpu", | 
|  | std::move(gpu_info_for_hardware_gpu_val)); | 
|  | } | 
|  | } | 
|  | gpu_info_val.Set("compositorInfo", CompositorInfo()); | 
|  | gpu_info_val.Set("gpuMemoryBufferInfo", GpuMemoryBufferInfo(gpu_extra_info)); | 
|  | gpu_info_val.Set("displayInfo", GetDisplayInfo()); | 
|  | gpu_info_val.Set("videoAcceleratorsInfo", GetVideoAcceleratorsInfo()); | 
|  | gpu_info_val.Set("ANGLEFeatures", GetANGLEFeatures()); | 
|  | gpu_info_val.Set("devicePerfInfo", GetDevicePerfInfo()); | 
|  | gpu_info_val.Set("dawnInfo", GetDawnInfo()); | 
|  |  | 
|  | return gpu_info_val; | 
|  | } | 
|  |  | 
|  | void GpuMessageHandler::OnGpuInfoUpdate() { | 
|  | FireWebUIListener("gpu-info-updated", GetGpuInfoDict()); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // | 
|  | // GpuInternalsUI | 
|  | // | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | GpuInternalsUI::GpuInternalsUI(WebUI* web_ui) | 
|  | : WebUIController(web_ui) { | 
|  | web_ui->AddMessageHandler(std::make_unique<GpuMessageHandler>()); | 
|  |  | 
|  | // Set up the chrome://gpu/ source. | 
|  | CreateAndAddGpuHTMLSource(web_ui->GetWebContents()->GetBrowserContext()); | 
|  | } | 
|  |  | 
|  | }  // namespace content |