| 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));
|
| +}
|
|
|