| Index: content/common/gpu/client/ipc/chrome/chrome_gpu_channel_host_ipc_transport.cc
|
| diff --git a/content/common/gpu/client/ipc/chrome/chrome_gpu_channel_host_ipc_transport.cc b/content/common/gpu/client/ipc/chrome/chrome_gpu_channel_host_ipc_transport.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c3e57bc36d7cd9531b4d40a1d8f7a3fb8e81ea7a
|
| --- /dev/null
|
| +++ b/content/common/gpu/client/ipc/chrome/chrome_gpu_channel_host_ipc_transport.cc
|
| @@ -0,0 +1,317 @@
|
| +// Copyright 2015 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/common/gpu/client/ipc/chrome/chrome_gpu_channel_host_ipc_transport.h"
|
| +
|
| +#include "base/threading/thread_restrictions.h"
|
| +#include "content/common/gpu/client/gpu_channel_host_factory.h"
|
| +#include "content/common/gpu/client/ipc/chrome/chrome_command_buffer_ipc_transport.h"
|
| +#include "content/common/gpu/client/ipc/chrome/chrome_gpu_jpeg_decode_accelerator_host_ipc_transport.h"
|
| +#include "content/common/gpu/gpu_messages.h"
|
| +#include "ipc/ipc_sync_channel.h"
|
| +
|
| +namespace content {
|
| +
|
| +// static
|
| +scoped_ptr<GpuChannelHostIPCTransport>
|
| +ChromeGpuChannelHostIPCTransport::Create() {
|
| + return make_scoped_ptr<GpuChannelHostIPCTransport>(
|
| + new ChromeGpuChannelHostIPCTransport());
|
| +}
|
| +
|
| +ChromeGpuChannelHostIPCTransport::~ChromeGpuChannelHostIPCTransport() {
|
| + DCHECK(factory_->IsMainThread());
|
| +}
|
| +
|
| +void ChromeGpuChannelHostIPCTransport::BindToService(
|
| + GpuChannelHostFactory* factory,
|
| + int channel_id,
|
| + const IPC::ChannelHandle& channel_handle,
|
| + base::WaitableEvent* shutdown_event) {
|
| + factory_ = factory;
|
| + channel_id_ = channel_id;
|
| + DCHECK(factory_->IsMainThread());
|
| + // Open a channel to the GPU process. We pass NULL as the main listener here
|
| + // since we need to filter everything to route it to the right thread.
|
| + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
|
| + factory_->GetIOThreadTaskRunner();
|
| + channel_ =
|
| + IPC::SyncChannel::Create(channel_handle, IPC::Channel::MODE_CLIENT, NULL,
|
| + io_task_runner.get(), true, shutdown_event);
|
| +
|
| + sync_filter_ = channel_->CreateSyncMessageFilter();
|
| +
|
| + channel_filter_ = new MessageFilter();
|
| +
|
| + // Install the filter last, because we intercept all leftover
|
| + // messages.
|
| + channel_->AddFilter(channel_filter_.get());
|
| +}
|
| +
|
| +bool ChromeGpuChannelHostIPCTransport::Send(IPC::Message* msg) {
|
| + // Callee takes ownership of message, regardless of whether Send is
|
| + // successful. See IPC::Sender.
|
| + scoped_ptr<IPC::Message> message(msg);
|
| + // The GPU process never sends synchronous IPCs so clear the unblock flag to
|
| + // preserve order.
|
| + message->set_unblock(false);
|
| +
|
| + // Currently we need to choose between two different mechanisms for sending.
|
| + // On the main thread we use the regular channel Send() method, on another
|
| + // thread we use SyncMessageFilter. We also have to be careful interpreting
|
| + // IsMainThread() since it might return false during shutdown,
|
| + // impl we are actually calling from the main thread (discard message then).
|
| + //
|
| + // TODO: Can we just always use sync_filter_ since we setup the channel
|
| + // without a main listener?
|
| + if (factory_->IsMainThread()) {
|
| + // channel_ is only modified on the main thread, so we don't need to take a
|
| + // lock here.
|
| + if (!channel_) {
|
| + DVLOG(1) << "GpuChannelHost::Send failed: Channel already destroyed";
|
| + return false;
|
| + }
|
| + // http://crbug.com/125264
|
| + base::ThreadRestrictions::ScopedAllowWait allow_wait;
|
| + bool result = channel_->Send(message.release());
|
| + if (!result)
|
| + DVLOG(1) << "GpuChannelHost::Send failed: Channel::Send failed";
|
| + return result;
|
| + }
|
| +
|
| + bool result = sync_filter_->Send(message.release());
|
| + return result;
|
| +}
|
| +
|
| +int32_t ChromeGpuChannelHostIPCTransport::GenerateRouteID() {
|
| + return next_route_id_.GetNext();
|
| +}
|
| +
|
| +void ChromeGpuChannelHostIPCTransport::AddRoute(
|
| + int route_id,
|
| + base::WeakPtr<IPC::Listener> listener) {
|
| + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
|
| + factory_->GetIOThreadTaskRunner();
|
| + io_task_runner->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&ChromeGpuChannelHostIPCTransport::MessageFilter::AddRoute,
|
| + channel_filter_.get(), route_id, listener,
|
| + base::ThreadTaskRunnerHandle::Get()));
|
| +}
|
| +
|
| +void ChromeGpuChannelHostIPCTransport::AddRouteOnIO(
|
| + int route_id,
|
| + base::WeakPtr<IPC::Listener> listener) {
|
| + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
|
| + factory_->GetIOThreadTaskRunner();
|
| + io_task_runner->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&ChromeGpuChannelHostIPCTransport::MessageFilter::AddRoute,
|
| + channel_filter_.get(), route_id, listener, io_task_runner));
|
| +}
|
| +
|
| +void ChromeGpuChannelHostIPCTransport::RemoveRoute(int route_id) {
|
| + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
|
| + factory_->GetIOThreadTaskRunner();
|
| + io_task_runner->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&ChromeGpuChannelHostIPCTransport::MessageFilter::RemoveRoute,
|
| + channel_filter_.get(), route_id));
|
| +}
|
| +
|
| +ChromeGpuChannelHostIPCTransport::ChromeGpuChannelHostIPCTransport()
|
| + : factory_(nullptr), channel_id_(0) {
|
| + next_route_id_.GetNext();
|
| +}
|
| +
|
| +bool ChromeGpuChannelHostIPCTransport::AsyncFlush(
|
| + CommandBufferIPCTransport* transport,
|
| + int32_t put_offset,
|
| + uint32_t flush_count,
|
| + const std::vector<ui::LatencyInfo>& latency_info) {
|
| + return Send(new GpuCommandBufferMsg_AsyncFlush(
|
| + static_cast<ChromeCommandBufferIPCTransport*>(transport)->route_id(),
|
| + put_offset, flush_count, latency_info));
|
| +}
|
| +
|
| +bool ChromeGpuChannelHostIPCTransport::CreateJpegDecoder(
|
| + GpuJpegDecodeAcceleratorHostIPCTransport* jpeg_decode_transport,
|
| + bool* succeeded) {
|
| + ChromeGpuJpegDecodeAcceleratorHostIPCTransport* chrome_ipc_transport =
|
| + static_cast<ChromeGpuJpegDecodeAcceleratorHostIPCTransport*>(
|
| + jpeg_decode_transport);
|
| + chrome_ipc_transport->BindToService(this);
|
| + int route_id = chrome_ipc_transport->route_id();
|
| + bool sent = Send(new GpuMsg_CreateJpegDecoder(route_id, succeeded));
|
| +
|
| + if (sent && *succeeded)
|
| + AddRouteOnIO(route_id, chrome_ipc_transport->GetWeakPtrForIO());
|
| +
|
| + return sent;
|
| +}
|
| +
|
| +bool ChromeGpuChannelHostIPCTransport::CreateViewCommandBuffer(
|
| + uint32_t surface_id,
|
| + const GpuCreateCommandBufferConfig& init_params,
|
| + CommandBufferIPCTransport* command_buffer_transport,
|
| + CreateCommandBufferResult* result) {
|
| + ChromeCommandBufferIPCTransport* chrome_ipc_transport =
|
| + static_cast<ChromeCommandBufferIPCTransport*>(command_buffer_transport);
|
| + chrome_ipc_transport->BindToService(this);
|
| + int route_id = chrome_ipc_transport->route_id();
|
| + *result =
|
| + factory_->CreateViewCommandBuffer(surface_id, init_params, route_id);
|
| + if (*result == CREATE_COMMAND_BUFFER_SUCCEEDED)
|
| + AddRoute(route_id, chrome_ipc_transport->AsWeakPtr());
|
| + else if (*result == CREATE_COMMAND_BUFFER_FAILED_AND_CHANNEL_LOST) {
|
| + // The GPU channel needs to be considered lost. The caller will
|
| + // then set up a new connection, and the GPU channel and any
|
| + // view command buffers will all be associated with the same GPU
|
| + // process.
|
| + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
|
| + factory_->GetIOThreadTaskRunner();
|
| + io_task_runner->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &ChromeGpuChannelHostIPCTransport::MessageFilter::OnChannelError,
|
| + channel_filter_.get()));
|
| + }
|
| + return *result != CREATE_COMMAND_BUFFER_FAILED_AND_CHANNEL_LOST;
|
| +}
|
| +
|
| +bool ChromeGpuChannelHostIPCTransport::CreateOffscreenCommandBuffer(
|
| + const gfx::Size& size,
|
| + const GpuCreateCommandBufferConfig& init_params,
|
| + CommandBufferIPCTransport* command_buffer_transport,
|
| + bool* succeeded) {
|
| + ChromeCommandBufferIPCTransport* chrome_ipc_transport =
|
| + static_cast<ChromeCommandBufferIPCTransport*>(command_buffer_transport);
|
| + chrome_ipc_transport->BindToService(this);
|
| + int route_id = chrome_ipc_transport->route_id();
|
| + bool sent = Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(
|
| + size, init_params, route_id, succeeded));
|
| +
|
| + if (sent && *succeeded)
|
| + AddRoute(route_id, chrome_ipc_transport->AsWeakPtr());
|
| +
|
| + return sent;
|
| +}
|
| +
|
| +bool ChromeGpuChannelHostIPCTransport::DestroyCommandBuffer(
|
| + CommandBufferIPCTransport* command_buffer_transport) {
|
| + int route_id =
|
| + static_cast<ChromeCommandBufferIPCTransport*>(command_buffer_transport)
|
| + ->route_id();
|
| + bool success = Send(new GpuChannelMsg_DestroyCommandBuffer(route_id));
|
| + RemoveRoute(route_id);
|
| + return success;
|
| +}
|
| +
|
| +bool ChromeGpuChannelHostIPCTransport::IsLost() const {
|
| + DCHECK(channel_filter_.get());
|
| + return channel_filter_->IsLost();
|
| +}
|
| +
|
| +bool ChromeGpuChannelHostIPCTransport::Nop() {
|
| + return Send(new GpuChannelMsg_Nop());
|
| +}
|
| +
|
| +base::SharedMemoryHandle ChromeGpuChannelHostIPCTransport::ShareToGpuProcess(
|
| + const base::SharedMemoryHandle& source_handle) {
|
| + if (IsLost())
|
| + return base::SharedMemory::NULLHandle();
|
| +
|
| +#if defined(OS_WIN) || defined(OS_MACOSX)
|
| + // Windows and Mac need to explicitly duplicate the handle out to another
|
| + // process.
|
| + base::SharedMemoryHandle target_handle;
|
| + base::ProcessId peer_pid;
|
| + {
|
| + // TODO(fsamuel): should we do locking inside the transport object?
|
| + if (!channel_)
|
| + return base::SharedMemory::NULLHandle();
|
| + peer_pid = channel_->GetPeerPID();
|
| + }
|
| + bool success = BrokerDuplicateSharedMemoryHandle(source_handle, peer_pid,
|
| + &target_handle);
|
| + if (!success)
|
| + return base::SharedMemory::NULLHandle();
|
| +
|
| + return target_handle;
|
| +#else
|
| + return base::SharedMemory::DuplicateHandle(source_handle);
|
| +#endif // defined(OS_WIN) || defined(OS_MACOSX)
|
| +}
|
| +
|
| +ChromeGpuChannelHostIPCTransport::MessageFilter::ListenerInfo::ListenerInfo() {}
|
| +
|
| +ChromeGpuChannelHostIPCTransport::MessageFilter::ListenerInfo::~ListenerInfo() {
|
| +}
|
| +
|
| +ChromeGpuChannelHostIPCTransport::MessageFilter::MessageFilter()
|
| + : lost_(false) {}
|
| +
|
| +ChromeGpuChannelHostIPCTransport::MessageFilter::~MessageFilter() {}
|
| +
|
| +void ChromeGpuChannelHostIPCTransport::MessageFilter::AddRoute(
|
| + int32_t route_id,
|
| + base::WeakPtr<IPC::Listener> listener,
|
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
|
| + DCHECK(listeners_.find(route_id) == listeners_.end());
|
| + DCHECK(task_runner);
|
| + ListenerInfo info;
|
| + info.listener = listener;
|
| + info.task_runner = task_runner;
|
| + listeners_[route_id] = info;
|
| +}
|
| +
|
| +void ChromeGpuChannelHostIPCTransport::MessageFilter::RemoveRoute(
|
| + int32_t route_id) {
|
| + listeners_.erase(route_id);
|
| +}
|
| +
|
| +bool ChromeGpuChannelHostIPCTransport::MessageFilter::OnMessageReceived(
|
| + const IPC::Message& message) {
|
| + // Never handle sync message replies or we will deadlock here.
|
| + if (message.is_reply())
|
| + return false;
|
| +
|
| + auto it = listeners_.find(message.routing_id());
|
| + if (it == listeners_.end())
|
| + return false;
|
| +
|
| + const ListenerInfo& info = it->second;
|
| + info.task_runner->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(base::IgnoreResult(&IPC::Listener::OnMessageReceived),
|
| + info.listener, message));
|
| + return true;
|
| +}
|
| +
|
| +void ChromeGpuChannelHostIPCTransport::MessageFilter::OnChannelError() {
|
| + // Set the lost state before signalling the proxies. That way, if they
|
| + // themselves post a task to recreate the context, they will not try to re-use
|
| + // this channel host.
|
| + {
|
| + base::AutoLock lock(lock_);
|
| + lost_ = true;
|
| + }
|
| +
|
| + // Inform all the proxies that an error has occurred. This will be reported
|
| + // via OpenGL as a lost context.
|
| + for (const auto& kv : listeners_) {
|
| + const ListenerInfo& info = kv.second;
|
| + info.task_runner->PostTask(
|
| + FROM_HERE, base::Bind(&IPC::Listener::OnChannelError, info.listener));
|
| + }
|
| +
|
| + listeners_.clear();
|
| +}
|
| +
|
| +bool ChromeGpuChannelHostIPCTransport::MessageFilter::IsLost() const {
|
| + base::AutoLock lock(lock_);
|
| + return lost_;
|
| +}
|
| +
|
| +} // namespace content
|
|
|