Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1507)

Unified Diff: content/common/gpu/client/ipc/chrome/chrome_gpu_channel_host_ipc_transport.cc

Issue 1656433002: Sample code: IPC Transport object for GPU Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: GpuMemoryBufferService + Transport object. TODO: Eliminate ChildThreadImpl dependency Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698