blob: fc77d384b66ff5bcbc3dcdb5a7d0df1cf6575734 [file] [log] [blame]
// 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/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_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 "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(base::make_span(kGpuResources, kGpuResourcesSize));
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) {
const gpu::GPUInfo::GPUDevice& active_gpu = gpu_info.active_gpu();
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(
"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])));
}
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)));
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(
"GPU CUDA compute capability major version",
base::Value(active_gpu.cuda_compute_capability_major)));
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::GetScreen()->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.vulkan_info->Serialize();
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::GetScreen()->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].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();
return "";
}
}
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();
return "";
}
#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();
return "";
}
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("description", feature.description);
angle_feature.Set("bug", feature.bug);
angle_feature.Set("status", feature.status);
angle_feature.Set("condition", feature.condition);
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;
// ui::GpuSwitchingObserver implementation.
void OnGpuSwitched(gl::GpuPreference) 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);
ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
}
void GpuMessageHandler::OnJavascriptDisallowed() {
ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
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
dict.Set("operating_system", base::SysInfo::OperatingSystemName() + " " +
base::SysInfo::OperatingSystemVersion());
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());
}
void GpuMessageHandler::OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) {
// Currently, about:gpu page does not update GPU info after the GPU switch.
// If there is something to be updated, the code should be added here.
}
} // 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