[go: nahoru, domu]

blob: 1d42308fd09cbe0e745b046c50659dd084777608 [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/gl/gpu_service_impl.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/no_destructor.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/viz/common/features.h"
#include "components/viz/common/gpu/metal_context_provider.h"
#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/command_buffer/service/scheduler.h"
#include "gpu/command_buffer/service/shared_context_state.h"
#include "gpu/command_buffer/service/skia_utils.h"
#include "gpu/command_buffer/service/sync_point_manager.h"
#include "gpu/config/dx_diag_node.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_info_collector.h"
#include "gpu/config/gpu_switches.h"
#include "gpu/config/gpu_util.h"
#include "gpu/ipc/common/gpu_client_ids.h"
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "gpu/ipc/common/gpu_peak_memory.h"
#include "gpu/ipc/common/memory_stats.h"
#include "gpu/ipc/in_process_command_buffer.h"
#include "gpu/ipc/service/gpu_channel.h"
#include "gpu/ipc/service/gpu_channel_manager.h"
#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
#include "gpu/ipc/service/gpu_watchdog_thread.h"
#include "gpu/ipc/service/image_decode_accelerator_worker.h"
#include "gpu/vulkan/buildflags.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_sync_channel.h"
#include "ipc/ipc_sync_message_filter.h"
#include "media/gpu/buildflags.h"
#include "media/gpu/gpu_video_accelerator_util.h"
#include "media/gpu/gpu_video_encode_accelerator_factory.h"
#include "media/gpu/ipc/service/gpu_video_decode_accelerator.h"
#include "media/gpu/ipc/service/media_gpu_channel_manager.h"
#include "media/mojo/services/mojo_video_encode_accelerator_provider.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "skia/buildflags.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h"
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_switches.h"
#include "ui/gl/gl_utils.h"
#include "ui/gl/gpu_switching_manager.h"
#include "ui/gl/init/create_gr_gl_interface.h"
#include "ui/gl/init/gl_factory.h"
#include "url/gurl.h"
#if BUILDFLAG(USE_VAAPI)
#include "media/gpu/vaapi/vaapi_image_decode_accelerator_worker.h"
#endif // BUILDFLAG(USE_VAAPI)
#if defined(OS_ANDROID)
#include "components/viz/service/gl/throw_uncaught_exception.h"
#include "media/base/android/media_codec_util.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "components/arc/video_accelerator/gpu_arc_video_decode_accelerator.h"
#include "components/arc/video_accelerator/gpu_arc_video_encode_accelerator.h"
#include "components/arc/video_accelerator/gpu_arc_video_protected_buffer_allocator.h"
#include "components/arc/video_accelerator/protected_buffer_manager.h"
#include "components/arc/video_accelerator/protected_buffer_manager_proxy.h"
#include "components/chromeos_camera/gpu_mjpeg_decode_accelerator_factory.h"
#include "components/chromeos_camera/mojo_jpeg_encode_accelerator_service.h"
#include "components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if defined(OS_WIN)
#include "ui/gl/direct_composition_surface_win.h"
#endif
#if defined(OS_APPLE)
#include "ui/base/cocoa/quartz_util.h"
#endif
#if BUILDFLAG(SKIA_USE_DAWN)
#include "components/viz/common/gpu/dawn_context_provider.h"
#endif
#if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX)
#include "base/test/clang_profiling.h"
#endif
#if BUILDFLAG(ENABLE_VULKAN)
#include "components/viz/common/gpu/vulkan_context_provider.h"
#include "components/viz/common/gpu/vulkan_in_process_context_provider.h"
#endif
namespace viz {
namespace {
using LogCallback = base::RepeatingCallback<
void(int severity, const std::string& header, const std::string& message)>;
struct LogMessage {
LogMessage(int severity,
const std::string& header,
const std::string& message)
: severity(severity),
header(std::move(header)),
message(std::move(message)) {}
const int severity;
const std::string header;
const std::string message;
};
// Forward declare log handlers so they can be used within LogMessageManager.
bool PreInitializeLogHandler(int severity,
const char* file,
int line,
size_t message_start,
const std::string& message);
bool PostInitializeLogHandler(int severity,
const char* file,
int line,
size_t message_start,
const std::string& message);
// Class which manages LOG() message forwarding before and after GpuServiceImpl
// InitializeWithHost(). Prior to initialize, log messages are deferred and kept
// within the class. During initialize, InstallPostInitializeLogHandler() will
// be called to flush deferred messages and route new ones directly to GpuHost.
class LogMessageManager {
public:
LogMessageManager() = default;
~LogMessageManager() = delete;
// Queues a deferred LOG() message into |deferred_messages_| unless
// |log_callback_| has been set -- in which case RouteMessage() is called.
void AddDeferredMessage(int severity,
const std::string& header,
const std::string& message) {
base::AutoLock lock(message_lock_);
// During InstallPostInitializeLogHandler() there's a brief window where a
// call into this function may be waiting on |message_lock_|, so we need to
// check if |log_callback_| was set once we get the lock.
if (log_callback_) {
RouteMessage(severity, std::move(header), std::move(message));
return;
}
// Otherwise just queue the message for InstallPostInitializeLogHandler() to
// forward later.
deferred_messages_.emplace_back(severity, std::move(header),
std::move(message));
}
// Used after InstallPostInitializeLogHandler() to route messages directly to
// |log_callback_|; avoids the need for a global lock.
void RouteMessage(int severity,
const std::string& header,
const std::string& message) {
log_callback_.Run(severity, std::move(header), std::move(message));
}
// If InstallPostInitializeLogHandler() will never be called, this method is
// called prior to process exit to ensure logs are forwarded.
void FlushMessages(mojom::GpuHost* gpu_host) {
base::AutoLock lock(message_lock_);
for (auto& log : deferred_messages_) {
gpu_host->RecordLogMessage(log.severity, std::move(log.header),
std::move(log.message));
}
deferred_messages_.clear();
}
// Used prior to InitializeWithHost() during GpuMain startup to ensure logs
// aren't lost before initialize.
void InstallPreInitializeLogHandler() {
DCHECK(!log_callback_);
logging::SetLogMessageHandler(PreInitializeLogHandler);
}
// Called by InitializeWithHost() to take over logging from the
// PostInitializeLogHandler(). Flushes all deferred messages.
void InstallPostInitializeLogHandler(LogCallback log_callback) {
base::AutoLock lock(message_lock_);
DCHECK(!log_callback_);
log_callback_ = std::move(log_callback);
for (auto& log : deferred_messages_)
RouteMessage(log.severity, std::move(log.header), std::move(log.message));
deferred_messages_.clear();
logging::SetLogMessageHandler(PostInitializeLogHandler);
}
// Called when it's no longer safe to invoke |log_callback_|.
void ShutdownLogging() { logging::SetLogMessageHandler(nullptr); }
private:
base::Lock message_lock_;
std::vector<LogMessage> deferred_messages_ GUARDED_BY(message_lock_);
// Set once under |mesage_lock_|, but may be accessed without lock after that.
LogCallback log_callback_;
};
LogMessageManager* GetLogMessageManager() {
static base::NoDestructor<LogMessageManager> message_manager;
return message_manager.get();
}
bool PreInitializeLogHandler(int severity,
const char* file,
int line,
size_t message_start,
const std::string& message) {
GetLogMessageManager()->AddDeferredMessage(severity,
message.substr(0, message_start),
message.substr(message_start));
return false;
}
bool PostInitializeLogHandler(int severity,
const char* file,
int line,
size_t message_start,
const std::string& message) {
GetLogMessageManager()->RouteMessage(severity,
message.substr(0, message_start),
message.substr(message_start));
return false;
}
bool IsAcceleratedJpegDecodeSupported() {
#if BUILDFLAG(IS_CHROMEOS_ASH)
return chromeos_camera::GpuMjpegDecodeAcceleratorFactory::
IsAcceleratedJpegDecodeSupported();
#else
return false;
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
void GetVideoCapabilities(const gpu::GpuPreferences& gpu_preferences,
const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
gpu::GPUInfo* gpu_info) {
// Due to https://crbug.com/709631, we don't want to query Android video
// decode/encode capabilities during startup. The renderer needs this info
// though, so assume some baseline capabilities.
#if defined(OS_ANDROID)
// Note: Video encoding on Android relies on MediaCodec, so all cases
// where it's disabled for decoding it is also disabled for encoding.
if (gpu_preferences.disable_accelerated_video_decode ||
gpu_preferences.disable_accelerated_video_encode) {
return;
}
auto& encoding_profiles =
gpu_info->video_encode_accelerator_supported_profiles;
gpu::VideoEncodeAcceleratorSupportedProfile vea_profile;
vea_profile.max_resolution = gfx::Size(1280, 720);
vea_profile.max_framerate_numerator = 30;
vea_profile.max_framerate_denominator = 1;
if (media::MediaCodecUtil::IsVp8EncoderAvailable()) {
vea_profile.profile = gpu::VP8PROFILE_ANY;
encoding_profiles.push_back(vea_profile);
}
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
if (media::MediaCodecUtil::IsH264EncoderAvailable(/*use_codec_list*/ false)) {
vea_profile.profile = gpu::H264PROFILE_BASELINE;
encoding_profiles.push_back(vea_profile);
}
#endif
// Note: Since Android doesn't have to support PPAPI/Flash, we have not
// returned the decoder profiles here since https://crrev.com/665999.
#else
gpu_info->video_decode_accelerator_capabilities =
media::GpuVideoDecodeAccelerator::GetCapabilities(gpu_preferences,
gpu_workarounds);
gpu_info->video_encode_accelerator_supported_profiles =
media::GpuVideoAcceleratorUtil::ConvertMediaToGpuEncodeProfiles(
media::GpuVideoEncodeAcceleratorFactory::GetSupportedProfiles(
gpu_preferences, gpu_workarounds));
#endif
}
// Returns a callback which does a PostTask to run |callback| on the |runner|
// task runner.
template <typename... Params>
base::OnceCallback<void(Params&&...)> WrapCallback(
scoped_refptr<base::SingleThreadTaskRunner> runner,
base::OnceCallback<void(Params...)> callback) {
return base::BindOnce(
[](base::SingleThreadTaskRunner* runner,
base::OnceCallback<void(Params && ...)> callback, Params&&... params) {
runner->PostTask(FROM_HERE,
base::BindOnce(std::move(callback),
std::forward<Params>(params)...));
},
base::RetainedRef(std::move(runner)), std::move(callback));
}
} // namespace
GpuServiceImpl::GpuServiceImpl(
const gpu::GPUInfo& gpu_info,
std::unique_ptr<gpu::GpuWatchdogThread> watchdog_thread,
scoped_refptr<base::SingleThreadTaskRunner> io_runner,
const gpu::GpuFeatureInfo& gpu_feature_info,
const gpu::GpuPreferences& gpu_preferences,
const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu,
const base::Optional<gpu::GpuFeatureInfo>&
gpu_feature_info_for_hardware_gpu,
const gfx::GpuExtraInfo& gpu_extra_info,
gpu::VulkanImplementation* vulkan_implementation,
base::OnceCallback<void(base::Optional<ExitCode>)> exit_callback)
: main_runner_(base::ThreadTaskRunnerHandle::Get()),
io_runner_(std::move(io_runner)),
watchdog_thread_(std::move(watchdog_thread)),
gpu_preferences_(gpu_preferences),
gpu_info_(gpu_info),
gpu_feature_info_(gpu_feature_info),
gpu_info_for_hardware_gpu_(gpu_info_for_hardware_gpu),
gpu_feature_info_for_hardware_gpu_(gpu_feature_info_for_hardware_gpu),
gpu_extra_info_(gpu_extra_info),
#if BUILDFLAG(ENABLE_VULKAN)
vulkan_implementation_(vulkan_implementation),
#endif
exit_callback_(std::move(exit_callback)) {
DCHECK(!io_runner_->BelongsToCurrentThread());
DCHECK(exit_callback_);
#if BUILDFLAG(IS_CHROMEOS_ASH)
protected_buffer_manager_ = new arc::ProtectedBufferManager();
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
GrContextOptions context_options =
GetDefaultGrContextOptions(gpu_preferences_.gr_context_type);
if (gpu_preferences_.force_max_texture_size) {
context_options.fMaxTextureSizeOverride =
gpu_preferences_.force_max_texture_size;
}
#if BUILDFLAG(ENABLE_VULKAN)
if (vulkan_implementation_) {
bool is_native_vulkan =
gpu_preferences_.use_vulkan == gpu::VulkanImplementationName::kNative ||
gpu_preferences_.use_vulkan ==
gpu::VulkanImplementationName::kForcedNative;
// With swiftshader the vendor_id is 0xffff. For some tests gpu_info is not
// initialized, so the vendor_id is 0.
bool is_native_gl =
gpu_info_.gpu.vendor_id != 0xffff && gpu_info_.gpu.vendor_id != 0;
// If GL is using a real GPU, the gpu_info will be passed in and vulkan will
// use the same GPU.
vulkan_context_provider_ = VulkanInProcessContextProvider::Create(
vulkan_implementation_,
(is_native_vulkan && is_native_gl) ? &gpu_info : nullptr);
if (vulkan_context_provider_) {
// If Vulkan is supported, then OOP-R is supported.
gpu_info_.oop_rasterization_supported = true;
gpu_feature_info_.status_values[gpu::GPU_FEATURE_TYPE_OOP_RASTERIZATION] =
gpu::kGpuFeatureStatusEnabled;
} else {
DLOG(ERROR) << "Failed to create Vulkan context provider.";
}
}
#endif
#if BUILDFLAG(SKIA_USE_DAWN)
if (gpu_preferences_.gr_context_type == gpu::GrContextType::kDawn) {
dawn_context_provider_ = DawnContextProvider::Create();
if (dawn_context_provider_) {
gpu_info_.oop_rasterization_supported = true;
gpu_feature_info_.status_values[gpu::GPU_FEATURE_TYPE_OOP_RASTERIZATION] =
gpu::kGpuFeatureStatusEnabled;
} else {
DLOG(ERROR) << "Failed to create Dawn context provider.";
}
}
#endif
#if BUILDFLAG(USE_VAAPI_IMAGE_CODECS)
image_decode_accelerator_worker_ =
media::VaapiImageDecodeAcceleratorWorker::Create();
#endif // BUILDFLAG(USE_VAAPI_IMAGE_CODECS)
#if defined(OS_APPLE)
if (gpu_feature_info_.status_values[gpu::GPU_FEATURE_TYPE_METAL] ==
gpu::kGpuFeatureStatusEnabled) {
metal_context_provider_ = MetalContextProvider::Create(context_options);
}
#endif
#if defined(OS_WIN)
auto info_callback = base::BindRepeating(
&GpuServiceImpl::UpdateOverlayAndHDRInfo, weak_ptr_factory_.GetWeakPtr());
gl::DirectCompositionSurfaceWin::SetOverlayHDRGpuInfoUpdateCallback(
info_callback);
#endif
gpu_memory_buffer_factory_ =
gpu::GpuMemoryBufferFactory::CreateNativeType(vulkan_context_provider());
weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
}
GpuServiceImpl::~GpuServiceImpl() {
DCHECK(main_runner_->BelongsToCurrentThread());
// Ensure we don't try to exit when already in the process of exiting.
is_exiting_.Set();
bind_task_tracker_.TryCancelAll();
GetLogMessageManager()->ShutdownLogging();
// Destroy the receiver on the IO thread.
base::WaitableEvent wait;
auto destroy_receiver_task = base::BindOnce(
[](mojo::Receiver<mojom::GpuService>* receiver,
base::WaitableEvent* wait) {
receiver->reset();
wait->Signal();
},
&receiver_, &wait);
if (io_runner_->PostTask(FROM_HERE, std::move(destroy_receiver_task)))
wait.Wait();
if (watchdog_thread_)
watchdog_thread_->OnGpuProcessTearDown();
media_gpu_channel_manager_.reset();
gpu_channel_manager_.reset();
// Scheduler must be destroyed before sync point manager is destroyed.
scheduler_.reset();
owned_sync_point_manager_.reset();
owned_shared_image_manager_.reset();
// The image decode accelerator worker must outlive the GPU channel manager so
// that it doesn't get any decode requests during/after destruction.
DCHECK(!gpu_channel_manager_);
image_decode_accelerator_worker_.reset();
// Signal this event before destroying the child process. That way all
// background threads can cleanup. For example, in the renderer the
// RenderThread instances will be able to notice shutdown before the render
// process begins waiting for them to exit.
if (owned_shutdown_event_)
owned_shutdown_event_->Signal();
}
void GpuServiceImpl::UpdateGPUInfo() {
DCHECK(main_runner_->BelongsToCurrentThread());
DCHECK(!gpu_host_);
gpu::GpuDriverBugWorkarounds gpu_workarounds(
gpu_feature_info_.enabled_gpu_driver_bug_workarounds);
GetVideoCapabilities(gpu_preferences_, gpu_workarounds, &gpu_info_);
gpu_info_.jpeg_decode_accelerator_supported =
IsAcceleratedJpegDecodeSupported();
if (image_decode_accelerator_worker_) {
gpu_info_.image_decode_accelerator_supported_profiles =
image_decode_accelerator_worker_->GetSupportedProfiles();
}
// Record initialization only after collecting the GPU info because that can
// take a significant amount of time.
gpu_info_.initialization_time = base::Time::Now() - start_time_;
}
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,
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.
bool thread_safe_manager = features::ShouldUseRealBuffersForPageFlipTest();
owned_shared_image_manager_ = std::make_unique<gpu::SharedImageManager>(
thread_safe_manager, false /* display_context_on_another_thread */);
shared_image_manager = owned_shared_image_manager_.get();
} else {
// With this feature enabled, we don't expect to receive an external
// SharedImageManager.
DCHECK(!features::ShouldUseRealBuffersForPageFlipTest());
}
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();
}
scheduler_ = std::make_unique<gpu::Scheduler>(
main_runner_, sync_point_manager, gpu_preferences_);
// 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_.get(), 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_.reset(
new media::MediaGpuChannelManager(gpu_channel_manager_.get()));
if (watchdog_thread())
watchdog_thread()->AddPowerObserver();
}
void GpuServiceImpl::Bind(
mojo::PendingReceiver<mojom::GpuService> pending_receiver) {
if (main_runner_->BelongsToCurrentThread()) {
bind_task_tracker_.PostTask(
io_runner_.get(), FROM_HERE,
base::BindOnce(&GpuServiceImpl::Bind, base::Unretained(this),
std::move(pending_receiver)));
return;
}
DCHECK(!receiver_.is_bound());
receiver_.Bind(std::move(pending_receiver));
}
void GpuServiceImpl::DisableGpuCompositing() {
// Can be called from any thread.
gpu_host_->DisableGpuCompositing();
}
scoped_refptr<gpu::SharedContextState> GpuServiceImpl::GetContextState() {
DCHECK(main_runner_->BelongsToCurrentThread());
gpu::ContextResult result;
return gpu_channel_manager_->GetSharedContextState(&result);
}
gpu::ImageFactory* GpuServiceImpl::gpu_image_factory() {
return gpu_memory_buffer_factory_
? gpu_memory_buffer_factory_->AsImageFactory()
: nullptr;
}
// static
void GpuServiceImpl::InstallPreInitializeLogHandler() {
GetLogMessageManager()->InstallPreInitializeLogHandler();
}
// static
void GpuServiceImpl::FlushPreInitializeLogMessages(mojom::GpuHost* gpu_host) {
GetLogMessageManager()->FlushMessages(gpu_host);
}
void GpuServiceImpl::RecordLogMessage(int severity,
const std::string& header,
const std::string& message) {
// This can be run from any thread.
gpu_host_->RecordLogMessage(severity, std::move(header), std::move(message));
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
void GpuServiceImpl::CreateArcVideoDecodeAccelerator(
mojo::PendingReceiver<arc::mojom::VideoDecodeAccelerator> vda_receiver) {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&GpuServiceImpl::CreateArcVideoDecodeAcceleratorOnMainThread,
weak_ptr_, std::move(vda_receiver)));
}
void GpuServiceImpl::CreateArcVideoEncodeAccelerator(
mojo::PendingReceiver<arc::mojom::VideoEncodeAccelerator> vea_receiver) {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&GpuServiceImpl::CreateArcVideoEncodeAcceleratorOnMainThread,
weak_ptr_, std::move(vea_receiver)));
}
void GpuServiceImpl::CreateArcVideoProtectedBufferAllocator(
mojo::PendingReceiver<arc::mojom::VideoProtectedBufferAllocator>
pba_receiver) {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&GpuServiceImpl::CreateArcVideoProtectedBufferAllocatorOnMainThread,
weak_ptr_, std::move(pba_receiver)));
}
void GpuServiceImpl::CreateArcProtectedBufferManager(
mojo::PendingReceiver<arc::mojom::ProtectedBufferManager> pbm_receiver) {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&GpuServiceImpl::CreateArcProtectedBufferManagerOnMainThread,
weak_ptr_, std::move(pbm_receiver)));
}
void GpuServiceImpl::CreateArcVideoDecodeAcceleratorOnMainThread(
mojo::PendingReceiver<arc::mojom::VideoDecodeAccelerator> vda_receiver) {
DCHECK(main_runner_->BelongsToCurrentThread());
mojo::MakeSelfOwnedReceiver(
std::make_unique<arc::GpuArcVideoDecodeAccelerator>(
gpu_preferences_, gpu_channel_manager_->gpu_driver_bug_workarounds(),
protected_buffer_manager_),
std::move(vda_receiver));
}
void GpuServiceImpl::CreateArcVideoEncodeAcceleratorOnMainThread(
mojo::PendingReceiver<arc::mojom::VideoEncodeAccelerator> vea_receiver) {
DCHECK(main_runner_->BelongsToCurrentThread());
mojo::MakeSelfOwnedReceiver(
std::make_unique<arc::GpuArcVideoEncodeAccelerator>(
gpu_preferences_, gpu_channel_manager_->gpu_driver_bug_workarounds()),
std::move(vea_receiver));
}
void GpuServiceImpl::CreateArcVideoProtectedBufferAllocatorOnMainThread(
mojo::PendingReceiver<arc::mojom::VideoProtectedBufferAllocator>
pba_receiver) {
DCHECK(main_runner_->BelongsToCurrentThread());
auto gpu_arc_video_protected_buffer_allocator =
arc::GpuArcVideoProtectedBufferAllocator::Create(
protected_buffer_manager_);
if (!gpu_arc_video_protected_buffer_allocator)
return;
mojo::MakeSelfOwnedReceiver(
std::move(gpu_arc_video_protected_buffer_allocator),
std::move(pba_receiver));
}
void GpuServiceImpl::CreateArcProtectedBufferManagerOnMainThread(
mojo::PendingReceiver<arc::mojom::ProtectedBufferManager> pbm_receiver) {
DCHECK(main_runner_->BelongsToCurrentThread());
mojo::MakeSelfOwnedReceiver(
std::make_unique<arc::GpuArcProtectedBufferManagerProxy>(
protected_buffer_manager_),
std::move(pbm_receiver));
}
void GpuServiceImpl::CreateJpegDecodeAccelerator(
mojo::PendingReceiver<chromeos_camera::mojom::MjpegDecodeAccelerator>
jda_receiver) {
DCHECK(io_runner_->BelongsToCurrentThread());
chromeos_camera::MojoMjpegDecodeAcceleratorService::Create(
std::move(jda_receiver));
}
void GpuServiceImpl::CreateJpegEncodeAccelerator(
mojo::PendingReceiver<chromeos_camera::mojom::JpegEncodeAccelerator>
jea_receiver) {
DCHECK(io_runner_->BelongsToCurrentThread());
chromeos_camera::MojoJpegEncodeAcceleratorService::Create(
std::move(jea_receiver));
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void GpuServiceImpl::CreateVideoEncodeAcceleratorProvider(
mojo::PendingReceiver<media::mojom::VideoEncodeAcceleratorProvider>
vea_provider_receiver) {
DCHECK(io_runner_->BelongsToCurrentThread());
media::MojoVideoEncodeAcceleratorProvider::Create(
std::move(vea_provider_receiver),
base::BindRepeating(&media::GpuVideoEncodeAcceleratorFactory::CreateVEA),
gpu_preferences_, gpu_channel_manager_->gpu_driver_bug_workarounds());
}
void GpuServiceImpl::CreateGpuMemoryBuffer(
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
int client_id,
gpu::SurfaceHandle surface_handle,
CreateGpuMemoryBufferCallback callback) {
DCHECK(io_runner_->BelongsToCurrentThread());
// This needs to happen in the IO thread.
gpu_memory_buffer_factory_->CreateGpuMemoryBufferAsync(
id, size, format, usage, client_id, surface_handle, std::move(callback));
}
void GpuServiceImpl::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
int client_id,
const gpu::SyncToken& sync_token) {
if (io_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuServiceImpl::DestroyGpuMemoryBuffer,
weak_ptr_, id, client_id, sync_token));
return;
}
gpu_channel_manager_->DestroyGpuMemoryBuffer(id, client_id, sync_token);
}
void GpuServiceImpl::GetVideoMemoryUsageStats(
GetVideoMemoryUsageStatsCallback callback) {
if (io_runner_->BelongsToCurrentThread()) {
auto wrap_callback = WrapCallback(io_runner_, std::move(callback));
main_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuServiceImpl::GetVideoMemoryUsageStats,
weak_ptr_, std::move(wrap_callback)));
return;
}
gpu::VideoMemoryUsageStats video_memory_usage_stats;
gpu_channel_manager_->GetVideoMemoryUsageStats(&video_memory_usage_stats);
std::move(callback).Run(video_memory_usage_stats);
}
void GpuServiceImpl::StartPeakMemoryMonitor(uint32_t sequence_num) {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTask(
FROM_HERE,
base::BindOnce(&GpuServiceImpl::StartPeakMemoryMonitorOnMainThread,
weak_ptr_, sequence_num));
}
void GpuServiceImpl::GetPeakMemoryUsage(uint32_t sequence_num,
GetPeakMemoryUsageCallback callback) {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuServiceImpl::GetPeakMemoryUsageOnMainThread,
weak_ptr_, sequence_num, std::move(callback)));
}
void GpuServiceImpl::RequestHDRStatus(RequestHDRStatusCallback callback) {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuServiceImpl::RequestHDRStatusOnMainThread,
weak_ptr_, std::move(callback)));
}
void GpuServiceImpl::RequestHDRStatusOnMainThread(
RequestHDRStatusCallback callback) {
DCHECK(main_runner_->BelongsToCurrentThread());
#if defined(OS_WIN)
hdr_enabled_ = gl::DirectCompositionSurfaceWin::IsHDRSupported();
#endif
io_runner_->PostTask(FROM_HERE,
base::BindOnce(std::move(callback), hdr_enabled_));
}
void GpuServiceImpl::RegisterDisplayContext(
gpu::DisplayContext* display_context) {
DCHECK(main_runner_->BelongsToCurrentThread());
display_contexts_.AddObserver(display_context);
}
void GpuServiceImpl::UnregisterDisplayContext(
gpu::DisplayContext* display_context) {
DCHECK(main_runner_->BelongsToCurrentThread());
display_contexts_.RemoveObserver(display_context);
}
void GpuServiceImpl::LoseAllContexts() {
DCHECK(main_runner_->BelongsToCurrentThread());
if (IsExiting())
return;
for (auto& display_context : display_contexts_)
display_context.MarkContextLost();
gpu_channel_manager_->LoseAllContexts();
}
void GpuServiceImpl::DidCreateContextSuccessfully() {
DCHECK(main_runner_->BelongsToCurrentThread());
gpu_host_->DidCreateContextSuccessfully();
}
void GpuServiceImpl::DidCreateOffscreenContext(const GURL& active_url) {
DCHECK(main_runner_->BelongsToCurrentThread());
gpu_host_->DidCreateOffscreenContext(active_url);
}
void GpuServiceImpl::DidDestroyChannel(int client_id) {
DCHECK(main_runner_->BelongsToCurrentThread());
media_gpu_channel_manager_->RemoveChannel(client_id);
gpu_host_->DidDestroyChannel(client_id);
}
void GpuServiceImpl::DidDestroyAllChannels() {
DCHECK(main_runner_->BelongsToCurrentThread());
gpu_host_->DidDestroyAllChannels();
}
void GpuServiceImpl::DidDestroyOffscreenContext(const GURL& active_url) {
DCHECK(main_runner_->BelongsToCurrentThread());
gpu_host_->DidDestroyOffscreenContext(active_url);
}
void GpuServiceImpl::DidLoseContext(bool offscreen,
gpu::error::ContextLostReason reason,
const GURL& active_url) {
DCHECK(main_runner_->BelongsToCurrentThread());
gpu_host_->DidLoseContext(offscreen, reason, active_url);
}
#if defined(OS_WIN)
void GpuServiceImpl::DidUpdateOverlayInfo(
const gpu::OverlayInfo& overlay_info) {
gpu_host_->DidUpdateOverlayInfo(gpu_info_.overlay_info);
}
void GpuServiceImpl::DidUpdateHDRStatus(bool hdr_enabled) {
gpu_host_->DidUpdateHDRStatus(hdr_enabled);
}
#endif
void GpuServiceImpl::StoreShaderToDisk(int client_id,
const std::string& key,
const std::string& shader) {
DCHECK(main_runner_->BelongsToCurrentThread());
gpu_host_->StoreShaderToDisk(client_id, key, shader);
}
void GpuServiceImpl::MaybeExitOnContextLost() {
MaybeExit(true);
}
bool GpuServiceImpl::IsExiting() const {
return is_exiting_.IsSet();
}
#if defined(OS_WIN)
void GpuServiceImpl::SendCreatedChildWindow(gpu::SurfaceHandle parent_window,
gpu::SurfaceHandle child_window) {
// This can be called from main or display compositor thread.
gpu_host_->SetChildSurface(parent_window, child_window);
}
#endif
void GpuServiceImpl::EstablishGpuChannel(int32_t client_id,
uint64_t client_tracing_id,
bool is_gpu_host,
bool cache_shaders_on_disk,
EstablishGpuChannelCallback callback) {
// This should always be called on the IO thread first.
if (io_runner_->BelongsToCurrentThread()) {
if (IsExiting()) {
// We are already exiting so there is no point in responding. Close the
// receiver so we can safely drop the callback.
receiver_.reset();
return;
}
if (gpu::IsReservedClientId(client_id)) {
// This returns a null handle, which is treated by the client as a failure
// case.
std::move(callback).Run(mojo::ScopedMessagePipeHandle());
return;
}
EstablishGpuChannelCallback wrap_callback = base::BindOnce(
[](scoped_refptr<base::SingleThreadTaskRunner> runner,
EstablishGpuChannelCallback cb,
mojo::ScopedMessagePipeHandle handle) {
runner->PostTask(FROM_HERE,
base::BindOnce(std::move(cb), std::move(handle)));
},
io_runner_, std::move(callback));
main_runner_->PostTask(
FROM_HERE,
base::BindOnce(&GpuServiceImpl::EstablishGpuChannel, weak_ptr_,
client_id, client_tracing_id, is_gpu_host,
cache_shaders_on_disk, std::move(wrap_callback)));
return;
}
gpu::GpuChannel* gpu_channel = gpu_channel_manager_->EstablishChannel(
client_id, client_tracing_id, is_gpu_host, cache_shaders_on_disk);
if (!gpu_channel) {
// This returns a null handle, which is treated by the client as a failure
// case.
std::move(callback).Run(mojo::ScopedMessagePipeHandle());
return;
}
mojo::MessagePipe pipe;
gpu_channel->Init(pipe.handle0.release(), shutdown_event_);
media_gpu_channel_manager_->AddChannel(client_id);
std::move(callback).Run(std::move(pipe.handle1));
}
void GpuServiceImpl::CloseChannel(int32_t client_id) {
if (io_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
FROM_HERE,
base::BindOnce(&GpuServiceImpl::CloseChannel, weak_ptr_, client_id));
return;
}
gpu_channel_manager_->RemoveChannel(client_id);
}
void GpuServiceImpl::LoadedShader(int32_t client_id,
const std::string& key,
const std::string& data) {
if (io_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuServiceImpl::LoadedShader, weak_ptr_,
client_id, key, data));
return;
}
gpu_channel_manager_->PopulateShaderCache(client_id, key, data);
}
void GpuServiceImpl::WakeUpGpu() {
if (io_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuServiceImpl::WakeUpGpu, weak_ptr_));
return;
}
#if defined(OS_ANDROID)
gpu_channel_manager_->WakeUpGpu();
#else
NOTREACHED() << "WakeUpGpu() not supported on this platform.";
#endif
}
void GpuServiceImpl::GpuSwitched(gl::GpuPreference active_gpu_heuristic) {
DVLOG(1) << "GPU: GPU has switched";
if (!in_host_process())
ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched(
active_gpu_heuristic);
}
void GpuServiceImpl::DisplayAdded() {
if (io_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuServiceImpl::DisplayAdded, weak_ptr_));
return;
}
DVLOG(1) << "GPU: A monitor is plugged in";
if (!in_host_process())
ui::GpuSwitchingManager::GetInstance()->NotifyDisplayAdded();
}
void GpuServiceImpl::DisplayRemoved() {
if (io_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuServiceImpl::DisplayRemoved, weak_ptr_));
return;
}
DVLOG(1) << "GPU: A monitor is unplugged ";
if (!in_host_process())
ui::GpuSwitchingManager::GetInstance()->NotifyDisplayRemoved();
}
void GpuServiceImpl::DisplayMetricsChanged() {
if (io_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
FROM_HERE,
base::BindOnce(&GpuServiceImpl::DisplayMetricsChanged, weak_ptr_));
return;
}
DVLOG(1) << "GPU: Display Metrics changed";
if (!in_host_process())
ui::GpuSwitchingManager::GetInstance()->NotifyDisplayMetricsChanged();
}
void GpuServiceImpl::DestroyAllChannels() {
if (io_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
FROM_HERE,
base::BindOnce(&GpuServiceImpl::DestroyAllChannels, weak_ptr_));
return;
}
DVLOG(1) << "GPU: Removing all contexts";
gpu_channel_manager_->DestroyAllChannels();
}
void GpuServiceImpl::OnBackgroundCleanup() {
// Currently only called on Android.
#if defined(OS_ANDROID)
if (io_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
FROM_HERE,
base::BindOnce(&GpuServiceImpl::OnBackgroundCleanup, weak_ptr_));
return;
}
DVLOG(1) << "GPU: Performing background cleanup";
gpu_channel_manager_->OnBackgroundCleanup();
#else
NOTREACHED();
#endif
}
void GpuServiceImpl::OnBackgrounded() {
DCHECK(io_runner_->BelongsToCurrentThread());
if (watchdog_thread_)
watchdog_thread_->OnBackgrounded();
main_runner_->PostTask(
FROM_HERE,
base::BindOnce(&GpuServiceImpl::OnBackgroundedOnMainThread, weak_ptr_));
}
void GpuServiceImpl::OnBackgroundedOnMainThread() {
gpu_channel_manager_->OnApplicationBackgrounded();
}
void GpuServiceImpl::OnForegrounded() {
if (watchdog_thread_)
watchdog_thread_->OnForegrounded();
}
#if !defined(OS_ANDROID)
void GpuServiceImpl::OnMemoryPressure(
::base::MemoryPressureListener::MemoryPressureLevel level) {
// Forward the notification to the registry of MemoryPressureListeners.
base::MemoryPressureListener::NotifyMemoryPressure(level);
}
#endif
#if defined(OS_APPLE)
void GpuServiceImpl::BeginCATransaction() {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTask(FROM_HERE, base::BindOnce(&ui::BeginCATransaction));
}
void GpuServiceImpl::CommitCATransaction(CommitCATransactionCallback callback) {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTaskAndReply(FROM_HERE,
base::BindOnce(&ui::CommitCATransaction),
WrapCallback(io_runner_, std::move(callback)));
}
#endif
#if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX)
void GpuServiceImpl::WriteClangProfilingProfile(
WriteClangProfilingProfileCallback callback) {
base::WriteClangProfilingProfile();
std::move(callback).Run();
}
#endif
void GpuServiceImpl::Crash() {
DCHECK(io_runner_->BelongsToCurrentThread());
gl::Crash();
}
void GpuServiceImpl::Hang() {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTask(FROM_HERE, base::BindOnce(&gl::Hang));
}
void GpuServiceImpl::ThrowJavaException() {
DCHECK(io_runner_->BelongsToCurrentThread());
#if defined(OS_ANDROID)
ThrowUncaughtException();
#else
NOTREACHED() << "Java exception not supported on this platform.";
#endif
}
void GpuServiceImpl::Stop(StopCallback callback) {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTaskAndReply(
FROM_HERE, base::BindOnce(&GpuServiceImpl::MaybeExit, weak_ptr_, false),
std::move(callback));
}
void GpuServiceImpl::StartPeakMemoryMonitorOnMainThread(uint32_t sequence_num) {
gpu_channel_manager_->StartPeakMemoryMonitor(sequence_num);
}
void GpuServiceImpl::GetPeakMemoryUsageOnMainThread(
uint32_t sequence_num,
GetPeakMemoryUsageCallback callback) {
uint64_t peak_memory = 0u;
auto allocation_per_source =
gpu_channel_manager_->GetPeakMemoryUsage(sequence_num, &peak_memory);
io_runner_->PostTask(FROM_HERE,
base::BindOnce(std::move(callback), peak_memory,
std::move(allocation_per_source)));
}
void GpuServiceImpl::MaybeExit(bool for_context_loss) {
DCHECK(main_runner_->BelongsToCurrentThread());
// We can't restart the GPU process when running in the host process.
if (in_host_process())
return;
if (IsExiting() || !exit_callback_)
return;
if (for_context_loss) {
LOG(ERROR) << "Exiting GPU process because some drivers can't recover "
"from errors. GPU process will restart shortly.";
}
is_exiting_.Set();
// For the unsandboxed GPU info collection process used for info collection,
// if we exit immediately, then the reply message could be lost. That's why
// the |exit_callback_| takes the boolean argument.
if (for_context_loss)
std::move(exit_callback_)
.Run(ExitCode::RESULT_CODE_GPU_EXIT_ON_CONTEXT_LOST);
else
std::move(exit_callback_).Run(base::nullopt);
}
gpu::Scheduler* GpuServiceImpl::GetGpuScheduler() {
return scheduler_.get();
}
#if defined(OS_WIN)
void GpuServiceImpl::UpdateOverlayAndHDRInfo() {
gpu::OverlayInfo old_overlay_info = gpu_info_.overlay_info;
gpu::CollectHardwareOverlayInfo(&gpu_info_.overlay_info);
// Update overlay info in the GPU process and send the updated data back to
// the GPU host in the Browser process through mojom if the info has changed.
if (old_overlay_info != gpu_info_.overlay_info)
DidUpdateOverlayInfo(gpu_info_.overlay_info);
// Update HDR status in the GPU process through the GPU host mojom.
bool old_hdr_enabled_status = hdr_enabled_;
hdr_enabled_ = gl::DirectCompositionSurfaceWin::IsHDRSupported();
if (old_hdr_enabled_status != hdr_enabled_)
DidUpdateHDRStatus(hdr_enabled_);
}
#endif
} // namespace viz