1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/viz/service/main/viz_main_impl.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/feature_list.h"
12 #include "base/message_loop/message_pump_type.h"
13 #include "base/power_monitor/power_monitor.h"
14 #include "base/power_monitor/power_monitor_source.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/trace_event/memory_dump_manager.h"
17 #include "build/build_config.h"
18 #include "components/ui_devtools/buildflags.h"
19 #include "gpu/command_buffer/common/activity_flags.h"
20 #include "gpu/config/gpu_finch_features.h"
21 #include "gpu/ipc/service/gpu_init.h"
22 #include "gpu/ipc/service/gpu_watchdog_thread.h"
23 #include "media/gpu/buildflags.h"
24 #include "services/metrics/public/cpp/delegating_ukm_recorder.h"
25 #include "services/metrics/public/cpp/mojo_ukm_recorder.h"
26 #include "skia/ext/legacy_display_globals.h"
27
28 namespace {
29
CreateAndStartIOThread()30 std::unique_ptr<base::Thread> CreateAndStartIOThread() {
31 // TODO(sad): We do not need the IO thread once gpu has a separate process.
32 // It should be possible to use |main_task_runner_| for doing IO tasks.
33 base::Thread::Options thread_options(base::MessagePumpType::IO, 0);
34 // TODO(reveman): Remove this in favor of setting it explicitly for each
35 // type of process.
36 if (base::FeatureList::IsEnabled(features::kGpuUseDisplayThreadPriority))
37 thread_options.priority = base::ThreadPriority::DISPLAY;
38 auto io_thread = std::make_unique<base::Thread>("GpuIOThread");
39 CHECK(io_thread->StartWithOptions(thread_options));
40 return io_thread;
41 }
42
43 } // namespace
44
45 namespace viz {
46
47 VizMainImpl::ExternalDependencies::ExternalDependencies() = default;
48
49 VizMainImpl::ExternalDependencies::~ExternalDependencies() = default;
50
51 VizMainImpl::ExternalDependencies::ExternalDependencies(
52 ExternalDependencies&& other) = default;
53
54 VizMainImpl::ExternalDependencies& VizMainImpl::ExternalDependencies::operator=(
55 ExternalDependencies&& other) = default;
56
VizMainImpl(Delegate * delegate,ExternalDependencies dependencies,std::unique_ptr<gpu::GpuInit> gpu_init)57 VizMainImpl::VizMainImpl(Delegate* delegate,
58 ExternalDependencies dependencies,
59 std::unique_ptr<gpu::GpuInit> gpu_init)
60 : delegate_(delegate),
61 dependencies_(std::move(dependencies)),
62 gpu_init_(std::move(gpu_init)),
63 gpu_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
64 DCHECK(gpu_init_);
65
66 // TODO(crbug.com/609317): Remove this when Mus Window Server and GPU are
67 // split into separate processes. Until then this is necessary to be able to
68 // run Mushrome (chrome with mus) with Mus running in the browser process.
69 if (dependencies_.power_monitor_source) {
70 base::PowerMonitor::Initialize(
71 std::move(dependencies_.power_monitor_source));
72 }
73
74 if (!dependencies_.io_thread_task_runner)
75 io_thread_ = CreateAndStartIOThread();
76
77 if (dependencies_.viz_compositor_thread_runner) {
78 viz_compositor_thread_runner_ = dependencies_.viz_compositor_thread_runner;
79 } else {
80 viz_compositor_thread_runner_impl_ =
81 std::make_unique<VizCompositorThreadRunnerImpl>();
82 viz_compositor_thread_runner_ = viz_compositor_thread_runner_impl_.get();
83 }
84 if (delegate_) {
85 delegate_->PostCompositorThreadCreated(
86 viz_compositor_thread_runner_->task_runner());
87 }
88
89 if (!gpu_init_->gpu_info().in_process_gpu && dependencies_.ukm_recorder) {
90 // NOTE: If the GPU is running in the browser process, we can use the
91 // browser's UKMRecorder.
92 ukm::DelegatingUkmRecorder::Get()->AddDelegate(
93 dependencies_.ukm_recorder->GetWeakPtr());
94 }
95
96 gpu_service_ = std::make_unique<GpuServiceImpl>(
97 gpu_init_->gpu_info(), gpu_init_->TakeWatchdogThread(), io_task_runner(),
98 gpu_init_->gpu_feature_info(), gpu_init_->gpu_preferences(),
99 gpu_init_->gpu_info_for_hardware_gpu(),
100 gpu_init_->gpu_feature_info_for_hardware_gpu(),
101 gpu_init_->gpu_extra_info(), gpu_init_->vulkan_implementation(),
102 base::BindOnce(&VizMainImpl::ExitProcess, base::Unretained(this)));
103 }
104
~VizMainImpl()105 VizMainImpl::~VizMainImpl() {
106 DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
107
108 // The compositor holds on to some resources from gpu service. So destroy the
109 // compositor first, before destroying the gpu service. However, before the
110 // compositor is destroyed, close the binding, so that the gpu service doesn't
111 // need to process commands from the host as it is shutting down.
112 receiver_.reset();
113
114 // If the VizCompositorThread was started and owned by VizMainImpl, then this
115 // will block until the thread has been shutdown. All RootCompositorFrameSinks
116 // must be destroyed before now, otherwise the compositor thread will deadlock
117 // waiting for a response from the blocked GPU thread.
118 // For the non-owned case for Android WebView, Viz does not communicate with
119 // this thread so there is no need to shutdown viz first.
120 viz_compositor_thread_runner_ = nullptr;
121 viz_compositor_thread_runner_impl_.reset();
122
123 if (dependencies_.ukm_recorder)
124 ukm::DelegatingUkmRecorder::Get()->RemoveDelegate(
125 dependencies_.ukm_recorder.get());
126 }
127
BindAssociated(mojo::PendingAssociatedReceiver<mojom::VizMain> pending_receiver)128 void VizMainImpl::BindAssociated(
129 mojo::PendingAssociatedReceiver<mojom::VizMain> pending_receiver) {
130 receiver_.Bind(std::move(pending_receiver));
131 }
132
CreateGpuService(mojo::PendingReceiver<mojom::GpuService> pending_receiver,mojo::PendingRemote<mojom::GpuHost> pending_gpu_host,mojo::PendingRemote<discardable_memory::mojom::DiscardableSharedMemoryManager> discardable_memory_manager,mojo::ScopedSharedBufferHandle activity_flags,gfx::FontRenderParams::SubpixelRendering subpixel_rendering)133 void VizMainImpl::CreateGpuService(
134 mojo::PendingReceiver<mojom::GpuService> pending_receiver,
135 mojo::PendingRemote<mojom::GpuHost> pending_gpu_host,
136 mojo::PendingRemote<
137 discardable_memory::mojom::DiscardableSharedMemoryManager>
138 discardable_memory_manager,
139 mojo::ScopedSharedBufferHandle activity_flags,
140 gfx::FontRenderParams::SubpixelRendering subpixel_rendering) {
141 DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
142
143 mojo::Remote<mojom::GpuHost> gpu_host(std::move(pending_gpu_host));
144
145 // If GL is disabled then don't try to collect GPUInfo, we're not using GPU.
146 if (gl::GetGLImplementation() != gl::kGLImplementationDisabled)
147 gpu_service_->UpdateGPUInfo();
148
149 if (!gpu_init_->init_successful()) {
150 LOG(ERROR) << "Exiting GPU process due to errors during initialization";
151 GpuServiceImpl::FlushPreInitializeLogMessages(gpu_host.get());
152 gpu_service_.reset();
153 gpu_host->DidFailInitialize();
154 if (delegate_)
155 delegate_->OnInitializationFailed();
156 return;
157 }
158
159 if (!gpu_init_->gpu_info().in_process_gpu) {
160 // If the GPU is running in the browser process, discardable memory manager
161 // has already been initialized.
162 discardable_shared_memory_manager_ = base::MakeRefCounted<
163 discardable_memory::ClientDiscardableSharedMemoryManager>(
164 std::move(discardable_memory_manager), io_task_runner());
165 base::DiscardableMemoryAllocator::SetInstance(
166 discardable_shared_memory_manager_.get());
167 }
168
169 skia::LegacyDisplayGlobals::SetCachedPixelGeometry(
170 gfx::FontRenderParams::SubpixelRenderingToSkiaPixelGeometry(
171 subpixel_rendering));
172
173 gpu_service_->Bind(std::move(pending_receiver));
174 gpu_service_->InitializeWithHost(
175 gpu_host.Unbind(),
176 gpu::GpuProcessActivityFlags(std::move(activity_flags)),
177 gpu_init_->TakeDefaultOffscreenSurface(),
178 dependencies_.sync_point_manager, dependencies_.shared_image_manager,
179 dependencies_.shutdown_event);
180
181 if (!pending_frame_sink_manager_params_.is_null()) {
182 CreateFrameSinkManagerInternal(
183 std::move(pending_frame_sink_manager_params_));
184 pending_frame_sink_manager_params_.reset();
185 }
186 if (delegate_)
187 delegate_->OnGpuServiceConnection(gpu_service_.get());
188 }
189
190 #if defined(OS_WIN)
CreateInfoCollectionGpuService(mojo::PendingReceiver<mojom::InfoCollectionGpuService> pending_receiver)191 void VizMainImpl::CreateInfoCollectionGpuService(
192 mojo::PendingReceiver<mojom::InfoCollectionGpuService> pending_receiver) {
193 DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
194 DCHECK(!info_collection_gpu_service_);
195 DCHECK(gpu_init_->device_perf_info().has_value());
196
197 info_collection_gpu_service_ = std::make_unique<InfoCollectionGpuServiceImpl>(
198 gpu_thread_task_runner_, io_task_runner(),
199 gpu_init_->device_perf_info().value(), gpu_init_->gpu_info().active_gpu(),
200 std::move(pending_receiver));
201 }
202 #endif
203
CreateFrameSinkManager(mojom::FrameSinkManagerParamsPtr params)204 void VizMainImpl::CreateFrameSinkManager(
205 mojom::FrameSinkManagerParamsPtr params) {
206 DCHECK(viz_compositor_thread_runner_);
207 DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
208 if (!gpu_service_ || !gpu_service_->is_initialized()) {
209 DCHECK(pending_frame_sink_manager_params_.is_null());
210 pending_frame_sink_manager_params_ = std::move(params);
211 return;
212 }
213 CreateFrameSinkManagerInternal(std::move(params));
214 }
215
CreateFrameSinkManagerInternal(mojom::FrameSinkManagerParamsPtr params)216 void VizMainImpl::CreateFrameSinkManagerInternal(
217 mojom::FrameSinkManagerParamsPtr params) {
218 DCHECK(gpu_service_);
219 DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
220
221 gl::GLSurfaceFormat format;
222 // If we are running a SW Viz process, we may not have a default offscreen
223 // surface.
224 if (auto* offscreen_surface =
225 gpu_service_->gpu_channel_manager()->default_offscreen_surface()) {
226 format = offscreen_surface->GetFormat();
227 } else {
228 DCHECK_EQ(gl::GetGLImplementation(), gl::kGLImplementationDisabled);
229 }
230
231 // When the host loses its connection to the viz process, it assumes the
232 // process has crashed and tries to reinitialize it. However, it is possible
233 // to have lost the connection for other reasons (e.g. deserialization
234 // errors) and the viz process is already set up. We cannot recreate
235 // FrameSinkManagerImpl, so just do a hard CHECK rather than crashing down the
236 // road so that all crash reports caused by this issue look the same and have
237 // the same signature. https://crbug.com/928845
238 CHECK(!task_executor_);
239
240 task_executor_ = std::make_unique<gpu::GpuInProcessThreadService>(
241 this, gpu_thread_task_runner_, gpu_service_->GetGpuScheduler(),
242 gpu_service_->sync_point_manager(), gpu_service_->mailbox_manager(),
243 format, gpu_service_->gpu_feature_info(),
244 gpu_service_->gpu_channel_manager()->gpu_preferences(),
245 gpu_service_->shared_image_manager(),
246 gpu_service_->gpu_channel_manager()->program_cache());
247
248 viz_compositor_thread_runner_->CreateFrameSinkManager(
249 std::move(params), task_executor_.get(), gpu_service_.get());
250 }
251
CreateVizDevTools(mojom::VizDevToolsParamsPtr params)252 void VizMainImpl::CreateVizDevTools(mojom::VizDevToolsParamsPtr params) {
253 #if BUILDFLAG(USE_VIZ_DEVTOOLS)
254 viz_compositor_thread_runner_->CreateVizDevTools(std::move(params));
255 #endif
256 }
257
GetSharedContextState()258 scoped_refptr<gpu::SharedContextState> VizMainImpl::GetSharedContextState() {
259 return gpu_service_->GetContextState();
260 }
261
GetShareGroup()262 scoped_refptr<gl::GLShareGroup> VizMainImpl::GetShareGroup() {
263 return gpu_service_->share_group();
264 }
265
ExitProcess(base::Optional<ExitCode> immediate_exit_code)266 void VizMainImpl::ExitProcess(base::Optional<ExitCode> immediate_exit_code) {
267 DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
268
269 if (!gpu_init_->gpu_info().in_process_gpu && immediate_exit_code) {
270 // Atomically shut down GPU process to make it faster and simpler.
271 base::Process::TerminateCurrentProcessImmediately(
272 static_cast<int>(immediate_exit_code.value()));
273 return;
274 }
275
276 // Close mojom::VizMain bindings first so the browser can't try to reconnect.
277 receiver_.reset();
278
279 if (viz_compositor_thread_runner_) {
280 // Destroy RootCompositorFrameSinkImpls on the compositor while the GPU
281 // thread is still running to avoid deadlock. Quit GPU thread TaskRunner
282 // after cleanup on compositor thread is finished.
283 viz_compositor_thread_runner_->CleanupForShutdown(base::BindOnce(
284 &Delegate::QuitMainMessageLoop, base::Unretained(delegate_)));
285 } else {
286 delegate_->QuitMainMessageLoop();
287 }
288 }
289
290 } // namespace viz
291