chromium/gpu/ipc/service/gpu_init.cc

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/ipc/service/gpu_init.h"

#include <cstdlib>
#include <cstring>
#include <optional>
#include <string>

#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/path_service.h"
#include "base/strings/pattern.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/timer/elapsed_timer.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "build/chromecast_buildflags.h"
#include "build/chromeos_buildflags.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/command_buffer/service/service_utils.h"
#include "gpu/config/gpu_driver_bug_list.h"
#include "gpu/config/gpu_driver_bug_workaround_type.h"
#include "gpu/config/gpu_driver_bug_workarounds.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_switching.h"
#include "gpu/config/gpu_util.h"
#include "gpu/ipc/service/gpu_watchdog_thread.h"
#include "ui/base/ui_base_features.h"
#include "ui/gfx/switches.h"
#include "ui/gl/buildflags.h"
#include "ui/gl/gl_display.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_switches.h"
#include "ui/gl/gl_utils.h"
#include "ui/gl/init/gl_factory.h"

#if BUILDFLAG(IS_MAC)
#include <GLES2/gl2.h>
#endif

#if BUILDFLAG(IS_OZONE)
#include "gpu/vulkan/drm_modifiers_filter_vulkan.h"
#include "ui/ozone/public/drm_modifiers_filter.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#endif

#if BUILDFLAG(IS_WIN)
#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "ui/gl/direct_composition_support.h"
#include "ui/gl/gl_surface_egl.h"
#endif

#if BUILDFLAG(IS_ANDROID)
#include "ui/gfx/android/android_surface_control_compat.h"
#endif

#if BUILDFLAG(ENABLE_VULKAN)
#include "gpu/vulkan/init/vulkan_factory.h"
#include "gpu/vulkan/vulkan_implementation.h"
#include "gpu/vulkan/vulkan_instance.h"
#include "gpu/vulkan/vulkan_util.h"
#endif

#if !BUILDFLAG(IS_MAC)
#include "ui/gl/gl_fence_egl.h"
#endif

#if BUILDFLAG(USE_DAWN) || BUILDFLAG(SKIA_USE_DAWN)
#include "third_party/dawn/include/dawn/dawn_proc.h"          // nogncheck
#include "third_party/dawn/include/dawn/native/DawnNative.h"  // nogncheck
#endif

#if BUILDFLAG(SKIA_USE_DAWN)
#include "gpu/command_buffer/service/dawn_context_provider.h"
#include "third_party/dawn/include/dawn/webgpu_cpp.h"  // nogncheck
#endif

#if BUILDFLAG(SKIA_USE_DAWN) && BUILDFLAG(IS_CHROMEOS)
#include "gpu/command_buffer/service/drm_modifiers_filter_dawn.h"
#endif

