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

Unified Diff: content/renderer/gpu/gpu_channel_host.cc

Issue 7634019: Allow cmdbuffer creation from compositor thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: MessageLoop::current() -> MessageLoopProxy::current() Created 9 years, 4 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/renderer/gpu/gpu_channel_host.cc
diff --git a/content/renderer/gpu/gpu_channel_host.cc b/content/renderer/gpu/gpu_channel_host.cc
index 9229183ab11c97249421be6fe25e88767fca7f12..9577c4f4ecf36bc81665edc1658309e915cec1bb 100644
--- a/content/renderer/gpu/gpu_channel_host.cc
+++ b/content/renderer/gpu/gpu_channel_host.cc
@@ -4,13 +4,113 @@
#include "content/renderer/gpu/gpu_channel_host.h"
+#include "base/message_loop_proxy.h"
#include "content/common/child_process.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/renderer/gpu/command_buffer_proxy.h"
#include "content/renderer/gpu/gpu_surface_proxy.h"
#include "content/renderer/gpu/transport_texture_service.h"
+#include "content/renderer/render_process.h"
#include "content/renderer/render_thread.h"
#include "googleurl/src/gurl.h"
+#include "ipc/ipc_sync_message_filter.h"
+
+using base::AutoLock;
+using base::MessageLoopProxy;
+
+GpuChannelHost::MessageFilter::Listener::Listener()
+ : orphaned_(false) {
+
+}
+
+GpuChannelHost::MessageFilter::Listener::~Listener() {
+
+}
+
+GpuChannelHost::MessageFilter::ListenerInfo::ListenerInfo() : loop_(NULL) {
+
+}
+
+GpuChannelHost::MessageFilter::ListenerInfo::ListenerInfo(
+ MessageLoopProxy* loop, scoped_refptr<Listener> listener)
+ : loop_(loop),
+ listener_(listener) {
+}
+
+GpuChannelHost::MessageFilter::ListenerInfo::~ListenerInfo() {
+
+}
+
+GpuChannelHost::MessageFilter::MessageFilter(GpuChannelHost* parent)
+ : parent_(parent) {
+ DetachFromThread();
+}
+
+void GpuChannelHost::MessageFilter::AddRoute(
+ int route_id,
+ scoped_refptr<Listener> listener,
+ MessageLoopProxy* loop) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(listeners_.find(route_id) == listeners_.end());
+ listeners_[route_id] = ListenerInfo(loop, listener);
+}
+
+void GpuChannelHost::MessageFilter::RemoveRoute(int route_id) {
+ DCHECK(CalledOnValidThread());
+ ListenerMap::iterator it = listeners_.find(route_id);
+ if (it != listeners_.end())
+ listeners_.erase(it);
+}
+
+bool GpuChannelHost::MessageFilter::OnMessageReceived(
+ const IPC::Message& message) {
+ DCHECK(CalledOnValidThread());
+
+ // Never handle sync message replies or we will deadlock here.
+ if (message.is_reply())
+ return false;
+
+ DCHECK(message.routing_id() != MSG_ROUTING_CONTROL);
+
+ ListenerMap::iterator it = listeners_.find(message.routing_id());
+
+ if (it != listeners_.end()) {
+ const ListenerInfo& info = it->second;
+ info.loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ info.listener_.get(),
+ &GpuChannelHost::MessageFilter::Listener::OnMessageReceived,
+ message));
+ }
+
+ return true;
+}
+
+void GpuChannelHost::MessageFilter::OnChannelError() {
+ DCHECK(CalledOnValidThread());
+
+ // Inform all the proxies that an error has occurred. This will be reported
+ // via OpenGL as a lost context.
+ for (ListenerMap::iterator it = listeners_.begin();
+ it != listeners_.end();
+ it++) {
+ const ListenerInfo& info = it->second;
+ info.loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ info.listener_.get(),
+ &GpuChannelHost::MessageFilter::Listener::OnChannelError));
+ }
+
+ listeners_.clear();
+
+ ChildThread* main_thread = RenderProcess::current()->main_thread();
+ MessageLoop* main_loop = main_thread->message_loop();
+ main_loop->PostTask(FROM_HERE,
+ NewRunnableMethod(parent_,
+ &GpuChannelHost::OnChannelError));
+}
GpuChannelHost::GpuChannelHost()
: state_(kUnconnected),
@@ -23,12 +123,27 @@ GpuChannelHost::~GpuChannelHost() {
void GpuChannelHost::Connect(
const IPC::ChannelHandle& channel_handle,
base::ProcessHandle renderer_process_for_gpu) {
- // Open a channel to the GPU process.
+ DCHECK(RenderThread::current());
+ // 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.
channel_.reset(new IPC::SyncChannel(
- channel_handle, IPC::Channel::MODE_CLIENT, this,
+ channel_handle, IPC::Channel::MODE_CLIENT, NULL,
ChildProcess::current()->io_message_loop_proxy(), true,
ChildProcess::current()->GetShutDownEvent()));
+ sync_filter_.reset(new IPC::SyncMessageFilter(
+ ChildProcess::current()->GetShutDownEvent()));
+
+ channel_->AddFilter(sync_filter_.get());
+
+ channel_->AddFilter(transport_texture_service_.get());
+
+ channel_filter_ = new MessageFilter(this);
+
+ // Install the filter last, because we intercept all leftover
+ // messages.
+ channel_->AddFilter(channel_filter_.get());
+
// It is safe to send IPC messages before the channel completes the connection
// and receives the hello message from the GPU process. The messages get
// cached.
@@ -51,43 +166,25 @@ void GpuChannelHost::SetStateLost() {
state_ = kLost;
}
-bool GpuChannelHost::OnMessageReceived(const IPC::Message& message) {
- DCHECK(message.routing_id() != MSG_ROUTING_CONTROL);
-
- return router_.RouteMessage(message);
-}
-
-void GpuChannelHost::OnChannelConnected(int32 peer_pid) {
- channel_->AddFilter(transport_texture_service_.get());
-}
-
void GpuChannelHost::OnChannelError() {
state_ = kLost;
// Channel is invalid and will be reinitialized if this host is requested
// again.
channel_.reset();
-
- // Inform all the proxies that an error has occured. This will be reported via
- // OpenGL as a lost context.
- for (ProxyMap::iterator iter = proxies_.begin();
- iter != proxies_.end(); iter++) {
- router_.RemoveRoute(iter->first);
- iter->second->OnChannelError();
- }
-
- // The proxies are reference counted so this will not result in their
- // destruction if the client still holds a reference. The proxy will report
- // a lost context, indicating to the client that it needs to be recreated.
- proxies_.clear();
}
bool GpuChannelHost::Send(IPC::Message* message) {
// The GPU process never sends synchronous IPCs so clear the unblock flag to
// preserve order.
message->set_unblock(false);
- if (channel_.get())
+
+ // Unfortunately a sync filter cannot be used on the main (listener) thread.
+ // TODO: Is that true even when we don't install a listener?
+ if (channel_.get() && RenderThread::current())
return channel_->Send(message);
+ else
+ return sync_filter_->Send(message);
// Callee takes ownership of message, regardless of whether Send is
// successful. See IPC::Message::Sender.
@@ -95,13 +192,14 @@ bool GpuChannelHost::Send(IPC::Message* message) {
return false;
}
-CommandBufferProxy* GpuChannelHost::CreateViewCommandBuffer(
+scoped_refptr<CommandBufferProxy> GpuChannelHost::CreateViewCommandBuffer(
int render_view_id,
CommandBufferProxy* share_group,
const std::string& allowed_extensions,
const std::vector<int32>& attribs,
const GURL& active_url) {
#if defined(ENABLE_GPU)
+ AutoLock lock(context_lock_);
// An error occurred. Need to get the host again to reinitialize it.
if (!channel_.get())
return NULL;
@@ -124,8 +222,9 @@ CommandBufferProxy* GpuChannelHost::CreateViewCommandBuffer(
if (route_id == MSG_ROUTING_NONE)
return NULL;
- CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id);
- router_.AddRoute(route_id, command_buffer);
+ scoped_refptr<CommandBufferProxy> command_buffer =
+ new CommandBufferProxy(this, route_id);
+ AddRoute(route_id, command_buffer);
proxies_[route_id] = command_buffer;
return command_buffer;
#else
@@ -137,19 +236,21 @@ GpuVideoDecodeAcceleratorHost* GpuChannelHost::CreateVideoDecoder(
int command_buffer_route_id,
const std::vector<int32>& configs,
media::VideoDecodeAccelerator::Client* client) {
+ AutoLock lock(context_lock_);
ProxyMap::iterator it = proxies_.find(command_buffer_route_id);
DCHECK(it != proxies_.end());
CommandBufferProxy* proxy = it->second;
return proxy->CreateVideoDecoder(configs, client);
}
-CommandBufferProxy* GpuChannelHost::CreateOffscreenCommandBuffer(
+scoped_refptr<CommandBufferProxy> GpuChannelHost::CreateOffscreenCommandBuffer(
const gfx::Size& size,
CommandBufferProxy* share_group,
const std::string& allowed_extensions,
const std::vector<int32>& attribs,
const GURL& active_url) {
#if defined(ENABLE_GPU)
+ AutoLock lock(context_lock_);
// An error occurred. Need to get the host again to reinitialize it.
if (!channel_.get())
return NULL;
@@ -170,8 +271,9 @@ CommandBufferProxy* GpuChannelHost::CreateOffscreenCommandBuffer(
if (route_id == MSG_ROUTING_NONE)
return NULL;
- CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id);
- router_.AddRoute(route_id, command_buffer);
+ scoped_refptr<CommandBufferProxy> command_buffer =
+ new CommandBufferProxy(this, route_id);
+ AddRoute(route_id, command_buffer);
proxies_[route_id] = command_buffer;
return command_buffer;
#else
@@ -181,38 +283,60 @@ CommandBufferProxy* GpuChannelHost::CreateOffscreenCommandBuffer(
void GpuChannelHost::DestroyCommandBuffer(CommandBufferProxy* command_buffer) {
#if defined(ENABLE_GPU)
+ AutoLock lock(context_lock_);
Send(new GpuChannelMsg_DestroyCommandBuffer(command_buffer->route_id()));
// Check the proxy has not already been removed after a channel error.
int route_id = command_buffer->route_id();
- if (proxies_.find(command_buffer->route_id()) != proxies_.end()) {
+ if (proxies_.find(command_buffer->route_id()) != proxies_.end())
proxies_.erase(route_id);
- router_.RemoveRoute(route_id);
- }
-
- delete command_buffer;
+ RemoveRoute(route_id);
+ command_buffer->Orphan();
#endif
}
-GpuSurfaceProxy* GpuChannelHost::CreateOffscreenSurface(const gfx::Size& size) {
+scoped_refptr<GpuSurfaceProxy> GpuChannelHost::CreateOffscreenSurface(
+ const gfx::Size& size) {
#if defined(ENABLE_GPU)
+ AutoLock lock(context_lock_);
int route_id;
if (!Send(new GpuChannelMsg_CreateOffscreenSurface(size, &route_id)))
return NULL;
- scoped_ptr<GpuSurfaceProxy> surface(new GpuSurfaceProxy(this, route_id));
- router_.AddRoute(route_id, surface.get());
+ scoped_refptr<GpuSurfaceProxy> surface(new GpuSurfaceProxy(this, route_id));
+ AddRoute(route_id, surface.get());
- return surface.release();
+ return surface;
#endif
}
void GpuChannelHost::DestroySurface(GpuSurfaceProxy* surface) {
#if defined(ENABLE_GPU)
+ AutoLock lock(context_lock_);
Send(new GpuChannelMsg_DestroySurface(surface->route_id()));
- if (router_.ResolveRoute(surface->route_id()))
- router_.RemoveRoute(surface->route_id());
- delete surface;
+ RemoveRoute(surface->route_id());
+ surface->Orphan();
#endif
}
+
+void GpuChannelHost::AddRoute(
+ int route_id, scoped_refptr<MessageFilter::Listener> listener) {
+ DCHECK(MessageLoopProxy::current());
+
+ MessageLoopProxy* io_loop = RenderProcess::current()->io_message_loop_proxy();
+ io_loop->PostTask(FROM_HERE,
+ NewRunnableMethod(
+ channel_filter_.get(),
+ &GpuChannelHost::MessageFilter::AddRoute,
+ route_id, listener, MessageLoopProxy::current()));
+}
+
+void GpuChannelHost::RemoveRoute(int route_id) {
+ MessageLoopProxy* io_loop = RenderProcess::current()->io_message_loop_proxy();
+ io_loop->PostTask(FROM_HERE,
+ NewRunnableMethod(
+ channel_filter_.get(),
+ &GpuChannelHost::MessageFilter::RemoveRoute,
+ route_id));
+}

Powered by Google App Engine
This is Rietveld 408576698