blob: fc57d02278b6c1dbbaa41c987e92067523e64e5d [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/host/gpu_client.h"
#include <utility>
#include "base/functional/bind.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/checked_math.h"
#include "base/task/single_thread_task_runner.h"
#include "build/chromeos_buildflags.h"
#include "components/viz/host/gpu_host_impl.h"
#include "components/viz/host/host_gpu_memory_buffer_manager.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "gpu/ipc/common/gpu_memory_buffer_impl.h"
#include "gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.h"
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "services/viz/privileged/mojom/gl/gpu_service.mojom.h"
#if !BUILDFLAG(IS_CHROMEOS)
#include "base/feature_list.h"
#include "components/ml/webnn/features.mojom-features.h"
#endif // !BUILDFLAG(IS_CHROMEOS)
namespace viz {
GpuClient::GpuClient(std::unique_ptr<GpuClientDelegate> delegate,
int client_id,
uint64_t client_tracing_id,
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: delegate_(std::move(delegate)),
client_id_(client_id),
client_tracing_id_(client_tracing_id),
task_runner_(std::move(task_runner)) {
DCHECK(delegate_);
gpu_receivers_.set_disconnect_handler(
base::BindRepeating(&GpuClient::OnError, base::Unretained(this),
ErrorReason::kConnectionLost));
}
GpuClient::~GpuClient() {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
gpu_receivers_.Clear();
OnError(ErrorReason::kInDestructor);
}
void GpuClient::Add(mojo::PendingReceiver<mojom::Gpu> receiver) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
gpu_receivers_.Add(this, std::move(receiver));
}
void GpuClient::OnError(ErrorReason reason) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
ClearCallback();
if (gpu_receivers_.empty() && delegate_) {
if (auto* gpu_memory_buffer_manager =
delegate_->GetGpuMemoryBufferManager()) {
gpu_memory_buffer_manager->DestroyAllGpuMemoryBufferForClient(client_id_);
}
}
if (reason == ErrorReason::kConnectionLost && connection_error_handler_)
std::move(connection_error_handler_).Run(this);
}
void GpuClient::PreEstablishGpuChannel() {
if (!task_runner_->RunsTasksInCurrentSequence()) {
task_runner_->PostTask(FROM_HERE,
base::BindOnce(&GpuClient::EstablishGpuChannel,
weak_factory_.GetWeakPtr(),
EstablishGpuChannelCallback()));
return;
}
EstablishGpuChannel(EstablishGpuChannelCallback());
}
void GpuClient::SetClientPid(base::ProcessId client_pid) {
if (!task_runner_->RunsTasksInCurrentSequence()) {
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&GpuClient::SetClientPid,
weak_factory_.GetWeakPtr(), client_pid));
return;
}
if (GpuHostImpl* gpu_host = delegate_->EnsureGpuHost())
gpu_host->SetChannelClientPid(client_id_, client_pid);
}
void GpuClient::SetDiskCacheHandle(const gpu::GpuDiskCacheHandle& handle) {
if (!task_runner_->RunsTasksInCurrentSequence()) {
task_runner_->PostTask(FROM_HERE,
base::BindOnce(&GpuClient::SetDiskCacheHandle,
weak_factory_.GetWeakPtr(), handle));
return;
}
if (GpuHostImpl* gpu_host = delegate_->EnsureGpuHost())
gpu_host->SetChannelDiskCacheHandle(client_id_, handle);
}
void GpuClient::RemoveDiskCacheHandles() {
if (!task_runner_->RunsTasksInCurrentSequence()) {
task_runner_->PostTask(FROM_HERE,
base::BindOnce(&GpuClient::RemoveDiskCacheHandles,
weak_factory_.GetWeakPtr()));
return;
}
if (GpuHostImpl* gpu_host = delegate_->EnsureGpuHost())
gpu_host->RemoveChannelDiskCacheHandles(client_id_);
}
void GpuClient::SetConnectionErrorHandler(
ConnectionErrorHandlerClosure connection_error_handler) {
connection_error_handler_ = std::move(connection_error_handler);
}
base::WeakPtr<GpuClient> GpuClient::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
#if !BUILDFLAG(IS_CHROMEOS)
void GpuClient::BindWebNNContextProvider(
mojo::PendingReceiver<webnn::mojom::WebNNContextProvider> receiver) {
if (auto* gpu_host = delegate_->EnsureGpuHost()) {
gpu_host->gpu_service()->BindWebNNContextProvider(std::move(receiver),
client_id_);
}
}
#endif // !BUILDFLAG(IS_CHROMEOS)
void GpuClient::OnEstablishGpuChannel(
mojo::ScopedMessagePipeHandle channel_handle,
const gpu::GPUInfo& gpu_info,
const gpu::GpuFeatureInfo& gpu_feature_info,
const gpu::SharedImageCapabilities& shared_image_capabilities,
GpuHostImpl::EstablishChannelStatus status) {
DCHECK_EQ(channel_handle.is_valid(),
status == GpuHostImpl::EstablishChannelStatus::kSuccess);
gpu_channel_requested_ = false;
EstablishGpuChannelCallback callback = std::move(callback_);
if (status == GpuHostImpl::EstablishChannelStatus::kGpuHostInvalid) {
// GPU process may have crashed or been killed. Try again.
EstablishGpuChannel(std::move(callback));
return;
}
if (callback) {
// A request is waiting.
std::move(callback).Run(client_id_, std::move(channel_handle), gpu_info,
gpu_feature_info, shared_image_capabilities);
return;
}
if (status == GpuHostImpl::EstablishChannelStatus::kSuccess) {
// This is the case we pre-establish a channel before a request arrives.
// Cache the channel for a future request.
channel_handle_ = std::move(channel_handle);
gpu_info_ = gpu_info;
gpu_feature_info_ = gpu_feature_info;
shared_image_capabilities_ = shared_image_capabilities;
}
}
void GpuClient::ClearCallback() {
if (!callback_)
return;
EstablishGpuChannelCallback callback = std::move(callback_);
std::move(callback).Run(client_id_, mojo::ScopedMessagePipeHandle(),
gpu::GPUInfo(), gpu::GpuFeatureInfo(),
gpu::SharedImageCapabilities());
}
void GpuClient::EstablishGpuChannel(EstablishGpuChannelCallback callback) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
// At most one channel should be requested. So clear previous request first.
ClearCallback();
if (channel_handle_.is_valid()) {
// If a channel has been pre-established and cached,
// 1) if callback is valid, return it right away.
// 2) if callback is empty, it's PreEstablishGpuChannel() being called
// more than once, no need to do anything.
if (callback) {
std::move(callback).Run(client_id_, std::move(channel_handle_), gpu_info_,
gpu_feature_info_, shared_image_capabilities_);
DCHECK(!channel_handle_.is_valid());
}
return;
}
GpuHostImpl* gpu_host = delegate_->EnsureGpuHost();
if (!gpu_host) {
if (callback) {
std::move(callback).Run(client_id_, mojo::ScopedMessagePipeHandle(),
gpu::GPUInfo(), gpu::GpuFeatureInfo(),
gpu::SharedImageCapabilities());
}
return;
}
callback_ = std::move(callback);
if (gpu_channel_requested_)
return;
gpu_channel_requested_ = true;
const bool is_gpu_host = false;
gpu_host->EstablishGpuChannel(
client_id_, client_tracing_id_, is_gpu_host, false,
base::BindOnce(&GpuClient::OnEstablishGpuChannel,
weak_factory_.GetWeakPtr()));
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
void GpuClient::CreateJpegDecodeAccelerator(
mojo::PendingReceiver<chromeos_camera::mojom::MjpegDecodeAccelerator>
jda_receiver) {
if (auto* gpu_host = delegate_->EnsureGpuHost()) {
gpu_host->gpu_service()->CreateJpegDecodeAccelerator(
std::move(jda_receiver));
}
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void GpuClient::CreateVideoEncodeAcceleratorProvider(
mojo::PendingReceiver<media::mojom::VideoEncodeAcceleratorProvider>
vea_provider_receiver) {
if (auto* gpu_host = delegate_->EnsureGpuHost()) {
gpu_host->gpu_service()->CreateVideoEncodeAcceleratorProvider(
std::move(vea_provider_receiver));
}
}
void GpuClient::CreateClientGpuMemoryBufferFactory(
mojo::PendingReceiver<gpu::mojom::ClientGmbInterface> receiver) {
// Send the PendingReceiver to GpuService via IPC.
if (auto* gpu_host = delegate_->EnsureGpuHost()) {
gpu_host->gpu_service()->BindClientGmbInterface(std::move(receiver),
client_id_);
} else {
receiver.ResetWithReason(0, "Can not bind the ClientGmbInterface.");
}
}
} // namespace viz