blob: 24440868b051ba99064c71b840ba4aa35cb9ae17 [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 "content/browser/gpu/gpu_client_impl.h"
#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/common/child_process_host_impl.h"
#include "content/public/browser/browser_thread.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"
namespace content {
// static
std::unique_ptr<GpuClient, BrowserThread::DeleteOnIOThread> GpuClient::Create(
ui::mojom::GpuRequest request,
ConnectionErrorHandlerClosure connection_error_handler) {
std::unique_ptr<GpuClientImpl, BrowserThread::DeleteOnIOThread> gpu_client(
new GpuClientImpl(ChildProcessHostImpl::GenerateChildProcessUniqueId()));
gpu_client->SetConnectionErrorHandler(std::move(connection_error_handler));
gpu_client->Add(std::move(request));
return gpu_client;
}
GpuClientImpl::GpuClientImpl(int client_id)
: client_id_(client_id), weak_factory_(this) {
gpu_bindings_.set_connection_error_handler(
base::Bind(&GpuClientImpl::OnError, base::Unretained(this),
ErrorReason::kConnectionLost));
}
GpuClientImpl::~GpuClientImpl() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
gpu_bindings_.CloseAllBindings();
OnError(ErrorReason::kInDestructor);
}
void GpuClientImpl::Add(ui::mojom::GpuRequest request) {
gpu_bindings_.AddBinding(this, std::move(request));
}
void GpuClientImpl::OnError(ErrorReason reason) {
ClearCallback();
if (gpu_bindings_.empty()) {
BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager =
BrowserGpuMemoryBufferManager::current();
if (gpu_memory_buffer_manager)
gpu_memory_buffer_manager->ProcessRemoved(client_id_);
}
if (reason == ErrorReason::kConnectionLost && connection_error_handler_)
std::move(connection_error_handler_).Run(this);
}
void GpuClientImpl::PreEstablishGpuChannel() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(&GpuClientImpl::EstablishGpuChannel,
base::Unretained(this), EstablishGpuChannelCallback()));
}
void GpuClientImpl::SetConnectionErrorHandler(
ConnectionErrorHandlerClosure connection_error_handler) {
connection_error_handler_ = std::move(connection_error_handler);
}
void GpuClientImpl::OnEstablishGpuChannel(
mojo::ScopedMessagePipeHandle channel_handle,
const gpu::GPUInfo& gpu_info,
const gpu::GpuFeatureInfo& gpu_feature_info,
GpuProcessHost::EstablishChannelStatus status) {
DCHECK_EQ(channel_handle.is_valid(),
status == GpuProcessHost::EstablishChannelStatus::SUCCESS);
gpu_channel_requested_ = false;
EstablishGpuChannelCallback callback = std::move(callback_);
DCHECK(!callback_);
if (status == GpuProcessHost::EstablishChannelStatus::GPU_HOST_INVALID) {
// 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);
return;
}
if (status == GpuProcessHost::EstablishChannelStatus::SUCCESS) {
// 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;
}
}
void GpuClientImpl::OnCreateGpuMemoryBuffer(
CreateGpuMemoryBufferCallback callback,
const gfx::GpuMemoryBufferHandle& handle) {
std::move(callback).Run(handle);
}
void GpuClientImpl::ClearCallback() {
if (!callback_)
return;
EstablishGpuChannelCallback callback = std::move(callback_);
std::move(callback).Run(client_id_, mojo::ScopedMessagePipeHandle(),
gpu::GPUInfo(), gpu::GpuFeatureInfo());
DCHECK(!callback_);
}
void GpuClientImpl::EstablishGpuChannel(EstablishGpuChannelCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// 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 PreEstablishGpyChannel() 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_);
DCHECK(!channel_handle_.is_valid());
}
return;
}
GpuProcessHost* host = GpuProcessHost::Get();
if (!host) {
if (callback) {
std::move(callback).Run(client_id_, mojo::ScopedMessagePipeHandle(),
gpu::GPUInfo(), gpu::GpuFeatureInfo());
}
return;
}
callback_ = std::move(callback);
if (gpu_channel_requested_)
return;
gpu_channel_requested_ = true;
bool preempts = false;
bool allow_view_command_buffers = false;
bool allow_real_time_streams = false;
host->EstablishGpuChannel(
client_id_,
ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(client_id_),
preempts, allow_view_command_buffers, allow_real_time_streams,
base::Bind(&GpuClientImpl::OnEstablishGpuChannel,
weak_factory_.GetWeakPtr()));
}
void GpuClientImpl::CreateJpegDecodeAccelerator(
media::mojom::JpegDecodeAcceleratorRequest jda_request) {
GpuProcessHost* host = GpuProcessHost::Get();
if (host)
host->gpu_service()->CreateJpegDecodeAccelerator(std::move(jda_request));
}
void GpuClientImpl::CreateVideoEncodeAcceleratorProvider(
media::mojom::VideoEncodeAcceleratorProviderRequest vea_provider_request) {
GpuProcessHost* host = GpuProcessHost::Get();
if (!host)
return;
host->gpu_service()->CreateVideoEncodeAcceleratorProvider(
std::move(vea_provider_request));
}
void GpuClientImpl::CreateGpuMemoryBuffer(
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
ui::mojom::GpuMemoryBufferFactory::CreateGpuMemoryBufferCallback callback) {
DCHECK(BrowserGpuMemoryBufferManager::current());
base::CheckedNumeric<int> bytes = size.width();
bytes *= size.height();
if (!bytes.IsValid()) {
OnCreateGpuMemoryBuffer(std::move(callback), gfx::GpuMemoryBufferHandle());
return;
}
BrowserGpuMemoryBufferManager::current()
->AllocateGpuMemoryBufferForChildProcess(
id, size, format, usage, client_id_,
base::BindOnce(&GpuClientImpl::OnCreateGpuMemoryBuffer,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void GpuClientImpl::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
const gpu::SyncToken& sync_token) {
DCHECK(BrowserGpuMemoryBufferManager::current());
BrowserGpuMemoryBufferManager::current()->ChildProcessDeletedGpuMemoryBuffer(
id, client_id_, sync_token);
}
void GpuClientImpl::CreateGpuMemoryBufferFactory(
ui::mojom::GpuMemoryBufferFactoryRequest request) {
gpu_memory_buffer_factory_bindings_.AddBinding(this, std::move(request));
}
} // namespace content