Chromium源码由浅入深(四)
接前一篇文章:Chromium源码由浅入深(三)
上回书结尾提到content/browser/gpu/gpu_internals_ui.cc的OnGpuInfoUpdate函数,本回对于这个函数的上下文进行深入分析。为了便于理解,再次贴出源码,如下:
void GpuMessageHandler::OnGpuInfoUpdate() {
// 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());
// Send GPU Info to javascript.
web_ui()->CallJavascriptFunctionUnsafe("browserBridge.onGpuInfoUpdate",
std::move(gpu_info_val));
}
重点关注以下代码片段:
// 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();
先来分析第一句:
const gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
对应的函数在content/browser/gpu/gpu_data_manager_impl.cc中,代码如下:
gpu::GPUInfo GpuDataManagerImpl::GetGPUInfo() {
base::AutoLock auto_lock(lock_);
return private_->GetGPUInfo();
}
可见,该函数只是加了锁,实际的工作则是交给了private_->GetGPUInfo()。
private_是GpuDataManagerImpl类中的成员变量,其定义在content/browser/gpu/gpu_data_manager_impl.h中,如下:
std::unique_ptr<GpuDataManagerImplPrivate> private_ GUARDED_BY(lock_)
也就是说private_->GetGPUInfo()实际调用的是GpuDataManagerImplPrivate类中的函数,在content/browser/gpu/gpu_data_manager_impl_private.h中,代码如下:
gpu::GPUInfo GpuDataManagerImplPrivate::GetGPUInfo() const {
return gpu_info_;
}
这里只是得到gpu_info_的值,那么它是在哪里被设置(改变)的?
gpu_info_是GpuDataManagerImplPrivate类的成员变量,也是在content/browser/gpu/gpu_data_manager_impl_private.h中定义,如下:
gpu::GPUInfo gpu_info_;
而对于gpu_info_的赋值则是在content/browser/gpu/gpu_data_manager_impl_private.cc的oid GpuDataManagerImplPrivate::UpdateGpuInfo函数(准确地说应该叫方法)中,代码如下:
void GpuDataManagerImplPrivate::UpdateGpuInfo(
const gpu::GPUInfo& gpu_info,
const absl::optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu) {
#if BUILDFLAG(IS_WIN)
// If GPU process crashes and launches again, GPUInfo will be sent back from
// the new GPU process again, and may overwrite the DX12, Vulkan, DxDiagNode
// info we already collected. This is to make sure it doesn't happen.
gpu::DxDiagNode dx_diagnostics = gpu_info_.dx_diagnostics;
uint32_t d3d12_feature_level = gpu_info_.d3d12_feature_level;
uint32_t vulkan_version = gpu_info_.vulkan_version;
#endif
gpu_info_ = gpu_info;
base::UmaHistogramCustomMicrosecondsTimes(
"GPU.GPUInitializationTime.V3", gpu_info_.initialization_time,
base::Milliseconds(5), base::Seconds(5), 50);
UMA_HISTOGRAM_EXACT_LINEAR("GPU.GpuCount", gpu_info_.GpuCount(), 10);
RecordDiscreteGpuHistograms(gpu_info_);
#if BUILDFLAG(IS_WIN)
if (!dx_diagnostics.IsEmpty()) {
gpu_info_.dx_diagnostics = dx_diagnostics;
}
if (d3d12_feature_level != 0) {
gpu_info_.d3d12_feature_level = d3d12_feature_level;
}
if (vulkan_version != 0) {
gpu_info_.vulkan_version = vulkan_version;
}
#endif // BUILDFLAG(IS_WIN)
bool needs_to_update_gpu_info_for_hardware_gpu =
!gpu_info_for_hardware_gpu_.IsInitialized();
if (!needs_to_update_gpu_info_for_hardware_gpu &&
!gpu_info_.UsesSwiftShader()) {
// On multi-GPU system, when switching to a different GPU, we want to reset
// GPUInfo for hardware GPU, because we want to know on which GPU Chrome
// crashes multiple times and falls back to SwiftShader.
const gpu::GPUInfo::GPUDevice& active_gpu = gpu_info_.active_gpu();
const gpu::GPUInfo::GPUDevice& cached_active_gpu =
gpu_info_for_hardware_gpu_.active_gpu();
#if BUILDFLAG(IS_WIN)
if (active_gpu.luid.HighPart != cached_active_gpu.luid.HighPart &&
active_gpu.luid.LowPart != cached_active_gpu.luid.LowPart) {
needs_to_update_gpu_info_for_hardware_gpu = true;
}
#else
if (active_gpu.vendor_id != cached_active_gpu.vendor_id ||
active_gpu.device_id != cached_active_gpu.device_id) {
needs_to_update_gpu_info_for_hardware_gpu = true;
}
#endif // BUILDFLAG(IS_WIN)
}
if (needs_to_update_gpu_info_for_hardware_gpu) {
if (gpu_info_for_hardware_gpu.has_value()) {
DCHECK(gpu_info_for_hardware_gpu->IsInitialized());
bool valid_info = true;
if (gpu_info_for_hardware_gpu->UsesSwiftShader()) {
valid_info = false;
} else if (gpu_info_for_hardware_gpu->gl_renderer.empty() &&
gpu_info_for_hardware_gpu->active_gpu().vendor_id == 0u) {
valid_info = false;
}
if (valid_info)
gpu_info_for_hardware_gpu_ = gpu_info_for_hardware_gpu.value();
} else {
if (!gpu_info_.UsesSwiftShader())
gpu_info_for_hardware_gpu_ = gpu_info_;
}
}
GetContentClient()->SetGpuInfo(gpu_info_);
NotifyGpuInfoUpdate();
}
那么又是在哪里调用的GpuDataManagerImplPrivate::UpdateGpuInfo()?
在Chromium源码中搜索,共有几处,而真正匹配的只有一处,在content/browser/gpu/gpu_data_manager_impl.cc中,代码如下:
void GpuDataManagerImpl::UpdateGpuInfo(
const gpu::GPUInfo& gpu_info,
const absl::optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu) {
base::AutoLock auto_lock(lock_);
private_->UpdateGpuInfo(gpu_info, gpu_info_for_hardware_gpu);
}
这就又回到了GpuDataManagerImpl类中。那么又是在哪里调用的GpuDataManagerImpl::UpdateGpuInfo()?
经过搜索定位,是在content/browser/gpu/gpu_process_host.cc中。但一共有两处都调用了这个函数。
- 第一处 GpuProcessHost::DidInitialize()中调用
代码如下:
void GpuProcessHost::DidInitialize(
const gpu::GPUInfo& gpu_info,
const gpu::GpuFeatureInfo& gpu_feature_info,
const absl::optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu,
const absl::optional<gpu::GpuFeatureInfo>&
gpu_feature_info_for_hardware_gpu,
const gfx::GpuExtraInfo& gpu_extra_info) {
if (GetGpuCrashCount() > 0) {
LOG(WARNING) << "Reinitialized the GPU process after a crash. The reported "
"initialization time was "
<< gpu_info.initialization_time.InMilliseconds() << " ms";
}
if (kind_ != GPU_PROCESS_KIND_INFO_COLLECTION) {
auto* gpu_data_manager = GpuDataManagerImpl::GetInstance();
// Update GpuFeatureInfo first, because UpdateGpuInfo() will notify all
// listeners.
gpu_data_manager->UpdateGpuFeatureInfo(gpu_feature_info,
gpu_feature_info_for_hardware_gpu);
gpu_data_manager->UpdateGpuInfo(gpu_info, gpu_info_for_hardware_gpu);
gpu_data_manager->UpdateGpuExtraInfo(gpu_extra_info);
}
#if BUILDFLAG(IS_ANDROID)
// Android may kill the GPU process to free memory, especially when the app
// is the background, so Android cannot have a hard limit on GPU starts.
// Reset crash count on Android when context creation succeeds, but only if no
// fallback option is available.
if (!GpuDataManagerImpl::GetInstance()->CanFallback())
recent_crash_count_ = 0;
#endif
}
- 第二处 GpuProcessHost::DidUpdateGPUInfo()中调用
代码如下:
void GpuProcessHost::DidUpdateGPUInfo(const gpu::GPUInfo& gpu_info) {
GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info, absl::nullopt);
}
分别对以上两个函数(方法)进行搜索,搜索其被调用的地方,最终定位到实际上是在同一文件中,代码还挨着。是在components/viz/service/gl/gpu_service_impl.cc中,代码如下:
void GpuServiceImpl::UpdateGPUInfoGL() {
DCHECK(main_runner_->BelongsToCurrentThread());
gpu::CollectGraphicsInfoGL(&gpu_info_, GetContextState()->display());
gpu_host_->DidUpdateGPUInfo(gpu_info_);
}
void GpuServiceImpl::InitializeWithHost(
mojo::PendingRemote<mojom::GpuHost> pending_gpu_host,
gpu::GpuProcessActivityFlags activity_flags,
scoped_refptr<gl::GLSurface> default_offscreen_surface,
gpu::SyncPointManager* sync_point_manager,
gpu::SharedImageManager* shared_image_manager,
gpu::Scheduler* scheduler,
base::WaitableEvent* shutdown_event) {
DCHECK(main_runner_->BelongsToCurrentThread());
mojo::Remote<mojom::GpuHost> gpu_host(std::move(pending_gpu_host));
gpu_host->DidInitialize(gpu_info_, gpu_feature_info_,
gpu_info_for_hardware_gpu_,
gpu_feature_info_for_hardware_gpu_, gpu_extra_info_);
gpu_host_ = mojo::SharedRemote<mojom::GpuHost>(gpu_host.Unbind(), io_runner_);
if (!in_host_process()) {
// The global callback is reset from the dtor. So Unretained() here is safe.
// Note that the callback can be called from any thread. Consequently, the
// callback cannot use a WeakPtr.
GetLogMessageManager()->InstallPostInitializeLogHandler(base::BindRepeating(
&GpuServiceImpl::RecordLogMessage, base::Unretained(this)));
}
if (!sync_point_manager) {
owned_sync_point_manager_ = std::make_unique<gpu::SyncPointManager>();
sync_point_manager = owned_sync_point_manager_.get();
}
if (!shared_image_manager) {
// When using real buffers for testing overlay configurations, we need
// access to SharedImageManager on the viz thread to obtain the buffer
// corresponding to a mailbox.
const bool display_context_on_another_thread =
features::IsDrDcEnabled() && !gpu_driver_bug_workarounds_.disable_drdc;
bool thread_safe_manager = display_context_on_another_thread;
// Raw draw needs to access shared image backing on the compositor thread.
thread_safe_manager |= features::IsUsingRawDraw();
#if BUILDFLAG(IS_OZONE)
thread_safe_manager |= features::ShouldUseRealBuffersForPageFlipTest();
#endif
owned_shared_image_manager_ = std::make_unique<gpu::SharedImageManager>(
thread_safe_manager, display_context_on_another_thread);
shared_image_manager = owned_shared_image_manager_.get();
#if BUILDFLAG(IS_OZONE)
} else {
// With this feature enabled, we don't expect to receive an external
// SharedImageManager.
DCHECK(!features::ShouldUseRealBuffersForPageFlipTest());
#endif
}
shutdown_event_ = shutdown_event;
if (!shutdown_event_) {
owned_shutdown_event_ = std::make_unique<base::WaitableEvent>(
base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
shutdown_event_ = owned_shutdown_event_.get();
}
if (scheduler) {
scheduler_ = scheduler;
} else {
owned_scheduler_ =
std::make_unique<gpu::Scheduler>(sync_point_manager, gpu_preferences_);
scheduler_ = owned_scheduler_.get();
}
// Defer creation of the render thread. This is to prevent it from handling
// IPC messages before the sandbox has been enabled and all other necessary
// initialization has succeeded.
gpu_channel_manager_ = std::make_unique<gpu::GpuChannelManager>(
gpu_preferences_, this, watchdog_thread_.get(), main_runner_, io_runner_,
scheduler_, sync_point_manager, shared_image_manager,
gpu_memory_buffer_factory_.get(), gpu_feature_info_,
std::move(activity_flags), std::move(default_offscreen_surface),
image_decode_accelerator_worker_.get(), vulkan_context_provider(),
metal_context_provider_.get(), dawn_context_provider());
media_gpu_channel_manager_ = std::make_unique<media::MediaGpuChannelManager>(
gpu_channel_manager_.get());
// Create and Initialize compositor gpu thread.
compositor_gpu_thread_ = CompositorGpuThread::Create(
gpu_channel_manager_.get(),
#if BUILDFLAG(ENABLE_VULKAN)
vulkan_implementation_,
vulkan_context_provider_ ? vulkan_context_provider_->GetDeviceQueue()
: nullptr,
#else
nullptr, nullptr,
#endif
gpu_channel_manager_->default_offscreen_surface()
? gpu_channel_manager_->default_offscreen_surface()->GetGLDisplay()
: nullptr,
!!watchdog_thread_);
}
欲知后事如何,且看下回分解。