namespace gpu {

namespace {
bool CollectGraphicsInfo(GPUInfo* gpu_info) {}

void InitializeDawnProcs() {}

void InitializePlatformOverlaySettings(GPUInfo* gpu_info,
                                       const GpuFeatureInfo& gpu_feature_info) {}

#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CASTOS)
bool CanAccessDeviceFile(const GPUInfo& gpu_info) {}
#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CASTOS)

class GpuWatchdogInit {};

void PauseGpuWatchdog(GpuWatchdogThread* watchdog_thread) {}
void ResumeGpuWatchdog(GpuWatchdogThread* watchdog_thread) {}

// TODO(crbug.com/40700374): We currently do not handle
// VK_ERROR_DEVICE_LOST in in-process-gpu.
// Android WebView is allowed for now because it CHECKs on context loss.
void DisableInProcessGpuVulkan(GpuFeatureInfo* gpu_feature_info,
                               GpuPreferences* gpu_preferences) {}

#if BUILDFLAG(IS_ANDROID)
// TODO(https://crbug.com/324468229): We currently do not handle Dawn device
// lost with in-process-gpu.
void DisableInProcessGpuGraphite(GpuFeatureInfo& gpu_feature_info,
                                 GpuPreferences& gpu_preferences) {
  if (gpu_feature_info.status_values[GPU_FEATURE_TYPE_SKIA_GRAPHITE] ==
          kGpuFeatureStatusEnabled ||
      gpu_preferences.gr_context_type == GrContextType::kGraphiteDawn) {
    LOG(ERROR) << "Graphite not supported with in process gpu";
    gpu_feature_info.status_values[GPU_FEATURE_TYPE_SKIA_GRAPHITE] =
        kGpuFeatureStatusDisabled;
    gpu_preferences.gr_context_type = GrContextType::kGL;
  }
}
#endif

#if BUILDFLAG(ENABLE_VULKAN)
bool MatchGLInfo(const std::string& field, const std::string& patterns) {}
#endif  // BUILDFLAG(ENABLE_VULKAN)

#if BUILDFLAG(IS_WIN)
uint64_t CHROME_LUID_to_uint64_t(const CHROME_LUID& luid) {
  uint64_t id64 = static_cast<uint32_t>(luid.HighPart);
  return (id64 << 32) | (luid.LowPart & 0xFFFFFFFF);
}
#endif  // BUILDFLAG(IS_WIN)

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
// GPU picking is only effective with ANGLE/Metal backend on Mac and
// on Windows with EGL.
// Returns the default GPU's system_device_id.
void SetupGLDisplayManagerEGL(const GPUInfo& gpu_info,
                              const GpuFeatureInfo& gpu_feature_info) {
  const GPUInfo::GPUDevice* gpu_high_perf =
      gpu_info.GetGpuByPreference(gl::GpuPreference::kHighPerformance);
  const GPUInfo::GPUDevice* gpu_low_power =
      gpu_info.GetGpuByPreference(gl::GpuPreference::kLowPower);
#if BUILDFLAG(IS_WIN)
  // On Windows the default GPU may not be the low power GPU.
  const GPUInfo::GPUDevice* gpu_default = &(gpu_info.gpu);
  uint64_t system_device_id_high_perf =
      gpu_high_perf ? CHROME_LUID_to_uint64_t(gpu_high_perf->luid) : 0;
  uint64_t system_device_id_low_power =
      gpu_low_power ? CHROME_LUID_to_uint64_t(gpu_low_power->luid) : 0;
  uint64_t system_device_id_default =
      CHROME_LUID_to_uint64_t(gpu_default->luid);
#else  // IS_MAC
  const GPUInfo::GPUDevice* gpu_default =
      gpu_low_power ? gpu_low_power : &(gpu_info.gpu);
  uint64_t system_device_id_high_perf =
      gpu_high_perf ? gpu_high_perf->system_device_id : 0;
  uint64_t system_device_id_low_power =
      gpu_low_power ? gpu_low_power->system_device_id : 0;
  uint64_t system_device_id_default = gpu_default->system_device_id;
#endif
  DCHECK(gpu_default);

  if (gpu_info.GpuCount() <= 1) {
    gl::SetGpuPreferenceEGL(gl::GpuPreference::kDefault,
                            system_device_id_default);
    return;
  }
  if (gpu_feature_info.IsWorkaroundEnabled(FORCE_LOW_POWER_GPU) &&
      system_device_id_low_power) {
    gl::SetGpuPreferenceEGL(gl::GpuPreference::kDefault,
                            system_device_id_low_power);
    return;
  }
  if (gpu_feature_info.IsWorkaroundEnabled(FORCE_HIGH_PERFORMANCE_GPU) &&
      system_device_id_high_perf) {
    gl::SetGpuPreferenceEGL(gl::GpuPreference::kDefault,
                            system_device_id_high_perf);
    return;
  }
  if (gpu_default == gpu_high_perf) {
    // If the default GPU is already the high performance GPU, then it's better
    // for Chrome to always use this GPU.
    gl::SetGpuPreferenceEGL(gl::GpuPreference::kDefault,
                            system_device_id_high_perf);
    return;
  }

  // Chrome uses the default GPU for internal rendering and the high
  // performance GPU for WebGL/WebGPU contexts that prefer high performance.
  // At this moment, a low power GPU different from the default GPU is not
  // supported.
  gl::SetGpuPreferenceEGL(gl::GpuPreference::kDefault,
                          system_device_id_default);
  if (system_device_id_high_perf) {
    gl::SetGpuPreferenceEGL(gl::GpuPreference::kHighPerformance,
                            system_device_id_high_perf);
  }
  return;
}
#endif  // IS_WIN || IS_MAC

}  // namespace

GpuInit::GpuInit() = default;

GpuInit::~GpuInit() {}

bool GpuInit::InitializeAndStartSandbox(base::CommandLine* command_line,
                                        const GpuPreferences& gpu_preferences) {}

#if BUILDFLAG(IS_ANDROID)
void GpuInit::InitializeInProcess(base::CommandLine* command_line,
                                  const GpuPreferences& gpu_preferences) {
  gpu_preferences_ = gpu_preferences;
  init_successful_ = true;
  DCHECK(!EnableSwiftShaderIfNeeded(
      command_line, gpu_feature_info_,
      gpu_preferences_.disable_software_rasterizer, false));

  gl::GLDisplay* gl_display = InitializeGLThreadSafe(
      command_line, gpu_preferences_, &gpu_info_, &gpu_feature_info_);

  if (!gl_display) {
    LOG(FATAL) << "gpu::InitializeGLThreadSafe() failed.";
  }

  if (command_line->HasSwitch(switches::kWebViewDrawFunctorUsesVulkan)) {
    bool result = InitializeVulkan();
    // There is no fallback for webview.
    CHECK(result);
  } else {
    DisableInProcessGpuVulkan(&gpu_feature_info_, &gpu_preferences_);
    DisableInProcessGpuGraphite(gpu_feature_info_, gpu_preferences_);
  }

  default_offscreen_surface_ =
      gl::init::CreateOffscreenGLSurface(gl_display, gfx::Size());

  UMA_HISTOGRAM_ENUMERATION("GPU.GLImplementation", gl::GetGLImplementation());
  InitializeDawnProcs();
}
#else
void GpuInit::InitializeInProcess(base::CommandLine* command_line,
                                  const GpuPreferences& gpu_preferences) {}
#endif  // BUILDFLAG(IS_ANDROID)

void GpuInit::SaveHardwareGpuInfoAndGpuFeatureInfo() {}

void GpuInit::AdjustInfoToSwiftShader() {}

scoped_refptr<gl::GLSurface> GpuInit::TakeDefaultOffscreenSurface() {}

bool GpuInit::InitializeDawn() {}

bool GpuInit::InitializeVulkan() {}

}  // namespace gpu