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