blob: 72b26afce32d5ad7e6f786737f4515a67f01d952 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/service/main/viz_main_impl.h"
#include <memory>
#include <utility>
#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
#include "base/power_monitor/power_monitor_device_source.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h"
#include "components/viz/common/switches.h"
#include "components/viz/service/display_embedder/gpu_display_provider.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "components/viz/service/gl/gpu_service_impl.h"
#include "gpu/command_buffer/common/activity_flags.h"
#include "gpu/config/gpu_switches.h"
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "gpu/ipc/common/gpu_preferences_util.h"
#include "gpu/ipc/gpu_in_process_thread_service.h"
#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
#include "gpu/ipc/service/gpu_watchdog_thread.h"
#include "media/gpu/buildflags.h"
#include "services/metrics/public/cpp/delegating_ukm_recorder.h"
#include "services/metrics/public/cpp/mojo_ukm_recorder.h"
#include "services/metrics/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
#include "ui/gfx/switches.h"
#if defined(OS_CHROMEOS) && BUILDFLAG(USE_VAAPI)
#include "media/gpu/vaapi/vaapi_wrapper.h"
#endif
#if defined(USE_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/ozone_switches.h"
#endif
namespace {
std::unique_ptr<base::Thread> CreateAndStartCompositorThread() {
auto thread = std::make_unique<base::Thread>("VizCompositorThread");
base::Thread::Options thread_options;
thread_options.message_loop_type = base::MessageLoop::TYPE_DEFAULT;
#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
thread_options.priority = base::ThreadPriority::DISPLAY;
#endif
CHECK(thread->StartWithOptions(thread_options));
return thread;
}
std::unique_ptr<base::Thread> CreateAndStartIOThread() {
// TODO(sad): We do not need the IO thread once gpu has a separate process.
// It should be possible to use |main_task_runner_| for doing IO tasks.
base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
thread_options.priority = base::ThreadPriority::NORMAL;
#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
// TODO(reveman): Remove this in favor of setting it explicitly for each
// type of process.
thread_options.priority = base::ThreadPriority::DISPLAY;
#endif
auto io_thread = std::make_unique<base::Thread>("GpuIOThread");
CHECK(io_thread->StartWithOptions(thread_options));
return io_thread;
}
} // namespace
namespace viz {
VizMainImpl::ExternalDependencies::ExternalDependencies() = default;
VizMainImpl::ExternalDependencies::~ExternalDependencies() = default;
VizMainImpl::ExternalDependencies::ExternalDependencies(
ExternalDependencies&& other) = default;
VizMainImpl::ExternalDependencies& VizMainImpl::ExternalDependencies::operator=(
ExternalDependencies&& other) = default;
VizMainImpl::VizMainImpl(Delegate* delegate,
ExternalDependencies dependencies,
std::unique_ptr<gpu::GpuInit> gpu_init)
: delegate_(delegate),
dependencies_(std::move(dependencies)),
gpu_init_(std::move(gpu_init)),
gpu_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
binding_(this),
associated_binding_(this) {
// TODO(crbug.com/609317): Remove this when Mus Window Server and GPU are
// split into separate processes. Until then this is necessary to be able to
// run Mushrome (chrome with mus) with Mus running in the browser process.
if (!base::PowerMonitor::Get()) {
power_monitor_ = std::make_unique<base::PowerMonitor>(
std::make_unique<base::PowerMonitorDeviceSource>());
}
if (!gpu_init_) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
gpu::GpuPreferences gpu_preferences;
if (command_line->HasSwitch(switches::kGpuPreferences)) {
std::string value =
command_line->GetSwitchValueASCII(switches::kGpuPreferences);
bool success = gpu::SwitchValueToGpuPreferences(value, &gpu_preferences);
CHECK(success);
}
#if defined(OS_CHROMEOS) && BUILDFLAG(USE_VAAPI)
// Initialize media codec. The UI service is running in a priviliged
// process. We don't need care when to initialize media codec. When we have
// a separate GPU (or VIZ) service process, we should initialize them
// before sandboxing
media::VaapiWrapper::PreSandboxInitialization();
#endif
// Initialize GpuInit before starting the IO or compositor threads.
gpu_init_ = std::make_unique<gpu::GpuInit>();
gpu_init_->set_sandbox_helper(this);
#if defined(USE_OZONE)
command_line->AppendSwitch(switches::kEnableDrmMojo);
#endif
// TODO(crbug.com/609317): Use InitializeAndStartSandbox() when gpu-mus is
// split into a separate process.
gpu_init_->InitializeInProcess(command_line, gpu_preferences);
}
if (!dependencies_.io_thread_task_runner)
io_thread_ = CreateAndStartIOThread();
if (dependencies_.create_display_compositor) {
compositor_thread_ = CreateAndStartCompositorThread();
compositor_thread_task_runner_ = compositor_thread_->task_runner();
if (delegate_)
delegate_->PostCompositorThreadCreated(
compositor_thread_task_runner_.get());
}
CreateUkmRecorderIfNeeded(dependencies.connector);
gpu_service_ = std::make_unique<GpuServiceImpl>(
gpu_init_->gpu_info(), gpu_init_->TakeWatchdogThread(), io_task_runner(),
gpu_init_->gpu_feature_info(), gpu_init_->gpu_preferences(),
gpu_init_->gpu_info_for_hardware_gpu(),
gpu_init_->gpu_feature_info_for_hardware_gpu());
}
VizMainImpl::~VizMainImpl() {
DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
// The compositor holds on to some resources from gpu service. So destroy the
// compositor first, before destroying the gpu service. However, before the
// compositor is destroyed, close the binding, so that the gpu service doesn't
// need to process commands from the host as it is shutting down.
binding_.Close();
associated_binding_.Close();
if (compositor_thread_) {
// Destroy all objects owned on the compositor thread before shutting down
// the thread. All RootCompositorFrameSinks must be destroyed before now,
// otherwise the compositor thread will deadlock waiting for a response from
// the blocked GPU thread.
compositor_thread_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&VizMainImpl::TearDownOnCompositorThread,
base::Unretained(this)));
compositor_thread_.reset();
compositor_thread_task_runner_ = nullptr;
}
if (ukm_recorder_)
ukm::DelegatingUkmRecorder::Get()->RemoveDelegate(ukm_recorder_.get());
}
void VizMainImpl::SetLogMessagesForHost(LogMessages log_messages) {
log_messages_ = std::move(log_messages);
}
void VizMainImpl::Bind(mojom::VizMainRequest request) {
binding_.Bind(std::move(request));
}
void VizMainImpl::BindAssociated(mojom::VizMainAssociatedRequest request) {
associated_binding_.Bind(std::move(request));
}
void VizMainImpl::CreateGpuService(
mojom::GpuServiceRequest request,
mojom::GpuHostPtr gpu_host,
discardable_memory::mojom::DiscardableSharedMemoryManagerPtr
discardable_memory_manager,
mojo::ScopedSharedBufferHandle activity_flags) {
DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
gpu_service_->UpdateGPUInfo();
for (const LogMessage& log : log_messages_)
gpu_host->RecordLogMessage(log.severity, log.header, log.message);
log_messages_.clear();
if (!gpu_init_->init_successful()) {
LOG(ERROR) << "Exiting GPU process due to errors during initialization";
gpu_service_.reset();
gpu_host->DidFailInitialize();
if (delegate_)
delegate_->OnInitializationFailed();
return;
}
if (!gpu_init_->gpu_info().in_process_gpu) {
// If the GPU is running in the browser process, discardable memory manager
// has already been initialized.
discardable_shared_memory_manager_ = std::make_unique<
discardable_memory::ClientDiscardableSharedMemoryManager>(
std::move(discardable_memory_manager), io_task_runner());
base::DiscardableMemoryAllocator::SetInstance(
discardable_shared_memory_manager_.get());
}
gpu_service_->Bind(std::move(request));
gpu_service_->InitializeWithHost(
std::move(gpu_host),
gpu::GpuProcessActivityFlags(std::move(activity_flags)),
dependencies_.sync_point_manager, dependencies_.shutdown_event);
if (!pending_frame_sink_manager_params_.is_null()) {
CreateFrameSinkManagerInternal(
std::move(pending_frame_sink_manager_params_));
pending_frame_sink_manager_params_.reset();
}
if (delegate_)
delegate_->OnGpuServiceConnection(gpu_service_.get());
}
void VizMainImpl::CreateUkmRecorderIfNeeded(
service_manager::Connector* connector) {
// If GPU is running in the browser process, we can use browser's UKMRecorder.
if (gpu_init_->gpu_info().in_process_gpu)
return;
DCHECK(connector) << "Unable to initialize UKMRecorder in the GPU process - "
<< "no valid connector.";
ukm_recorder_ = ukm::MojoUkmRecorder::Create(connector);
ukm::DelegatingUkmRecorder::Get()->AddDelegate(ukm_recorder_->GetWeakPtr());
}
void VizMainImpl::CreateFrameSinkManager(
mojom::FrameSinkManagerParamsPtr params) {
DCHECK(compositor_thread_task_runner_);
DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
if (!gpu_service_ || !gpu_service_->is_initialized()) {
DCHECK(pending_frame_sink_manager_params_.is_null());
pending_frame_sink_manager_params_ = std::move(params);
return;
}
CreateFrameSinkManagerInternal(std::move(params));
}
void VizMainImpl::CreateFrameSinkManagerInternal(
mojom::FrameSinkManagerParamsPtr params) {
DCHECK(!gpu_command_service_);
DCHECK(gpu_service_);
DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
gpu_command_service_ = base::MakeRefCounted<gpu::GpuInProcessThreadService>(
gpu_thread_task_runner_, gpu_service_->sync_point_manager(),
gpu_service_->mailbox_manager(), gpu_service_->share_group(),
gpu_service_->gpu_feature_info(),
gpu_service_->gpu_channel_manager()->gpu_preferences());
compositor_thread_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&VizMainImpl::CreateFrameSinkManagerOnCompositorThread,
base::Unretained(this), std::move(params)));
}
void VizMainImpl::CreateFrameSinkManagerOnCompositorThread(
mojom::FrameSinkManagerParamsPtr params) {
DCHECK(!frame_sink_manager_);
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
display_provider_ = std::make_unique<GpuDisplayProvider>(
params->restart_id, gpu_service_.get(), gpu_command_service_,
gpu_service_->gpu_channel_manager(),
command_line->HasSwitch(switches::kHeadless),
command_line->HasSwitch(switches::kRunAllCompositorStagesBeforeDraw));
mojom::FrameSinkManagerClientPtr client(
std::move(params->frame_sink_manager_client));
base::Optional<uint32_t> activation_deadline_in_frames;
if (params->use_activation_deadline)
activation_deadline_in_frames = params->activation_deadline_in_frames;
frame_sink_manager_ = std::make_unique<FrameSinkManagerImpl>(
activation_deadline_in_frames, display_provider_.get());
frame_sink_manager_->BindAndSetClient(std::move(params->frame_sink_manager),
nullptr, std::move(client));
}
void VizMainImpl::TearDownOnCompositorThread() {
frame_sink_manager_.reset();
display_provider_.reset();
}
void VizMainImpl::PreSandboxStartup() {
// TODO(sad): https://crbug.com/645602
}
bool VizMainImpl::EnsureSandboxInitialized(
gpu::GpuWatchdogThread* watchdog_thread,
const gpu::GPUInfo* gpu_info,
const gpu::GpuPreferences& gpu_prefs) {
// TODO(sad): https://crbug.com/645602
return true;
}
} // namespace viz