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