#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "content/browser/gpu/gpu_data_manager_impl_private.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include <aclapi.h>
#include <sddl.h>
#endif
#include <array>
#include <iterator>
#include <memory>
#include <utility>
#include "base/command_line.h"
#include "base/debug/dump_without_crashing.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/path_service.h"
#include "base/rand_util.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_util.h"
#include "base/task/bind_post_task.h"
#include "base/trace_event/trace_event.h"
#include "base/version.h"
#include "build/chromecast_buildflags.h"
#include "build/chromeos_buildflags.h"
#include "cc/base/switches.h"
#include "components/viz/common/features.h"
#include "content/browser/gpu/gpu_memory_buffer_manager_singleton.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/media/frameless_media_interface_proxy.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "content/public/browser/gpu_utils.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/command_buffer/service/service_utils.h"
#include "gpu/config/gpu_blocklist.h"
#include "gpu/config/gpu_driver_bug_list.h"
#include "gpu/config/gpu_driver_bug_workaround_type.h"
#include "gpu/config/gpu_feature_info.h"
#include "gpu/config/gpu_feature_type.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_info_collector.h"
#include "gpu/config/gpu_preferences.h"
#include "gpu/config/gpu_switches.h"
#include "gpu/config/gpu_util.h"
#include "gpu/config/software_rendering_list_autogen.h"
#include "gpu/ipc/common/memory_stats.h"
#include "gpu/ipc/host/gpu_disk_cache.h"
#include "gpu/vulkan/buildflags.h"
#include "media/gpu/gpu_video_accelerator_util.h"
#include "media/media_buildflags.h"
#include "media/mojo/clients/mojo_video_decoder.h"
#include "media/mojo/mojom/video_encode_accelerator.mojom.h"
#include "ui/base/ui_base_switches.h"
#include "ui/display/screen.h"
#include "ui/gfx/switches.h"
#include "ui/gl/buildflags.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_switches.h"
#include "ui/gl/gpu_preference.h"
#include "ui/gl/gpu_switching_manager.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/android/application_status_listener.h"
#endif
#if BUILDFLAG(IS_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#endif
#if BUILDFLAG(IS_MAC)
#include <ApplicationServices/ApplicationServices.h>
#endif
#if BUILDFLAG(IS_WIN)
#include "base/base_paths_win.h"
#include "ui/display/win/screen_win.h"
#include "ui/gfx/mojom/dxgi_info.mojom.h"
#endif
#if BUILDFLAG(IS_CASTOS)
#include "chromecast/chromecast_buildflags.h"
#endif
namespace content {
namespace {
bool CanUpdateGmbGpuPreferences() { … }
#if BUILDFLAG(IS_ANDROID)
NOINLINE void FatalGpuProcessLaunchFailureOnBackground() {
if (!base::android::ApplicationStatusListener::HasVisibleActivities()) {
if (base::RandInt(1, 100) == 1)
base::debug::DumpWithoutCrashing();
kill(getpid(), SIGKILL);
}
}
#endif
#if BUILDFLAG(IS_WIN)
bool ValidateFileHandle(HANDLE cache_file_handle,
const base::FilePath& cache_file_path) {
BY_HANDLE_FILE_INFORMATION file_info = {};
if (!::GetFileInformationByHandle(cache_file_handle, &file_info))
return false;
if (file_info.nNumberOfLinks > 1)
return false;
wchar_t final_path_buffer[MAX_PATH];
if (!::GetFinalPathNameByHandle(cache_file_handle, final_path_buffer,
_countof(final_path_buffer),
FILE_NAME_NORMALIZED | VOLUME_NAME_DOS)) {
return false;
}
if (!base::StartsWith(final_path_buffer, L"\\\\?\\",
base::CompareCase::INSENSITIVE_ASCII)) {
return false;
}
return cache_file_path == base::FilePath(&final_path_buffer[4]);
}
bool GetIntelCacheFileNames(std::vector<base::FilePath::StringType>* names) {
DCHECK(names);
DCHECK(names->empty());
base::FilePath module_path;
if (!base::PathService::Get(base::FILE_EXE, &module_path))
return false;
module_path = module_path.BaseName().RemoveExtension();
base::FilePath::StringType module_name = module_path.value();
if (module_name.size() == 0)
return false;
names->push_back(module_name + L"_0");
names->push_back(module_name + L"_1");
names->push_back(module_name + L"_2");
return true;
}
void EnableIntelShaderCache() {
base::FilePath dir;
if (!base::PathService::Get(base::DIR_COMMON_APP_DATA, &dir))
return;
dir = dir.Append(L"Intel").Append(L"ShaderCache");
if (!base::DirectoryExists(dir))
return;
PSECURITY_DESCRIPTOR sd = nullptr;
ULONG sd_length = 0;
BOOL success = ::ConvertStringSecurityDescriptorToSecurityDescriptor(
L"D:(A;;FA;;;AU)(A;;FA;;;BA)(A;;GRGWGX;;;S-1-15-2-1)(A;;GRGWGX;;;S-1-15-"
L"2-2)",
SDDL_REVISION_1, &sd, &sd_length);
if (!success)
return;
DCHECK(sd);
DCHECK_LT(0u, sd_length);
std::unique_ptr<void, decltype(::LocalFree)*> sd_holder(sd, ::LocalFree);
PACL dacl = nullptr;
BOOL present = FALSE, defaulted = FALSE;
success = ::GetSecurityDescriptorDacl(sd, &present, &dacl, &defaulted);
if (!success)
return;
DCHECK(present);
DCHECK(dacl);
DCHECK(!defaulted);
std::vector<base::FilePath::StringType> cache_file_names;
if (!GetIntelCacheFileNames(&cache_file_names))
return;
for (const auto& cache_file_name : cache_file_names) {
base::FilePath cache_file_path = dir.Append(cache_file_name);
HANDLE cache_file_handle = ::CreateFileW(
cache_file_path.value().c_str(), WRITE_DAC,
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, 0, nullptr);
base::win::ScopedHandle handle_holder(cache_file_handle);
if (cache_file_handle == INVALID_HANDLE_VALUE ||
!ValidateFileHandle(cache_file_handle, cache_file_path)) {
continue;
}
DWORD result = ::SetSecurityInfo(cache_file_handle, SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION, nullptr,
nullptr, dacl, nullptr);
if (result != ERROR_SUCCESS) {
LOG(ERROR) << "SetSecurityInfo returned " << result;
}
}
}
#endif
enum class CanvasOopRasterAndGpuAcceleration { … };
void RecordCanvasAcceleratedOopRasterHistogram(
const gpu::GpuFeatureInfo& gpu_feature_info,
bool gpu_compositing_disabled) { … }
void UpdateFeatureStats(const gpu::GpuFeatureInfo& gpu_feature_info) { … }
void UpdateDriverBugListStats(const gpu::GpuFeatureInfo& gpu_feature_info) { … }
#if BUILDFLAG(IS_MAC)
void DisplayReconfigCallback(CGDirectDisplayID display,
CGDisplayChangeSummaryFlags flags,
void* gpu_data_manager) {
if (flags == kCGDisplayBeginConfigurationFlag)
return;
GpuDataManagerImpl* manager =
reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager);
DCHECK(manager);
gpu::GPUInfo info = manager->GetGPUInfo();
gl::GLImplementationParts parts = info.gl_implementation_parts;
if (!(parts.gl == gl::kGLImplementationEGLANGLE &&
parts.angle == gl::ANGLEImplementation::kOpenGL)) {
return;
}
if (!info.amd_switchable) {
return;
}
manager->HandleGpuSwitch();
}
#endif
void OnVideoMemoryUsageStats(
GpuDataManager::VideoMemoryUsageStatsCallback callback,
const gpu::VideoMemoryUsageStats& stats) { … }
void RequestVideoMemoryUsageStats(
GpuDataManager::VideoMemoryUsageStatsCallback callback,
GpuProcessHost* host) { … }
bool SwiftShaderAllowed() { … }
enum class CompositingMode { … };
NOINLINE void IntentionallyCrashBrowserForUnusableGpuProcess() { … }
#if BUILDFLAG(IS_WIN)
void CollectExtraDevicePerfInfo(const gpu::GPUInfo& gpu_info,
gpu::DevicePerfInfo* device_perf_info) {
device_perf_info->intel_gpu_generation = gpu::GetIntelGpuGeneration(gpu_info);
const gpu::GPUInfo::GPUDevice& device = gpu_info.active_gpu();
if (device.vendor_id == 0xffff ||
device.vendor_id == 0x15ad ||
device.vendor_id == 0x1414 ||
gl::IsSoftwareGLImplementation(
gpu_info.gl_implementation_parts) ) {
device_perf_info->software_rendering = true;
}
}
class HDRProxy {
public:
static void Initialize() {
display::win::ScreenWin::SetRequestHDRStatusCallback(
base::BindRepeating(&HDRProxy::RequestHDRStatus));
}
static void RequestHDRStatus() {
auto* gpu_process_host =
GpuProcessHost::Get(GPU_PROCESS_KIND_SANDBOXED, false);
if (gpu_process_host) {
auto* gpu_service = gpu_process_host->gpu_host()->gpu_service();
gpu_service->RequestDXGIInfo(base::BindOnce(&HDRProxy::GotResult));
} else {
GotResult(gfx::mojom::DXGIInfo::New());
}
}
static void GotResult(gfx::mojom::DXGIInfoPtr dxgi_info) {
display::win::ScreenWin::SetDXGIInfo(std::move(dxgi_info));
}
};
#endif
}
GpuDataManagerImplPrivate::GpuDataManagerImplPrivate(GpuDataManagerImpl* owner)
: … { … }
GpuDataManagerImplPrivate::~GpuDataManagerImplPrivate() { … }
void GpuDataManagerImplPrivate::StartUmaTimer() { … }
void GpuDataManagerImplPrivate::InitializeGpuModes() { … }
void GpuDataManagerImplPrivate::BlocklistWebGLForTesting() { … }
void GpuDataManagerImplPrivate::SetSkiaGraphiteEnabledForTesting(bool enabled) { … }
gpu::GPUInfo GpuDataManagerImplPrivate::GetGPUInfo() const { … }
gpu::GPUInfo GpuDataManagerImplPrivate::GetGPUInfoForHardwareGpu() const { … }
std::vector<std::string> GpuDataManagerImplPrivate::GetDawnInfoList() const { … }
bool GpuDataManagerImplPrivate::GpuAccessAllowed(std::string* reason) const { … }
bool GpuDataManagerImplPrivate::GpuAccessAllowedForHardwareGpu(
std::string* reason) const { … }
void GpuDataManagerImplPrivate::RequestDx12VulkanVideoGpuInfoIfNeeded(
GpuDataManagerImpl::GpuInfoRequest request,
bool delayed) { … }
void GpuDataManagerImplPrivate::RequestGpuSupportedDirectXVersion(
bool delayed) { … }
void GpuDataManagerImplPrivate::RequestGpuSupportedVulkanVersion(bool delayed) { … }
void GpuDataManagerImplPrivate::RequestDawnInfo(bool delayed,
bool collect_metrics) { … }
void GpuDataManagerImplPrivate::RequestMojoMediaVideoCapabilities() { … }
bool GpuDataManagerImplPrivate::IsEssentialGpuInfoAvailable() const { … }
bool GpuDataManagerImplPrivate::IsDx12VulkanVersionAvailable() const { … }
bool GpuDataManagerImplPrivate::IsGpuFeatureInfoAvailable() const { … }
gpu::GpuFeatureStatus GpuDataManagerImplPrivate::GetFeatureStatus(
gpu::GpuFeatureType feature) const { … }
void GpuDataManagerImplPrivate::RequestVideoMemoryUsageStatsUpdate(
GpuDataManager::VideoMemoryUsageStatsCallback callback) const { … }
void GpuDataManagerImplPrivate::AddObserver(GpuDataManagerObserver* observer) { … }
void GpuDataManagerImplPrivate::RemoveObserver(
GpuDataManagerObserver* observer) { … }
void GpuDataManagerImplPrivate::UnblockDomainFrom3DAPIs(const GURL& url) { … }
void GpuDataManagerImplPrivate::UpdateGpuInfo(
const gpu::GPUInfo& gpu_info,
const std::optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu) { … }
#if BUILDFLAG(IS_WIN)
void GpuDataManagerImplPrivate::UpdateDirectXInfo(
uint32_t d3d12_feature_level,
uint32_t directml_feature_level) {
gpu_info_.d3d12_feature_level = d3d12_feature_level;
gpu_info_.directml_feature_level = directml_feature_level;
gpu_info_dx_valid_ = true;
}
void GpuDataManagerImplPrivate::UpdateVulkanInfo(uint32_t vulkan_version) {
gpu_info_.vulkan_version = vulkan_version;
gpu_info_vulkan_valid_ = true;
NotifyGpuInfoUpdate();
}
void GpuDataManagerImplPrivate::UpdateDevicePerfInfo(
const gpu::DevicePerfInfo& device_perf_info) {
gpu::DevicePerfInfo mutable_device_perf_info = device_perf_info;
CollectExtraDevicePerfInfo(gpu_info_, &mutable_device_perf_info);
gpu::SetDevicePerfInfo(mutable_device_perf_info);
NotifyGpuInfoUpdate();
}
void GpuDataManagerImplPrivate::UpdateOverlayInfo(
const gpu::OverlayInfo& overlay_info) {
gpu_info_.overlay_info = overlay_info;
NotifyGpuInfoUpdate();
}
void GpuDataManagerImplPrivate::UpdateDXGIInfo(
gfx::mojom::DXGIInfoPtr dxgi_info) {
GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&HDRProxy::GotResult, std::move(dxgi_info)));
}
void GpuDataManagerImplPrivate::UpdateDirectXRequestStatus(
bool request_continues) {
gpu_info_dx_requested_ = true;
gpu_info_dx_request_failed_ = !request_continues;
if (gpu_info_dx_request_failed_) {
gpu::DevicePerfInfo device_perf_info;
gpu::CollectDevicePerfInfo(&device_perf_info, true);
UpdateDevicePerfInfo(device_perf_info);
}
}
void GpuDataManagerImplPrivate::UpdateVulkanRequestStatus(
bool request_continues) {
gpu_info_vulkan_requested_ = true;
gpu_info_vulkan_request_failed_ = !request_continues;
}
bool GpuDataManagerImplPrivate::DirectXRequested() const {
return gpu_info_dx_requested_;
}
bool GpuDataManagerImplPrivate::VulkanRequested() const {
return gpu_info_vulkan_requested_;
}
void GpuDataManagerImplPrivate::TerminateInfoCollectionGpuProcess() {
if (gpu_info_dx_requested_ && !gpu_info_dx_request_failed_ &&
!gpu::GetDevicePerfInfo().has_value()) {
return;
}
if (gpu_info_vulkan_requested_ && !gpu_info_vulkan_request_failed_ &&
!gpu_info_vulkan_valid_)
return;
base::AutoUnlock unlock(owner_->lock_);
GpuProcessHost* host = GpuProcessHost::Get(GPU_PROCESS_KIND_INFO_COLLECTION,
false );
if (host)
host->ForceShutdown();
}
#endif
void GpuDataManagerImplPrivate::PostCreateThreads() { … }
void GpuDataManagerImplPrivate::UpdateDawnInfo(
const std::vector<std::string>& dawn_info_list) { … }
void GpuDataManagerImplPrivate::UpdateGpuFeatureInfo(
const gpu::GpuFeatureInfo& gpu_feature_info,
const std::optional<gpu::GpuFeatureInfo>&
gpu_feature_info_for_hardware_gpu) { … }
void GpuDataManagerImplPrivate::UpdateGpuExtraInfo(
const gfx::GpuExtraInfo& gpu_extra_info) { … }
void GpuDataManagerImplPrivate::UpdateMojoMediaVideoDecoderCapabilities(
const media::SupportedVideoDecoderConfigs& configs) { … }
void GpuDataManagerImplPrivate::UpdateMojoMediaVideoEncoderCapabilities(
const media::VideoEncodeAccelerator::SupportedProfiles& profiles) { … }
gpu::GpuFeatureInfo GpuDataManagerImplPrivate::GetGpuFeatureInfo() const { … }
gpu::GpuFeatureInfo GpuDataManagerImplPrivate::GetGpuFeatureInfoForHardwareGpu()
const { … }
gfx::GpuExtraInfo GpuDataManagerImplPrivate::GetGpuExtraInfo() const { … }
bool GpuDataManagerImplPrivate::IsGpuCompositingDisabled() const { … }
bool GpuDataManagerImplPrivate::IsGpuCompositingDisabledForHardwareGpu() const { … }
void GpuDataManagerImplPrivate::SetGpuCompositingDisabled() { … }
void GpuDataManagerImplPrivate::AppendGpuCommandLine(
base::CommandLine* command_line,
GpuProcessKind kind) const { … }
void GpuDataManagerImplPrivate::UpdateGpuPreferences(
gpu::GpuPreferences* gpu_preferences,
GpuProcessKind kind) const { … }
void GpuDataManagerImplPrivate::DisableHardwareAcceleration() { … }
bool GpuDataManagerImplPrivate::HardwareAccelerationEnabled() const { … }
void GpuDataManagerImplPrivate::OnGpuBlocked() { … }
void GpuDataManagerImplPrivate::AddLogMessage(int level,
const std::string& header,
const std::string& message) { … }
void GpuDataManagerImplPrivate::ProcessCrashed() { … }
base::Value::List GpuDataManagerImplPrivate::GetLogMessages() const { … }
void GpuDataManagerImplPrivate::HandleGpuSwitch() { … }
void GpuDataManagerImplPrivate::OnDisplayAdded(
const display::Display& new_display) { … }
void GpuDataManagerImplPrivate::OnDisplaysRemoved(
const display::Displays& removed_displays) { … }
void GpuDataManagerImplPrivate::OnDisplayMetricsChanged(
const display::Display& display,
uint32_t changed_metrics) { … }
void GpuDataManagerImplPrivate::BlockDomainsFrom3DAPIs(
const std::set<GURL>& urls,
gpu::DomainGuilt guilt) { … }
bool GpuDataManagerImplPrivate::Are3DAPIsBlocked(const GURL& top_origin_url,
ThreeDAPIType requester) { … }
void GpuDataManagerImplPrivate::DisableDomainBlockingFor3DAPIsForTesting() { … }
void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() { … }
bool GpuDataManagerImplPrivate::IsGpuProcessUsingHardwareGpu() const { … }
void GpuDataManagerImplPrivate::SetApplicationVisible(bool is_visible) { … }
std::string GpuDataManagerImplPrivate::GetDomainFromURL(const GURL& url) const { … }
void GpuDataManagerImplPrivate::BlockDomainsFrom3DAPIsAtTime(
const std::set<GURL>& urls,
gpu::DomainGuilt guilt,
base::Time at_time) { … }
static const base::TimeDelta kBlockedDomainExpirationPeriod = …;
void GpuDataManagerImplPrivate::ExpireOldBlockedDomainsAtTime(
base::Time at_time) const { … }
GpuDataManagerImplPrivate::DomainBlockStatus
GpuDataManagerImplPrivate::Are3DAPIsBlockedAtTime(const GURL& url,
base::Time at_time) const { … }
base::TimeDelta GpuDataManagerImplPrivate::GetDomainBlockingExpirationPeriod()
const { … }
gpu::GpuMode GpuDataManagerImplPrivate::GetGpuMode() const { … }
void GpuDataManagerImplPrivate::FallBackToNextGpuMode() { … }
void GpuDataManagerImplPrivate::RecordCompositingMode() { … }
#if BUILDFLAG(IS_LINUX)
bool GpuDataManagerImplPrivate::IsGpuMemoryBufferNV12Supported() { … }
void GpuDataManagerImplPrivate::SetGpuMemoryBufferNV12Supported(
bool supported) { … }
#endif
}