diff options
39 files changed, 1219 insertions, 259 deletions
diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc index f2cdc80..ef90edc 100644 --- a/chrome/browser/gpu_process_host.cc +++ b/chrome/browser/gpu_process_host.cc @@ -11,9 +11,11 @@ #include "chrome/browser/child_process_host.h" #include "chrome/browser/child_process_launcher.h" #include "chrome/browser/io_thread.h" +#include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/common/child_process_info.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/gpu_messages.h" +#include "chrome/common/render_messages.h" #include "ipc/ipc_switches.h" GpuProcessHost::GpuProcessHost() : last_routing_id_(1) { @@ -93,8 +95,7 @@ bool GpuProcessHost::Send(IPC::Message* msg) { void GpuProcessHost::OnMessageReceived(const IPC::Message& message) { if (message.routing_id() == MSG_ROUTING_CONTROL) { - // We don't currently have any control messages. - // OnControlMessageReceived(message); + OnControlMessageReceived(message); } else { router_.OnMessageReceived(message); } @@ -121,3 +122,40 @@ void GpuProcessHost::AddRoute(int32 routing_id, void GpuProcessHost::RemoveRoute(int32 routing_id) { router_.RemoveRoute(routing_id); } + +void GpuProcessHost::EstablishGpuChannel( + int renderer_id, + int routing_id) { + if (Send(new GpuMsg_EstablishChannel(renderer_id))) + sent_requests_.push(ChannelRequest(renderer_id, routing_id)); + else + ReplyToRenderer(renderer_id, routing_id, IPC::ChannelHandle()); +} + +void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message) + IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished) + IPC_MESSAGE_UNHANDLED_ERROR() + IPC_END_MESSAGE_MAP() +} + +void GpuProcessHost::OnChannelEstablished( + const IPC::ChannelHandle& channel_handle) { + const ChannelRequest& request = sent_requests_.front(); + + ReplyToRenderer(request.renderer_id, request.routing_id, channel_handle); + sent_requests_.pop(); +} + +void GpuProcessHost::ReplyToRenderer( + int renderer_id, + int routing_id, + const IPC::ChannelHandle& channel) { + // Check whether the renderer process is still around. + RenderProcessHost* process_host = RenderProcessHost::FromID(renderer_id); + if (!process_host) + return; + + CHECK(process_host->Send(new ViewMsg_GpuChannelEstablished(routing_id, + channel))); +} diff --git a/chrome/browser/gpu_process_host.h b/chrome/browser/gpu_process_host.h index d107b88..f64cdd8 100644 --- a/chrome/browser/gpu_process_host.h +++ b/chrome/browser/gpu_process_host.h @@ -13,9 +13,11 @@ #include "chrome/browser/child_process_launcher.h" #include "chrome/common/gpu_native_window_handle.h" #include "chrome/common/message_router.h" +#include "ipc/ipc_channel_handle.h" #include "ipc/ipc_channel_proxy.h" class ChildProcessLauncher; +class CommandBufferProxy; class GpuProcessHost : public IPC::Channel::Sender, public IPC::Channel::Listener, @@ -45,16 +47,51 @@ class GpuProcessHost : public IPC::Channel::Sender, void AddRoute(int32 routing_id, IPC::Channel::Listener* listener); void RemoveRoute(int32 routing_id); + // Tells the GPU process to create a new channel for communication with a + // renderer. Will asynchronously send message to object with given routing id + // on completion. + void EstablishGpuChannel(int renderer_id, int routing_id); + private: friend struct DefaultSingletonTraits<GpuProcessHost>; + // Used to queue pending channel requests. + struct ChannelRequest { + ChannelRequest(int renderer_id, + int routing_id) : + renderer_id(renderer_id), + routing_id(routing_id) {} + // Used to identify the renderer. The ID is used instead of a pointer to + // the RenderProcessHost in case it is destroyed while the request is + // pending. + // TODO(apatrick): investigate whether these IDs are used for future + // render processes. + int renderer_id; + + // Routing ID of object to receive reply message. + int routing_id; + }; + GpuProcessHost(); virtual ~GpuProcessHost(); + void OnControlMessageReceived(const IPC::Message& message); + + // Message handlers. + void OnChannelEstablished(const IPC::ChannelHandle& channel_handle); + + void ReplyToRenderer(int renderer_id, + int routing_id, + const IPC::ChannelHandle& channel); + + // These are the channel requests that we have already sent to + // the GPU process, but haven't heard back about yet. + std::queue<ChannelRequest> sent_requests_; + scoped_ptr<ChildProcessLauncher> child_process_; // A proxy for our IPC::Channel that lives on the IO thread (see - // browser_process.h). This will be NULL if the class failed to initialize. + // browser_process.h). This will be NULL if the class failed to connect. scoped_ptr<IPC::ChannelProxy> channel_; int last_routing_id_; diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h index a60adc2..b32a0e2 100644 --- a/chrome/browser/renderer_host/backing_store.h +++ b/chrome/browser/renderer_host/backing_store.h @@ -8,6 +8,7 @@ #include <vector> #include "base/basictypes.h" +#include "base/gfx/rect.h" #include "base/gfx/size.h" #include "base/process.h" #include "chrome/common/transport_dib.h" diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index 44a36bd..2bee3e6 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -8,6 +8,7 @@ #include "base/histogram.h" #include "base/keyboard_codes.h" #include "base/message_loop.h" +#include "chrome/browser/gpu_process_host.h" #include "chrome/browser/renderer_host/backing_store.h" #include "chrome/browser/renderer_host/backing_store_manager.h" #include "chrome/browser/renderer_host/render_process_host.h" @@ -15,6 +16,7 @@ #include "chrome/browser/renderer_host/render_widget_host_painting_observer.h" #include "chrome/browser/renderer_host/render_widget_host_view.h" #include "chrome/browser/renderer_host/video_layer.h" +#include "chrome/common/gpu_messages.h" #include "chrome/common/notification_service.h" #include "chrome/common/render_messages.h" #include "webkit/glue/webcursor.h" @@ -137,6 +139,8 @@ void RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_FocusedNodeChanged, OnMsgFocusedNodeChanged) IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnMsgSetCursor) IPC_MESSAGE_HANDLER(ViewHostMsg_ImeUpdateStatus, OnMsgImeUpdateStatus) + IPC_MESSAGE_HANDLER(ViewHostMsg_EstablishGpuChannel, + OnMsgEstablishGpuChannel) #if defined(OS_LINUX) IPC_MESSAGE_HANDLER(ViewHostMsg_CreatePluginContainer, OnMsgCreatePluginContainer) @@ -861,6 +865,10 @@ void RenderWidgetHost::OnMsgImeUpdateStatus(int control, } } +void RenderWidgetHost::OnMsgEstablishGpuChannel() { + GpuProcessHost::Get()->EstablishGpuChannel(process_->id(), routing_id_); +} + #if defined(OS_LINUX) void RenderWidgetHost::OnMsgCreatePluginContainer(gfx::PluginWindowHandle id) { diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index f1b402e..a3fdfdf 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -13,6 +13,7 @@ #include "base/scoped_ptr.h" #include "base/string16.h" #include "base/timer.h" +#include "ipc/ipc_channel_handle.h" #include "chrome/common/edit_command.h" #include "chrome/common/native_web_keyboard_event.h" #include "chrome/common/property_bag.h" @@ -443,6 +444,11 @@ class RenderWidgetHost : public IPC::Channel::Listener, // Using int instead of ViewHostMsg_ImeControl for control's type to avoid // having to bring in render_messages.h in a header file. void OnMsgImeUpdateStatus(int control, const gfx::Rect& caret_rect); + + // Renderer process is requesting that the browser process establish a GPU + // channel. + void OnMsgEstablishGpuChannel(); + #if defined(OS_LINUX) void OnMsgCreatePluginContainer(gfx::PluginWindowHandle id); void OnMsgDestroyPluginContainer(gfx::PluginWindowHandle id); diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index f6b8fd6..9b2dfeb 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -664,12 +664,17 @@ 'msvs_guid': 'F10F1ECD-D84D-4C33-8468-9DDFE19F4D8A', 'dependencies': [ '../base/base.gyp:base', + '../gpu/gpu.gyp:command_buffer_service', 'common', '../skia/skia.gyp:skia', ], 'sources': [ 'gpu/gpu_backing_store_win.cc', 'gpu/gpu_backing_store_win.h', + 'gpu/gpu_channel.cc', + 'gpu/gpu_channel.h', + 'gpu/gpu_command_buffer_stub.cc', + 'gpu/gpu_command_buffer_stub.h', 'gpu/gpu_config.h', 'gpu/gpu_main.cc', 'gpu/gpu_process.cc', diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index 7acf628..2f27359 100755 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -94,6 +94,8 @@ 'renderer/form_manager.h', 'renderer/geolocation_dispatcher.cc', 'renderer/geolocation_dispatcher.h', + 'renderer/gpu_channel_host.cc', + 'renderer/gpu_channel_host.h', 'renderer/localized_error.cc', 'renderer/localized_error.h', 'renderer/navigation_state.h', diff --git a/chrome/common/command_buffer_messages.h b/chrome/common/command_buffer_messages.h deleted file mode 100644 index 144ff2f..0000000 --- a/chrome/common/command_buffer_messages.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2009 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. - -#ifndef CHROME_COMMON_COMMAND_BUFFER_MESSAGES_H_ -#define CHROME_COMMON_COMMAND_BUFFER_MESSAGES_H_ - -#include "chrome/common/common_param_traits.h" -#include "gpu/command_buffer/common/command_buffer.h" - -namespace IPC { -template <> -struct ParamTraits<gpu::CommandBuffer::State> { - typedef gpu::CommandBuffer::State param_type; - static void Write(Message* m, const param_type& p) { - m->WriteInt(p.size); - m->WriteInt(p.get_offset); - m->WriteInt(p.put_offset); - m->WriteInt(p.token); - m->WriteInt(p.error); - } - static bool Read(const Message* m, void** iter, param_type* p) { - int32 temp; - if (m->ReadInt(iter, &p->size) && - m->ReadInt(iter, &p->get_offset) && - m->ReadInt(iter, &p->put_offset) && - m->ReadInt(iter, &p->token) && - m->ReadInt(iter, &temp)) { - p->error = static_cast<gpu::error::Error>(temp); - return true; - } else { - return false; - } - } - static void Log(const param_type& p, std::wstring* l) { - l->append(L"<CommandBuffer::State>"); - } -}; -} // namespace IPC - -#define MESSAGES_INTERNAL_FILE "chrome/common/command_buffer_messages_internal.h" -#include "ipc/ipc_message_macros.h" - -#endif // CHROME_COMMON_COMMAND_BUFFER_MESSAGES_H_ diff --git a/chrome/common/command_buffer_messages_internal.h b/chrome/common/command_buffer_messages_internal.h deleted file mode 100644 index 5a62b00..0000000 --- a/chrome/common/command_buffer_messages_internal.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2009 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 "base/shared_memory.h" -#include "ipc/ipc_message_macros.h" - -IPC_BEGIN_MESSAGES(CommandBuffer) - // Initialize a command buffer with the given number of command entries. - // Returns the shared memory handle for the command buffer mapped to the - // calling process. - IPC_SYNC_MESSAGE_ROUTED1_1(CommandBufferMsg_Initialize, - int32 /* size */, - base::SharedMemoryHandle /* ring_buffer */) - - // Get the current state of the command buffer. - IPC_SYNC_MESSAGE_ROUTED0_1(CommandBufferMsg_GetState, - gpu::CommandBuffer::State /* state */) - - // Get the current state of the command buffer asynchronously. State is - // returned via UpdateState message. - IPC_MESSAGE_ROUTED0(CommandBufferMsg_AsyncGetState) - - // Synchronize the put and get offsets of both processes. Caller passes its - // current put offset. Current state (including get offset) is returned. - IPC_SYNC_MESSAGE_ROUTED1_1(CommandBufferMsg_Flush, - int32 /* put_offset */, - gpu::CommandBuffer::State /* state */) - - // Asynchronously synchronize the put and get offsets of both processes. - // Caller passes its current put offset. Current state (including get offset) - // is returned via an UpdateState message. - IPC_MESSAGE_ROUTED1(CommandBufferMsg_AsyncFlush, - int32 /* put_offset */) - - // Return the current state of the command buffer following a request via - // an AsyncGetState or AsyncFlush message. - IPC_MESSAGE_ROUTED1(CommandBufferMsg_UpdateState, - gpu::CommandBuffer::State /* state */) - - // Create a shared memory transfer buffer. Returns an id that can be used to - // identify the transfer buffer from a comment. - IPC_SYNC_MESSAGE_ROUTED1_1(CommandBufferMsg_CreateTransferBuffer, - int32 /* size */, - int32 /* id */) - - // Destroy a previously created transfer buffer. - IPC_SYNC_MESSAGE_ROUTED1_0(CommandBufferMsg_DestroyTransferBuffer, - int32 /* id */) - - // Get the shared memory handle for a transfer buffer mapped to the callers - // process. - IPC_SYNC_MESSAGE_ROUTED1_2(CommandBufferMsg_GetTransferBuffer, - int32 /* id */, - base::SharedMemoryHandle /* transfer_buffer */, - uint32 /* size */) - - // Send from command buffer stub to proxy when window is invalid and must be - // repainted. - IPC_MESSAGE_ROUTED0(CommandBufferMsg_NotifyRepaint) - -#if defined(OS_MACOSX) - // On Mac OS X the GPU plugin must be offscreen, because there is no - // true cross-process window hierarchy. For this reason we must send - // resize events explicitly to the command buffer stub so it can - // reallocate its backing store and send the new one back to the - // browser. This message is currently used only on 10.6 and later. - IPC_MESSAGE_ROUTED2(CommandBufferMsg_SetWindowSize, - int32 /* width */, - int32 /* height */) -#endif - -IPC_END_MESSAGES(CommandBuffer) diff --git a/chrome/common/gpu_messages.h b/chrome/common/gpu_messages.h index fc2a826..1bf9bac 100644 --- a/chrome/common/gpu_messages.h +++ b/chrome/common/gpu_messages.h @@ -15,11 +15,36 @@ #include "chrome/common/common_param_traits.h" #include "chrome/common/gpu_native_window_handle.h" #include "chrome/common/transport_dib.h" +#include "gpu/command_buffer/common/command_buffer.h" namespace IPC { - -// Potential new structures for messages go here. - +template <> +struct ParamTraits<gpu::CommandBuffer::State> { + typedef gpu::CommandBuffer::State param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p.size); + m->WriteInt(p.get_offset); + m->WriteInt(p.put_offset); + m->WriteInt(p.token); + m->WriteInt(p.error); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int32 temp; + if (m->ReadInt(iter, &p->size) && + m->ReadInt(iter, &p->get_offset) && + m->ReadInt(iter, &p->put_offset) && + m->ReadInt(iter, &p->token) && + m->ReadInt(iter, &temp)) { + p->error = static_cast<gpu::error::Error>(temp); + return true; + } else { + return false; + } + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<CommandBuffer::State>"); + } +}; } // namespace IPC #define MESSAGES_INTERNAL_FILE \ diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h index 0581e4c..6780a5e 100644 --- a/chrome/common/gpu_messages_internal.h +++ b/chrome/common/gpu_messages_internal.h @@ -8,13 +8,23 @@ // This file needs to be included again, even though we're actually included // from it via utility_messages.h. +#include "base/shared_memory.h" +#include "ipc/ipc_channel_handle.h" #include "ipc/ipc_message_macros.h" //------------------------------------------------------------------------------ -// Backing Store Messages +// GPU Messages // These are messages from the browser to the GPU process. IPC_BEGIN_MESSAGES(Gpu) + // Tells the GPU process to create a new channel for communication with a + // given renderer. The channel name is returned in a + // GpuHostMsg_ChannelEstablished message. The renderer ID is passed so that + // the GPU process reuses an existing channel to that process if it exists. + // This ID is a unique opaque identifier generated by the browser process. + IPC_MESSAGE_CONTROL1(GpuMsg_EstablishChannel, + int /* renderer_id */) + IPC_MESSAGE_CONTROL2(GpuMsg_NewRenderWidgetHostView, GpuNativeWindowHandle, /* parent window */ int32 /* view_id */) @@ -61,7 +71,7 @@ IPC_BEGIN_MESSAGES(Gpu) IPC_END_MESSAGES(Gpu) //------------------------------------------------------------------------------ -// Backing Store Host Messagse +// GPU Host Messages // These are messages from the GPU process to the browser. IPC_BEGIN_MESSAGES(GpuHost) @@ -76,4 +86,97 @@ IPC_BEGIN_MESSAGES(GpuHost) // Sent in response to GpuMsg_PaintToVideoLayer, see that for more. IPC_MESSAGE_ROUTED0(GpuHostMsg_PaintToVideoLayer_ACK) + // Response to a GpuHostMsg_EstablishChannel message. + IPC_MESSAGE_CONTROL1(GpuHostMsg_ChannelEstablished, + IPC::ChannelHandle /* channel_handle */) IPC_END_MESSAGES(GpuHost) + +//------------------------------------------------------------------------------ +// GPU Channel Messages +// These are messages from a renderer process to the GPU process. +IPC_BEGIN_MESSAGES(GpuChannel) + + // Tells the GPU process to create a new command buffer with the given + // id. A corresponding GpuCommandBufferStub is created. + IPC_SYNC_MESSAGE_CONTROL0_1(GpuChannelMsg_CreateCommandBuffer, + int32 /* route_id */) + + // The CommandBufferProxy sends this to the GpuCommandBufferStub in its + // destructor, so that the stub deletes the actual WebPluginDelegateImpl + // object that it's hosting. + // TODO(apatrick): Implement this. + IPC_MESSAGE_CONTROL1(GpuChannelMsg_DestroyCommandBuffer, + int32 /* instance_id */) + +IPC_END_MESSAGES(GpuChannel) + +//------------------------------------------------------------------------------ +// GPU Command Buffer Messages +// These are messages from a renderer process to the GPU process relating to a +// single OpenGL context. +IPC_BEGIN_MESSAGES(GpuCommandBuffer) + // Initialize a command buffer with the given number of command entries. + // Returns the shared memory handle for the command buffer mapped to the + // calling process. + IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_Initialize, + int32 /* size */, + base::SharedMemoryHandle /* ring_buffer */) + + // Get the current state of the command buffer. + IPC_SYNC_MESSAGE_ROUTED0_1(GpuCommandBufferMsg_GetState, + gpu::CommandBuffer::State /* state */) + + // Get the current state of the command buffer asynchronously. State is + // returned via UpdateState message. + IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_AsyncGetState) + + // Synchronize the put and get offsets of both processes. Caller passes its + // current put offset. Current state (including get offset) is returned. + IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_Flush, + int32 /* put_offset */, + gpu::CommandBuffer::State /* state */) + + // Asynchronously synchronize the put and get offsets of both processes. + // Caller passes its current put offset. Current state (including get offset) + // is returned via an UpdateState message. + IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_AsyncFlush, + int32 /* put_offset */) + + // Return the current state of the command buffer following a request via + // an AsyncGetState or AsyncFlush message. + IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_UpdateState, + gpu::CommandBuffer::State /* state */) + + // Create a shared memory transfer buffer. Returns an id that can be used to + // identify the transfer buffer from a comment. + IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_CreateTransferBuffer, + int32 /* size */, + int32 /* id */) + + // Destroy a previously created transfer buffer. + IPC_SYNC_MESSAGE_ROUTED1_0(GpuCommandBufferMsg_DestroyTransferBuffer, + int32 /* id */) + + // Get the shared memory handle for a transfer buffer mapped to the callers + // process. + IPC_SYNC_MESSAGE_ROUTED1_2(GpuCommandBufferMsg_GetTransferBuffer, + int32 /* id */, + base::SharedMemoryHandle /* transfer_buffer */, + uint32 /* size */) + + // Send from command buffer stub to proxy when window is invalid and must be + // repainted. + IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_NotifyRepaint) + +#if defined(OS_MACOSX) + // On Mac OS X the GPU plugin must be offscreen, because there is no + // true cross-process window hierarchy. For this reason we must send + // resize events explicitly to the command buffer stub so it can + // reallocate its backing store and send the new one back to the + // browser. This message is currently used only on 10.6 and later. + IPC_MESSAGE_ROUTED2(GpuCommandBufferMsg_SetWindowSize, + int32 /* width */, + int32 /* height */) +#endif + +IPC_END_MESSAGES(GpuCommandBuffer) diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h index f83bfca..1f8dd54 100644 --- a/chrome/common/plugin_messages_internal.h +++ b/chrome/common/plugin_messages_internal.h @@ -294,6 +294,8 @@ IPC_BEGIN_MESSAGES(Plugin) IPC_SYNC_MESSAGE_ROUTED0_1(PluginMsg_CreateCommandBuffer, int /* route_id */) + IPC_MESSAGE_ROUTED0(PluginMsg_DestroyCommandBuffer) + IPC_MESSAGE_CONTROL1(PluginMsg_SignalModalDialogEvent, gfx::NativeViewId /* containing_window */) diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index e4a9b72..dc852f7 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -607,6 +607,11 @@ IPC_BEGIN_MESSAGES(View) // into a full window). IPC_MESSAGE_ROUTED0(ViewMsg_DisassociateFromPopupCount) + // The browser sends this to a renderer process in response to a + // ViewHostMsg_EstablishGpuChannel message. + IPC_MESSAGE_ROUTED1(ViewMsg_GpuChannelEstablished, + IPC::ChannelHandle /* handle to channel */) + // Notifies the renderer of the appcache that has been selected for a // a particular host. This is sent in reply to AppCacheMsg_SelectCache. IPC_MESSAGE_CONTROL3(AppCacheMsg_CacheSelected, @@ -1330,6 +1335,12 @@ IPC_BEGIN_MESSAGES(ViewHost) IPC::ChannelHandle /* handle to channel */, WebPluginInfo /* info */) + // A renderer sends this to the browser process when it wants to + // create connect to the GPU. The browser will create the GPU process if + // necessary, and will return a handle to the channel via + // a GpuChannelEstablished message. + IPC_MESSAGE_ROUTED0(ViewHostMsg_EstablishGpuChannel) + // A renderer sends this to the browser process when it wants to start // a new instance of the Native Client process. The browser will launch // the process and return a handle to an IMC channel. diff --git a/chrome/gpu/DEPS b/chrome/gpu/DEPS index beacfd9..f071f77 100644 --- a/chrome/gpu/DEPS +++ b/chrome/gpu/DEPS @@ -1,4 +1,5 @@ include_rules = [
- "+chrome/app",
+ "+chrome/app",
+ "+gpu/command_buffer",
]
diff --git a/chrome/gpu/gpu_channel.cc b/chrome/gpu/gpu_channel.cc new file mode 100644 index 0000000..25bb951 --- /dev/null +++ b/chrome/gpu/gpu_channel.cc @@ -0,0 +1,185 @@ +// Copyright (c) 2010 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 "chrome/gpu/gpu_channel.h" + +#include "base/command_line.h" +#include "base/lock.h" +#include "base/process_util.h" +#include "base/string_util.h" +#include "base/waitable_event.h" +#include "build/build_config.h" +#include "chrome/common/child_process.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/gpu_messages.h" +#include "chrome/gpu/gpu_thread.h" + +#if defined(OS_POSIX) +#include "ipc/ipc_channel_posix.h" +#endif + +namespace { +class GpuReleaseTask : public Task { + public: + void Run() { + ChildProcess::current()->ReleaseProcess(); + } +}; + +typedef base::hash_map<std::string, scoped_refptr<GpuChannel> > + GpuChannelMap; + +// How long we wait before releasing the GPU process. +const int kGpuReleaseTimeMS = 10000; + +GpuChannelMap g_gpu_channels; +} // namespace anonymous + +GpuChannel* GpuChannel::EstablishGpuChannel(int renderer_id) { + // Map renderer ID to a (single) channel to that process. + std::string channel_name = StringPrintf( + "%d.r%d", base::GetCurrentProcId(), renderer_id); + + scoped_refptr<GpuChannel> channel; + + GpuChannelMap::const_iterator iter = g_gpu_channels.find(channel_name); + if (iter == g_gpu_channels.end()) { + channel = new GpuChannel; + } else { + channel = iter->second; + } + + DCHECK(channel != NULL); + + if (!channel->channel_.get()) { + if (channel->Init(channel_name)) { + g_gpu_channels[channel_name] = channel; + } else { + channel = NULL; + } + } + + return channel.get(); +} + +GpuChannel::GpuChannel() + : renderer_id_(-1) +#if defined(OS_POSIX) + , renderer_fd_(-1) +#endif +{ + ChildProcess::current()->AddRefProcess(); + const CommandLine* command_line = CommandLine::ForCurrentProcess(); + log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages); +} + +GpuChannel::~GpuChannel() { +#if defined(OS_POSIX) + // If we still have the renderer FD, close it. + if (renderer_fd_ != -1) { + close(renderer_fd_); + } +#endif + ChildProcess::current()->io_message_loop()->PostDelayedTask( + FROM_HERE, + new GpuReleaseTask(), + kGpuReleaseTimeMS); +} + +void GpuChannel::OnChannelConnected(int32 peer_pid) { + if (!renderer_process_.Open(peer_pid)) { + NOTREACHED(); + } +} + +void GpuChannel::OnMessageReceived(const IPC::Message& message) { + if (log_messages_) { + LOG(INFO) << "received message @" << &message << " on channel @" << this + << " with type " << message.type(); + } + + if (message.routing_id() == MSG_ROUTING_CONTROL) { + OnControlMessageReceived(message); + } else { + // The sender should know not to route messages to an object after it + // has been destroyed. + CHECK(router_.RouteMessage(message)); + } +} + +void GpuChannel::OnChannelError() { + // Destroy channel. This will cause the channel to be recreated if another + // attempt is made to establish a connection from the corresponding renderer. + channel_.reset(); + + // Close renderer process handle. + renderer_process_.Close(); + +#if defined(ENABLE_GPU) + // Destroy all the stubs on this channel. + for (size_t i = 0; i < stubs_.size(); ++i) { + router_.RemoveRoute(stubs_[i]->route_id()); + } + stubs_.clear(); +#endif +} + +bool GpuChannel::Send(IPC::Message* message) { + if (log_messages_) { + LOG(INFO) << "sending message @" << message << " on channel @" << this + << " with type " << message->type(); + } + + if (!channel_.get()) { + delete message; + return false; + } + + return channel_->Send(message); +} + +void GpuChannel::OnControlMessageReceived(const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg) + IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateCommandBuffer, + OnCreateCommandBuffer) + IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer, + OnDestroyCommandBuffer) + IPC_MESSAGE_UNHANDLED_ERROR() + IPC_END_MESSAGE_MAP() +} + +int GpuChannel::GenerateRouteID() { + static int last_id = 0; + return ++last_id; +} + +void GpuChannel::OnCreateCommandBuffer(int* route_id) { +#if defined(ENABLE_GPU) + *route_id = GenerateRouteID(); + scoped_refptr<GpuCommandBufferStub> stub = new GpuCommandBufferStub( + this, *route_id); + router_.AddRoute(*route_id, stub); + stubs_[*route_id] = stub; +#else + *route_id = 0; +#endif +} + +void GpuChannel::OnDestroyCommandBuffer(int route_id) { +#if defined(ENABLE_GPU) + StubMap::iterator it = stubs_.find(route_id); + DCHECK(it != stubs_.end()); + stubs_.erase(it); + router_.RemoveRoute(route_id); +#endif +} + +bool GpuChannel::Init(const std::string& channel_name) { + channel_name_ = channel_name; + channel_.reset(new IPC::SyncChannel( + channel_name, IPC::Channel::MODE_SERVER, this, NULL, + ChildProcess::current()->io_message_loop(), false, + ChildProcess::current()->GetShutDownEvent())); + return true; +} diff --git a/chrome/gpu/gpu_channel.h b/chrome/gpu/gpu_channel.h new file mode 100644 index 0000000..17ea363 --- /dev/null +++ b/chrome/gpu/gpu_channel.h @@ -0,0 +1,104 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_GPU_GPU_CHANNEL_H_ +#define CHROME_GPU_GPU_CHANNEL_H_ + +#include <string> + +#include "base/hash_tables.h" +#include "base/ref_counted.h" +#include "base/scoped_open_process.h" +#include "build/build_config.h" +#include "chrome/common/message_router.h" +#include "chrome/gpu/gpu_command_buffer_stub.h" +#include "ipc/ipc_channel.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_sync_channel.h" + +// Encapsulates an IPC channel between the GPU process and one renderer +// process. On the renderer side there's a corresponding GpuChannelHost. +class GpuChannel : public IPC::Channel::Listener, + public IPC::Message::Sender, + public base::RefCountedThreadSafe<GpuChannel> { + public: + // Get a new GpuChannel object for the current process to talk to the + // given renderer process. The renderer ID is an opaque unique ID generated + // by the browser. + // + // POSIX only: If |channel_fd| > 0, use that file descriptor for the + // channel socket. + static GpuChannel* EstablishGpuChannel(int renderer_id); + + virtual ~GpuChannel(); + + std::string channel_name() const { return channel_name_; } + + base::ProcessHandle renderer_handle() const { + return renderer_process_.handle(); + } + +#if defined(OS_POSIX) + // When first created, the GpuChannel gets assigned the file descriptor + // for the renderer. + // After the first time we pass it through the IPC, we don't need it anymore, + // and we close it. At that time, we reset renderer_fd_ to -1. + int DisownRendererFd() { + int value = renderer_fd_; + renderer_fd_ = -1; + return value; + } +#endif + + // IPC::Channel::Listener implementation: + virtual void OnMessageReceived(const IPC::Message& msg); + virtual void OnChannelConnected(int32 peer_pid); + virtual void OnChannelError(); + + // IPC::Message::Sender implementation: + virtual bool Send(IPC::Message* msg); + + private: + // Called on the plugin thread + GpuChannel(); + + bool Init(const std::string& channel_name); + + void OnControlMessageReceived(const IPC::Message& msg); + + int GenerateRouteID(); + + // Message handlers. + void OnCreateCommandBuffer(int* instance_id); + void OnDestroyCommandBuffer(int instance_id); + + scoped_ptr<IPC::SyncChannel> channel_; + std::string channel_name_; + + // Handle to the renderer process who is on the other side of the channel. + base::ScopedOpenProcess renderer_process_; + + // The id of the renderer who is on the other side of the channel. + int renderer_id_; + +#if defined(OS_POSIX) + // FD for the renderer end of the pipe. It is stored until we send it over + // IPC after which it is cleared. It will be closed by the IPC mechanism. + int renderer_fd_; +#endif + + // Used to implement message routing functionality to CommandBuffer objects + MessageRouter router_; + +#if defined(ENABLE_GPU) + typedef base::hash_map<int, scoped_refptr<GpuCommandBufferStub> > StubMap; + StubMap stubs_; +#endif + + bool log_messages_; // True if we should log sent and received messages. + + DISALLOW_COPY_AND_ASSIGN(GpuChannel); +}; + +#endif // CHROME_GPU_GPU_CHANNEL_H_ diff --git a/chrome/gpu/gpu_command_buffer_stub.cc b/chrome/gpu/gpu_command_buffer_stub.cc new file mode 100644 index 0000000..6c3f5cc --- /dev/null +++ b/chrome/gpu/gpu_command_buffer_stub.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2010 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. + +#if defined(ENABLE_GPU) + +#include "base/process_util.h" +#include "base/shared_memory.h" +#include "chrome/common/gpu_messages.h" +#include "chrome/gpu/gpu_channel.h" +#include "chrome/gpu/gpu_command_buffer_stub.h" + +using gpu::Buffer; + +GpuCommandBufferStub::GpuCommandBufferStub(GpuChannel* channel, + int32 route_id) + : channel_(channel), + route_id_(route_id) { +} + +GpuCommandBufferStub::~GpuCommandBufferStub() { +} + +void GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(GpuCommandBufferStub, message) + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Initialize, OnInitialize); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_GetState, OnGetState); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncGetState, OnAsyncGetState); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Flush, OnFlush); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncFlush, OnAsyncFlush); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_CreateTransferBuffer, + OnCreateTransferBuffer); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyTransferBuffer, + OnDestroyTransferBuffer); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_GetTransferBuffer, + OnGetTransferBuffer); + IPC_MESSAGE_UNHANDLED_ERROR() + IPC_END_MESSAGE_MAP() +} + +bool GpuCommandBufferStub::Send(IPC::Message* message) { + return channel_->Send(message); +} + +void GpuCommandBufferStub::OnInitialize( + int32 size, + base::SharedMemoryHandle* ring_buffer) { + DCHECK(!command_buffer_.get()); + + *ring_buffer = base::SharedMemory::NULLHandle(); + + command_buffer_.reset(new gpu::CommandBufferService); + + // Initialize the CommandBufferService and GPUProcessor. + if (command_buffer_->Initialize(size)) { + Buffer buffer = command_buffer_->GetRingBuffer(); + if (buffer.shared_memory) { + processor_ = new gpu::GPUProcessor(command_buffer_.get()); + if (processor_->Initialize(gfx::kNullPluginWindow)) { + command_buffer_->SetPutOffsetChangeCallback( + NewCallback(processor_.get(), + &gpu::GPUProcessor::ProcessCommands)); + + // Assume service is responsible for duplicating the handle from the + // calling process. + buffer.shared_memory->ShareToProcess(channel_->renderer_handle(), + ring_buffer); + } else { + processor_ = NULL; + command_buffer_.reset(); + } + } + } +} + +void GpuCommandBufferStub::OnGetState(gpu::CommandBuffer::State* state) { + *state = command_buffer_->GetState(); +} + +void GpuCommandBufferStub::OnAsyncGetState() { + gpu::CommandBuffer::State state = command_buffer_->GetState(); + Send(new GpuCommandBufferMsg_UpdateState(route_id_, state)); +} + +void GpuCommandBufferStub::OnFlush(int32 put_offset, + gpu::CommandBuffer::State* state) { + *state = command_buffer_->Flush(put_offset); +} + +void GpuCommandBufferStub::OnAsyncFlush(int32 put_offset) { + gpu::CommandBuffer::State state = command_buffer_->Flush(put_offset); + Send(new GpuCommandBufferMsg_UpdateState(route_id_, state)); +} + +void GpuCommandBufferStub::OnCreateTransferBuffer(int32 size, int32* id) { + *id = command_buffer_->CreateTransferBuffer(size); +} + +void GpuCommandBufferStub::OnDestroyTransferBuffer(int32 id) { + command_buffer_->DestroyTransferBuffer(id); +} + +void GpuCommandBufferStub::OnGetTransferBuffer( + int32 id, + base::SharedMemoryHandle* transfer_buffer, + uint32* size) { + *transfer_buffer = base::SharedMemoryHandle(); + *size = 0; + + Buffer buffer = command_buffer_->GetTransferBuffer(id); + if (buffer.shared_memory) { + // Assume service is responsible for duplicating the handle to the calling + // process. + buffer.shared_memory->ShareToProcess(channel_->renderer_handle(), + transfer_buffer); + *size = buffer.shared_memory->max_size(); + } +} + +#endif // ENABLE_GPU diff --git a/chrome/gpu/gpu_command_buffer_stub.h b/chrome/gpu/gpu_command_buffer_stub.h new file mode 100644 index 0000000..f1446e8 --- /dev/null +++ b/chrome/gpu/gpu_command_buffer_stub.h @@ -0,0 +1,62 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_GPU_GPU_COMMAND_BUFFER_STUB_H_ +#define CHROME_GPU_GPU_COMMAND_BUFFER_STUB_H_ + +#if defined(ENABLE_GPU) + +#include "app/gfx/native_widget_types.h" +#include "base/process.h" +#include "base/ref_counted.h" +#include "gpu/command_buffer/service/command_buffer_service.h" +#include "gpu/command_buffer/service/gpu_processor.h" +#include "ipc/ipc_channel.h" +#include "ipc/ipc_message.h" + +class GpuChannel; + +class GpuCommandBufferStub + : public IPC::Channel::Listener, + public IPC::Message::Sender, + public base::RefCountedThreadSafe<GpuCommandBufferStub> { + public: + GpuCommandBufferStub(GpuChannel* channel, + int32 route_id); + + virtual ~GpuCommandBufferStub(); + + // IPC::Channel::Listener implementation: + virtual void OnMessageReceived(const IPC::Message& message); + + // IPC::Message::Sender implementation: + virtual bool Send(IPC::Message* msg); + + int route_id() const { return route_id_; } + + private: + // Message handlers: + void OnInitialize(int32 size, base::SharedMemoryHandle* ring_buffer); + void OnGetState(gpu::CommandBuffer::State* state); + void OnAsyncGetState(); + void OnFlush(int32 put_offset, gpu::CommandBuffer::State* state); + void OnAsyncFlush(int32 put_offset); + void OnCreateTransferBuffer(int32 size, int32* id); + void OnDestroyTransferBuffer(int32 id); + void OnGetTransferBuffer(int32 id, + base::SharedMemoryHandle* transfer_buffer, + uint32* size); + + scoped_refptr<GpuChannel> channel_; + int route_id_; + + scoped_ptr<gpu::CommandBufferService> command_buffer_; + scoped_refptr<gpu::GPUProcessor> processor_; + + DISALLOW_COPY_AND_ASSIGN(GpuCommandBufferStub); +}; + +#endif // ENABLE_GPU + +#endif // CHROME_GPU_GPU_COMMAND_BUFFER_STUB_H_ diff --git a/chrome/gpu/gpu_thread.cc b/chrome/gpu/gpu_thread.cc index 4c9a974..1839412 100644 --- a/chrome/gpu/gpu_thread.cc +++ b/chrome/gpu/gpu_thread.cc @@ -5,7 +5,9 @@ #include "chrome/gpu/gpu_thread.h" #include "build/build_config.h" +#include "chrome/common/child_process.h" #include "chrome/common/gpu_messages.h" +#include "chrome/gpu/gpu_channel.h" #include "chrome/gpu/gpu_config.h" #if defined(OS_WIN) @@ -37,11 +39,30 @@ GpuBackingStoreGLXContext* GpuThread::GetGLXContext() { void GpuThread::OnControlMessageReceived(const IPC::Message& msg) { bool msg_is_ok = true; IPC_BEGIN_MESSAGE_MAP_EX(GpuThread, msg, msg_is_ok) + IPC_MESSAGE_HANDLER(GpuMsg_EstablishChannel, + OnEstablishChannel) IPC_MESSAGE_HANDLER(GpuMsg_NewRenderWidgetHostView, OnNewRenderWidgetHostView) IPC_END_MESSAGE_MAP_EX() } +void GpuThread::OnEstablishChannel(int renderer_id) { + scoped_refptr<GpuChannel> channel = + GpuChannel::EstablishGpuChannel(renderer_id); + IPC::ChannelHandle channel_handle; + if (channel.get()) { + channel_handle.name = channel->channel_name(); +#if defined(OS_POSIX) + // On POSIX, pass the renderer-side FD. Also mark it as auto-close so that + // it gets closed after it has been sent. + int renderer_fd = channel->DisownRendererFd(); + channel_handle.socket = base::FileDescriptor(renderer_fd, true); +#endif + } + + Send(new GpuHostMsg_ChannelEstablished(channel_handle)); +} + void GpuThread::OnNewRenderWidgetHostView(GpuNativeWindowHandle parent_window, int32 routing_id) { // The GPUView class' lifetime is controlled by the host, which will send a diff --git a/chrome/gpu/gpu_thread.h b/chrome/gpu/gpu_thread.h index f58db07..8224a9b 100644 --- a/chrome/gpu/gpu_thread.h +++ b/chrome/gpu/gpu_thread.h @@ -34,6 +34,7 @@ class GpuThread : public ChildThread { virtual void OnControlMessageReceived(const IPC::Message& msg); // Message handlers. + void OnEstablishChannel(int renderer_id); void OnNewRenderWidgetHostView(GpuNativeWindowHandle parent_window, int32 routing_id); diff --git a/chrome/plugin/command_buffer_stub.cc b/chrome/plugin/command_buffer_stub.cc index d8cc7d4..5ae203d 100644 --- a/chrome/plugin/command_buffer_stub.cc +++ b/chrome/plugin/command_buffer_stub.cc @@ -5,7 +5,7 @@ #include "base/callback.h" #include "base/scoped_open_process.h" #include "base/shared_memory.h" -#include "chrome/common/command_buffer_messages.h" +#include "chrome/common/gpu_messages.h" #include "chrome/common/plugin_messages.h" #include "chrome/plugin/command_buffer_stub.h" #include "chrome/plugin/plugin_channel.h" @@ -29,19 +29,19 @@ CommandBufferStub::~CommandBufferStub() { void CommandBufferStub::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(CommandBufferStub, message) - IPC_MESSAGE_HANDLER(CommandBufferMsg_Initialize, OnInitialize); - IPC_MESSAGE_HANDLER(CommandBufferMsg_GetState, OnGetState); - IPC_MESSAGE_HANDLER(CommandBufferMsg_AsyncGetState, OnAsyncGetState); - IPC_MESSAGE_HANDLER(CommandBufferMsg_Flush, OnFlush); - IPC_MESSAGE_HANDLER(CommandBufferMsg_AsyncFlush, OnAsyncFlush); - IPC_MESSAGE_HANDLER(CommandBufferMsg_CreateTransferBuffer, + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Initialize, OnInitialize); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_GetState, OnGetState); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncGetState, OnAsyncGetState); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Flush, OnFlush); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncFlush, OnAsyncFlush); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_CreateTransferBuffer, OnCreateTransferBuffer); - IPC_MESSAGE_HANDLER(CommandBufferMsg_DestroyTransferBuffer, + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyTransferBuffer, OnDestroyTransferBuffer); - IPC_MESSAGE_HANDLER(CommandBufferMsg_GetTransferBuffer, + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_GetTransferBuffer, OnGetTransferBuffer); #if defined(OS_MACOSX) - IPC_MESSAGE_HANDLER(CommandBufferMsg_SetWindowSize, OnSetWindowSize); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SetWindowSize, OnSetWindowSize); #endif IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP() @@ -127,7 +127,7 @@ void CommandBufferStub::OnGetState(gpu::CommandBuffer::State* state) { void CommandBufferStub::OnAsyncGetState() { gpu::CommandBuffer::State state = command_buffer_->GetState(); - Send(new CommandBufferMsg_UpdateState(route_id_, state)); + Send(new GpuCommandBufferMsg_UpdateState(route_id_, state)); } void CommandBufferStub::OnFlush(int32 put_offset, @@ -137,7 +137,7 @@ void CommandBufferStub::OnFlush(int32 put_offset, void CommandBufferStub::OnAsyncFlush(int32 put_offset) { gpu::CommandBuffer::State state = command_buffer_->Flush(put_offset); - Send(new CommandBufferMsg_UpdateState(route_id_, state)); + Send(new GpuCommandBufferMsg_UpdateState(route_id_, state)); } void CommandBufferStub::OnCreateTransferBuffer(int32 size, int32* id) { diff --git a/chrome/plugin/command_buffer_stub_win.cc b/chrome/plugin/command_buffer_stub_win.cc index 656bbd1..abf13b1 100644 --- a/chrome/plugin/command_buffer_stub_win.cc +++ b/chrome/plugin/command_buffer_stub_win.cc @@ -4,7 +4,7 @@ #include <windows.h> -#include "chrome/common/command_buffer_messages.h" +#include "chrome/common/gpu_messages.h" #include "chrome/plugin/command_buffer_stub.h" namespace { @@ -45,7 +45,7 @@ LRESULT WINAPI WndProc(HWND handle, } // namespace anonymous void CommandBufferStub::NotifyRepaint() { - Send(new CommandBufferMsg_NotifyRepaint(route_id_)); + Send(new GpuCommandBufferMsg_NotifyRepaint(route_id_)); } bool CommandBufferStub::InitializePlatformSpecific() { diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc index 7654058..e3d477e 100644 --- a/chrome/plugin/webplugin_delegate_stub.cc +++ b/chrome/plugin/webplugin_delegate_stub.cc @@ -140,6 +140,8 @@ void WebPluginDelegateStub::OnMessageReceived(const IPC::Message& msg) { OnHTTPRangeRequestReply) IPC_MESSAGE_HANDLER(PluginMsg_CreateCommandBuffer, OnCreateCommandBuffer) + IPC_MESSAGE_HANDLER(PluginMsg_DestroyCommandBuffer, + OnDestroyCommandBuffer) #if defined(OS_MACOSX) IPC_MESSAGE_HANDLER(PluginMsg_SetFakeGPUPluginWindowHandle, OnSetFakeGPUPluginWindowHandle) @@ -406,6 +408,12 @@ void WebPluginDelegateStub::OnCreateCommandBuffer(int* route_id) { #endif // ENABLE_GPU } +void WebPluginDelegateStub::OnDestroyCommandBuffer() { +#if defined(ENABLE_GPU) + command_buffer_stub_.reset(); +#endif +} + void WebPluginDelegateStub::CreateSharedBuffer( uint32 size, base::SharedMemory* shared_buf, diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h index 36fda08..1bbd04d 100644 --- a/chrome/plugin/webplugin_delegate_stub.h +++ b/chrome/plugin/webplugin_delegate_stub.h @@ -98,6 +98,8 @@ class WebPluginDelegateStub : public IPC::Channel::Listener, int notify_id); void OnHTTPRangeRequestReply(unsigned long resource_id, int range_request_id); void OnCreateCommandBuffer(int* route_id); + void OnDestroyCommandBuffer(); + void CreateSharedBuffer(uint32 size, base::SharedMemory* shared_buf, base::SharedMemoryHandle* remote_handle); diff --git a/chrome/renderer/command_buffer_proxy.cc b/chrome/renderer/command_buffer_proxy.cc index b2eaa86..bd0f3a0 100644 --- a/chrome/renderer/command_buffer_proxy.cc +++ b/chrome/renderer/command_buffer_proxy.cc @@ -4,7 +4,7 @@ #include "base/logging.h" #include "base/process_util.h" -#include "chrome/common/command_buffer_messages.h" +#include "chrome/common/gpu_messages.h" #include "chrome/common/plugin_messages.h" #include "chrome/renderer/command_buffer_proxy.h" #include "chrome/renderer/plugin_channel_host.h" @@ -13,12 +13,11 @@ using gpu::Buffer; CommandBufferProxy::CommandBufferProxy( - PluginChannelHost* channel, + IPC::Channel::Sender* channel, int route_id) : size_(0), channel_(channel), route_id_(route_id) { - channel->AddRoute(route_id_, this, false); } CommandBufferProxy::~CommandBufferProxy() { @@ -30,20 +29,24 @@ CommandBufferProxy::~CommandBufferProxy() { delete it->second.shared_memory; it->second.shared_memory = NULL; } - - channel_->RemoveRoute(route_id_); } void CommandBufferProxy::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(CommandBufferProxy, message) - IPC_MESSAGE_HANDLER(CommandBufferMsg_UpdateState, OnUpdateState); - IPC_MESSAGE_HANDLER(CommandBufferMsg_NotifyRepaint, + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_UpdateState, OnUpdateState); + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_NotifyRepaint, OnNotifyRepaint); IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP() } void CommandBufferProxy::OnChannelError() { + // Prevent any further messages from being sent. + channel_ = NULL; + + // When the client sees that the context is lost, they should delete this + // CommandBufferProxy and create a new one. + last_state_.error = gpu::error::kLostContext; } bool CommandBufferProxy::Send(IPC::Message* msg) { @@ -63,7 +66,7 @@ bool CommandBufferProxy::Initialize(int32 size) { // process is responsible for duplicating the handle. This might not be true // for NaCl. base::SharedMemoryHandle handle; - if (Send(new CommandBufferMsg_Initialize(route_id_, size, &handle)) && + if (Send(new GpuCommandBufferMsg_Initialize(route_id_, size, &handle)) && base::SharedMemory::IsHandleValid(handle)) { ring_buffer_.reset(new base::SharedMemory(handle, false)); if (ring_buffer_->Map(size * sizeof(int32))) { @@ -87,12 +90,12 @@ Buffer CommandBufferProxy::GetRingBuffer() { } gpu::CommandBuffer::State CommandBufferProxy::GetState() { - Send(new CommandBufferMsg_GetState(route_id_, &last_state_)); + Send(new GpuCommandBufferMsg_GetState(route_id_, &last_state_)); return last_state_; } gpu::CommandBuffer::State CommandBufferProxy::Flush(int32 put_offset) { - Send(new CommandBufferMsg_Flush(route_id_, + Send(new GpuCommandBufferMsg_Flush(route_id_, put_offset, &last_state_)); return last_state_; @@ -105,7 +108,7 @@ void CommandBufferProxy::SetGetOffset(int32 get_offset) { int32 CommandBufferProxy::CreateTransferBuffer(size_t size) { int32 id; - if (Send(new CommandBufferMsg_CreateTransferBuffer(route_id_, size, &id))) + if (Send(new GpuCommandBufferMsg_CreateTransferBuffer(route_id_, size, &id))) return id; return -1; @@ -121,7 +124,7 @@ void CommandBufferProxy::DestroyTransferBuffer(int32 id) { transfer_buffers_.erase(it); - Send(new CommandBufferMsg_DestroyTransferBuffer(route_id_, id)); + Send(new GpuCommandBufferMsg_DestroyTransferBuffer(route_id_, id)); } Buffer CommandBufferProxy::GetTransferBuffer(int32 id) { @@ -136,7 +139,7 @@ Buffer CommandBufferProxy::GetTransferBuffer(int32 id) { // duplicating the handle. This might not be true for NaCl. base::SharedMemoryHandle handle; uint32 size; - if (!Send(new CommandBufferMsg_GetTransferBuffer(route_id_, + if (!Send(new GpuCommandBufferMsg_GetTransferBuffer(route_id_, id, &handle, &size))) { @@ -182,12 +185,12 @@ void CommandBufferProxy::SetParseError( #if defined(OS_MACOSX) void CommandBufferProxy::SetWindowSize(int32 width, int32 height) { - Send(new CommandBufferMsg_SetWindowSize(route_id_, width, height)); + Send(new GpuCommandBufferMsg_SetWindowSize(route_id_, width, height)); } #endif void CommandBufferProxy::AsyncGetState(Task* completion_task) { - IPC::Message* message = new CommandBufferMsg_AsyncGetState(route_id_); + IPC::Message* message = new GpuCommandBufferMsg_AsyncGetState(route_id_); // Do not let a synchronous flush hold up this message. If this handler is // deferred until after the synchronous flush completes, it will overwrite the @@ -199,7 +202,7 @@ void CommandBufferProxy::AsyncGetState(Task* completion_task) { } void CommandBufferProxy::AsyncFlush(int32 put_offset, Task* completion_task) { - IPC::Message* message = new CommandBufferMsg_AsyncFlush(route_id_, + IPC::Message* message = new GpuCommandBufferMsg_AsyncFlush(route_id_, put_offset); // Do not let a synchronous flush hold up this message. If this handler is diff --git a/chrome/renderer/command_buffer_proxy.h b/chrome/renderer/command_buffer_proxy.h index 990f6f3..5d72f2c 100644 --- a/chrome/renderer/command_buffer_proxy.h +++ b/chrome/renderer/command_buffer_proxy.h @@ -27,9 +27,7 @@ class CommandBufferProxy : public gpu::CommandBuffer, public IPC::Channel::Listener, public IPC::Message::Sender { public: - explicit CommandBufferProxy( - PluginChannelHost* channel, - int route_id); + CommandBufferProxy(IPC::Channel::Sender* channel, int route_id); virtual ~CommandBufferProxy(); // IPC::Channel::Listener implementation: @@ -39,6 +37,8 @@ class CommandBufferProxy : public gpu::CommandBuffer, // IPC::Message::Sender implementation: virtual bool Send(IPC::Message* msg); + int route_id() const { return route_id_; } + // CommandBuffer implementation: virtual bool Initialize(int32 size); virtual gpu::Buffer GetRingBuffer(); @@ -90,7 +90,7 @@ class CommandBufferProxy : public gpu::CommandBuffer, // The last cached state received from the service. State last_state_; - scoped_refptr<PluginChannelHost> channel_; + IPC::Channel::Sender* channel_; int route_id_; // Pending asynchronous flush callbacks. diff --git a/chrome/renderer/gpu_channel_host.cc b/chrome/renderer/gpu_channel_host.cc new file mode 100644 index 0000000..8e48b85 --- /dev/null +++ b/chrome/renderer/gpu_channel_host.cc @@ -0,0 +1,101 @@ +// Copyright (c) 2010 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 "chrome/renderer/gpu_channel_host.h" + +#include "chrome/common/child_process.h" +#include "chrome/common/gpu_messages.h" +#include "chrome/renderer/command_buffer_proxy.h" + +GpuChannelHost::GpuChannelHost() : state_(UNCONNECTED) { +} + +GpuChannelHost::~GpuChannelHost() { +} + +void GpuChannelHost::Connect(const std::string& channel_name) { + // Open a channel to the GPU process. + channel_.reset(new IPC::SyncChannel( + channel_name, IPC::Channel::MODE_CLIENT, this, NULL, + ChildProcess::current()->io_message_loop(), true, + ChildProcess::current()->GetShutDownEvent())); +} + +void GpuChannelHost::OnMessageReceived(const IPC::Message& message) { + DCHECK(message.routing_id() != MSG_ROUTING_CONTROL); + if (!router_.RouteMessage(message)) { + NOTREACHED() << "GpuChannelHost failed to route message"; + } +} + +void GpuChannelHost::OnChannelConnected(int32 peer_pid) { + state_ = CONNECTED; +} + +void GpuChannelHost::OnChannelError() { + state_ = LOST; + + // 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++) { + proxies_.erase(iter->first); + 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) { + if (!channel_.get()) { + delete message; + return false; + } + + return channel_->Send(message); +} + +CommandBufferProxy* GpuChannelHost::CreateCommandBuffer() { +#if defined(ENABLE_GPU) + // An error occurred. Need to get the host again to reinitialize it. + if (!channel_.get()) + return NULL; + + int32 route_id; + if (!Send(new GpuChannelMsg_CreateCommandBuffer(&route_id)) && + route_id != MSG_ROUTING_NONE) { + return NULL; + } + + CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id); + router_.AddRoute(route_id, command_buffer); + proxies_[route_id] = command_buffer; + return command_buffer; +#else + return NULL; +#endif +} + +void GpuChannelHost::DestroyCommandBuffer(CommandBufferProxy* command_buffer) { +#if defined(ENABLE_GPU) + 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()) { + proxies_.erase(route_id); + router_.RemoveRoute(route_id); + } + + delete command_buffer; +#endif +} diff --git a/chrome/renderer/gpu_channel_host.h b/chrome/renderer/gpu_channel_host.h new file mode 100644 index 0000000..00a6129 --- /dev/null +++ b/chrome/renderer/gpu_channel_host.h @@ -0,0 +1,77 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_RENDERER_GPU_CHANNEL_HOST_H_ +#define CHROME_RENDERER_GPU_CHANNEL_HOST_H_ + +#include <string> + +#include "base/hash_tables.h" +#include "chrome/common/message_router.h" +#include "ipc/ipc_channel.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_sync_channel.h" + +class CommandBufferProxy; + +// Encapsulates an IPC channel between the renderer and one plugin process. +// On the plugin side there's a corresponding GpuChannel. +class GpuChannelHost : public IPC::Channel::Listener, + public IPC::Message::Sender, + public base::RefCountedThreadSafe<GpuChannelHost> { + public: + enum State { + // Not yet connected. + UNCONNECTED, + // Ready to use. + CONNECTED, + // An error caused the host to become disconnected. Recreate channel to + // reestablish connection. + LOST + }; + + // Called on the render thread + GpuChannelHost(); + ~GpuChannelHost(); + + // Connect to GPU process channel. + void Connect(const std::string& channel_name); + + State state() const { return state_; } + + // Returns whether the channel to the GPU process is ready. + bool ready() const { return channel_.get() != NULL; } + + // IPC::Channel::Listener implementation: + virtual void OnMessageReceived(const IPC::Message& msg); + virtual void OnChannelConnected(int32 peer_pid); + virtual void OnChannelError(); + + // IPC::Message::Sender implementation: + virtual bool Send(IPC::Message* msg); + + // Create and connect to a command buffer in the GPU process. + CommandBufferProxy* CreateCommandBuffer(); + + // Destroy a command buffer created by this channel. + void DestroyCommandBuffer(CommandBufferProxy* command_buffer); + + private: + State state_; + + scoped_ptr<IPC::SyncChannel> channel_; + + // Used to implement message routing functionality to CommandBufferProxy + // objects + MessageRouter router_; + + // Keep track of all the registered CommandBufferProxies to + // inform about OnChannelError + typedef base::hash_map<int, IPC::Channel::Listener*> ProxyMap; + ProxyMap proxies_; + + DISALLOW_COPY_AND_ASSIGN(GpuChannelHost); +}; + +#endif // CHROME_RENDERER_GPU_CHANNEL_HOST_H_ diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc index 343db541..7d59256 100644 --- a/chrome/renderer/render_widget.cc +++ b/chrome/renderer/render_widget.cc @@ -147,6 +147,7 @@ IPC_DEFINE_MESSAGE_MAP(RenderWidget) IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition) IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnMsgRepaint) IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection) + IPC_MESSAGE_HANDLER(ViewMsg_GpuChannelEstablished, OnGpuChannelEstablished) IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck) IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP() @@ -725,6 +726,17 @@ void RenderWidget::OnSetTextDirection(WebTextDirection direction) { webwidget_->setTextDirection(direction); } +void RenderWidget::OnGpuChannelEstablished( + const IPC::ChannelHandle& channel_handle) { + if (channel_handle.name.size() != 0) { + // Connect to the GPU process if a channel name was received. + gpu_channel_->Connect(channel_handle.name); + } else { + // Otherwise cancel the connection. + gpu_channel_ = NULL; + } +} + void RenderWidget::SetHidden(bool hidden) { if (is_hidden_ == hidden) return; @@ -867,3 +879,32 @@ void RenderWidget::CleanupWindowInPluginMoves(gfx::PluginWindowHandle window) { } } } + +void RenderWidget::EstablishGpuChannel() { + if (gpu_channel_.get()) { + // Do nothing if we are already establishing GPU channel. + if (gpu_channel_->state() == GpuChannelHost::UNCONNECTED) + return; + + // Recreate the channel if it has been lost. + if (gpu_channel_->state() == GpuChannelHost::LOST) + gpu_channel_ = NULL; + } + + if (!gpu_channel_.get()) + gpu_channel_ = new GpuChannelHost; + + // Ask the browser for the channel name. + CHECK(Send(new ViewHostMsg_EstablishGpuChannel(routing_id_))); +} + +GpuChannelHost* RenderWidget::GetGpuChannel() { + if (!gpu_channel_.get()) + return NULL; + + if (gpu_channel_->state() != GpuChannelHost::CONNECTED) + return NULL; + + return gpu_channel_.get(); +} + diff --git a/chrome/renderer/render_widget.h b/chrome/renderer/render_widget.h index ab591f0..cc32898 100644 --- a/chrome/renderer/render_widget.h +++ b/chrome/renderer/render_widget.h @@ -14,9 +14,11 @@ #include "base/gfx/size.h" #include "base/ref_counted.h" #include "base/shared_memory.h" +#include "chrome/renderer/gpu_channel_host.h" #include "chrome/renderer/paint_aggregator.h" #include "chrome/renderer/render_process.h" #include "ipc/ipc_channel.h" +#include "ipc/ipc_channel_handle.h" #include "skia/ext/platform_canvas.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/WebKit/WebKit/chromium/public/WebCompositionCommand.h" @@ -105,6 +107,15 @@ class RenderWidget : public IPC::Channel::Listener, // Close the underlying WebWidget. virtual void Close(); + // Asynchronously establish a channel to the GPU plugin if not previously + // established or if it has been lost (for example if the GPU plugin crashed). + // Use GetGpuChannel() to determine when the channel is ready for use. + void EstablishGpuChannel(); + + // Get the GPU channel. Returns NULL if the channel is not established or + // has been lost. + GpuChannelHost* GetGpuChannel(); + protected: // Friend RefCounted so that the dtor can be non-public. Using this class // without ref-counting is an error. @@ -160,6 +171,7 @@ class RenderWidget : public IPC::Channel::Listener, const string16& ime_string); void OnMsgRepaint(const gfx::Size& size_to_paint); void OnSetTextDirection(WebKit::WebTextDirection direction); + void OnGpuChannelEstablished(const IPC::ChannelHandle& channel_handle); // Override point to notify that a paint has happened. This fires after the // browser side has updated the screen for a newly painted region. @@ -317,6 +329,9 @@ class RenderWidget : public IPC::Channel::Listener, // Indicates if the next sequence of Char events should be suppressed or not. bool suppress_next_char_events_; + // The channel from the renderer process to the GPU process. + scoped_refptr<GpuChannelHost> gpu_channel_; + DISALLOW_COPY_AND_ASSIGN(RenderWidget); }; diff --git a/chrome/renderer/webplugin_delegate_pepper.cc b/chrome/renderer/webplugin_delegate_pepper.cc index 5f09e65..e6efd40 100644 --- a/chrome/renderer/webplugin_delegate_pepper.cc +++ b/chrome/renderer/webplugin_delegate_pepper.cc @@ -123,6 +123,13 @@ void WebPluginDelegatePepper::DestroyInstance() { // rendering commands after the GPU plugin has stopped processing them and // responding to them. if (nested_delegate_) { +#if defined(ENABLE_GPU) + if (command_buffer_) { + nested_delegate_->DestroyCommandBuffer(command_buffer_); + command_buffer_ = NULL; + } +#endif + nested_delegate_->PluginDestroyed(); nested_delegate_ = NULL; } @@ -159,7 +166,7 @@ void WebPluginDelegatePepper::UpdateGeometry( // Send the new window size to the command buffer service code so it // can allocate a new backing store. The handle to the new backing // store is sent back to the browser asynchronously. - if (command_buffer_.get()) { + if (command_buffer_) { command_buffer_->SetWindowSize(window_rect_.width(), window_rect_.height()); } @@ -364,8 +371,8 @@ NPError WebPluginDelegatePepper::Device3DInitializeContext( plugin_->SetAcceptsInputEvents(true); // Ask the GPU plugin to create a command buffer and return a proxy. - command_buffer_.reset(nested_delegate_->CreateCommandBuffer()); - if (command_buffer_.get()) { + command_buffer_ = nested_delegate_->CreateCommandBuffer(); + if (command_buffer_) { // Initialize the proxy command buffer. if (command_buffer_->Initialize(config->commandBufferSize)) { // Get the initial command buffer state. @@ -395,14 +402,15 @@ NPError WebPluginDelegatePepper::Device3DInitializeContext( // Save the implementation information (the CommandBuffer). Device3DImpl* impl = new Device3DImpl; - impl->command_buffer = command_buffer_.get(); + impl->command_buffer = command_buffer_; context->reserved = impl; return NPERR_NO_ERROR; } } - command_buffer_.reset(); + nested_delegate_->DestroyCommandBuffer(command_buffer_); + command_buffer_ = NULL; } nested_delegate_->PluginDestroyed(); @@ -482,9 +490,12 @@ NPError WebPluginDelegatePepper::Device3DDestroyContext( delete static_cast<Device3DImpl*>(context->reserved); context->reserved = NULL; - command_buffer_.reset(); - if (nested_delegate_) { + if (command_buffer_) { + nested_delegate_->DestroyCommandBuffer(command_buffer_); + command_buffer_ = NULL; + } + nested_delegate_->PluginDestroyed(); nested_delegate_ = NULL; } @@ -849,7 +860,7 @@ void WebPluginDelegatePepper::Device3DUpdateState( NPDeviceContext3D* context, NPDeviceFlushContextCallbackPtr callback, void* user_data) { - if (command_buffer_.get()) { + if (command_buffer_) { Synchronize3DContext(context, command_buffer_->GetLastState()); if (callback) callback(npp, context, NPERR_NO_ERROR, user_data); diff --git a/chrome/renderer/webplugin_delegate_pepper.h b/chrome/renderer/webplugin_delegate_pepper.h index a67b530..181b40b 100644 --- a/chrome/renderer/webplugin_delegate_pepper.h +++ b/chrome/renderer/webplugin_delegate_pepper.h @@ -205,7 +205,7 @@ class WebPluginDelegatePepper : public webkit_glue::WebPluginDelegate { #if defined(ENABLE_GPU) // The command buffer used to issue commands to the nested GPU plugin. - scoped_ptr<CommandBufferProxy> command_buffer_; + CommandBufferProxy* command_buffer_; #endif // Tells the browser out-of-band where the nested delegate lives on diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index 4157a1f..1e64648 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -1280,12 +1280,25 @@ CommandBufferProxy* WebPluginDelegateProxy::CreateCommandBuffer() { return NULL; } - return new CommandBufferProxy(channel_host_, command_buffer_id); + CommandBufferProxy* command_buffer = + new CommandBufferProxy(channel_host_, command_buffer_id); + channel_host_->AddRoute(command_buffer_id, command_buffer, NULL); + return command_buffer; #else return NULL; #endif // ENABLE_GPU } +void WebPluginDelegateProxy::DestroyCommandBuffer( + CommandBufferProxy* command_buffer) { + DCHECK(command_buffer); +#if defined(ENABLE_GPU) + Send(new PluginMsg_DestroyCommandBuffer(instance_id_)); + channel_host_->RemoveRoute(command_buffer->route_id()); + delete command_buffer; +#endif +} + gfx::PluginWindowHandle WebPluginDelegateProxy::GetPluginWindowHandle() { return window_; } diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h index 18d2704..212758e 100644 --- a/chrome/renderer/webplugin_delegate_proxy.h +++ b/chrome/renderer/webplugin_delegate_proxy.h @@ -106,6 +106,8 @@ class WebPluginDelegateProxy unsigned long resource_id, int range_request_id); CommandBufferProxy* CreateCommandBuffer(); + void DestroyCommandBuffer(CommandBufferProxy* command_buffer); + gfx::PluginWindowHandle GetPluginWindowHandle(); protected: diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index dbb49e9..e07dc99 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -287,8 +287,14 @@ class GLES2DecoderImpl : public GLES2Decoder { return group_->texture_manager(); } +#if defined(OS_WIN) + static bool InitializeOneOff(bool anti_aliased); +#endif + + bool InitPlatformSpecific(); - bool InitGlew(); + static bool InitGlew(); + void DestroyPlatformSpecific(); // Template to help call glGenXXX functions. template <void gl_gen_function(GLES2DecoderImpl*, GLsizei, GLuint*)> @@ -615,8 +621,10 @@ class GLES2DecoderImpl : public GLES2Decoder { #if defined(UNIT_TEST) #elif defined(OS_WIN) - HDC device_context_; + static int pixel_format_; + HDC gl_device_context_; HGLRC gl_context_; + HPBUFFERARB pbuffer_; #elif defined(OS_MACOSX) CGLContextObj gl_context_; CGLPBufferObj pbuffer_; @@ -657,6 +665,11 @@ GLES2Decoder* GLES2Decoder::Create(ContextGroup* group) { return new GLES2DecoderImpl(group); } +#if defined(UNIT_TEST) +#elif defined(OS_WIN) +int GLES2DecoderImpl::pixel_format_; +#endif + GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group) : GLES2Decoder(group), error_bits_(0), @@ -668,8 +681,9 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group) black_cube_texture_id_(0), #if defined(UNIT_TEST) #elif defined(OS_WIN) - device_context_(NULL), + gl_device_context_(NULL), gl_context_(NULL), + pbuffer_(NULL), #elif defined(OS_MACOSX) gl_context_(NULL), pbuffer_(NULL), @@ -685,49 +699,62 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group) } bool GLES2DecoderImpl::Initialize() { - bool success = false; - - if (InitPlatformSpecific()) { - if (MakeCurrent()) { - if (InitGlew()) { - CHECK_GL_ERROR(); - success = group_->Initialize(); - if (success) { - vertex_attrib_infos_.reset( - new VertexAttribInfo[group_->max_vertex_attribs()]); - texture_units_.reset( - new TextureUnit[group_->max_texture_units()]); - GLuint ids[2]; - glGenTextures(2, ids); - // Make black textures for replacing non-renderable textures. - black_2d_texture_id_ = ids[0]; - black_cube_texture_id_ = ids[1]; - static int8 black[] = {0, 0, 0, 0}; - glBindTexture(GL_TEXTURE_2D, black_2d_texture_id_); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, - GL_UNSIGNED_BYTE, black); - glBindTexture(GL_TEXTURE_2D, 0); - glBindTexture(GL_TEXTURE_CUBE_MAP, black_cube_texture_id_); - static GLenum faces[] = { - GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - }; - for (size_t ii = 0; ii < arraysize(faces); ++ii) { - glTexImage2D(faces[ii], 0, GL_RGBA, 1, 1, 0, GL_RGBA, - GL_UNSIGNED_BYTE, black); - } - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); - CHECK_GL_ERROR(); - } - } - } + if (!InitPlatformSpecific()) { + Destroy(); + return false; + } + if (!MakeCurrent()) { + Destroy(); + return false; + } + + // This happens in InitializeOneOff in windows. TODO(apatrick): generalize to + // other platforms. +#if !defined(OS_WIN) + if (!InitGlew()) { + Destroy(); + return false; + } +#endif + + CHECK_GL_ERROR(); + + if (!group_->Initialize()) { + Destroy(); + return false; + } + + vertex_attrib_infos_.reset( + new VertexAttribInfo[group_->max_vertex_attribs()]); + texture_units_.reset( + new TextureUnit[group_->max_texture_units()]); + GLuint ids[2]; + glGenTextures(2, ids); + // Make black textures for replacing non-renderable textures. + black_2d_texture_id_ = ids[0]; + black_cube_texture_id_ = ids[1]; + static int8 black[] = {0, 0, 0, 0}; + glBindTexture(GL_TEXTURE_2D, black_2d_texture_id_); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, + GL_UNSIGNED_BYTE, black); + glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_CUBE_MAP, black_cube_texture_id_); + static GLenum faces[] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + }; + for (size_t ii = 0; ii < arraysize(faces); ++ii) { + glTexImage2D(faces[ii], 0, GL_RGBA, 1, 1, 0, GL_RGBA, + GL_UNSIGNED_BYTE, black); } + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + CHECK_GL_ERROR(); - return success; + return true; } // TODO(kbr): the use of this anonymous namespace core dumps the @@ -764,11 +791,9 @@ LRESULT CALLBACK IntermediateWindowProc(HWND window, return ::DefWindowProc(window, message, w_param, l_param); } -// Helper routine that returns the highest quality pixel format supported on -// the current platform. Returns true upon success. -bool GetWindowsPixelFormat(HWND window, - bool anti_aliased, - int* pixel_format) { +// Helper routine that does one-off initialization like determining the +// pixel format and initializing glew. +bool GLES2DecoderImpl::InitializeOneOff(bool anti_aliased) { // We must initialize a GL context before we can determine the multi-sampling // supported on the current hardware, so we create an intermediate window // and context here. @@ -815,9 +840,9 @@ bool GetWindowsPixelFormat(HWND window, } HDC intermediate_dc = ::GetDC(intermediate_window); - int format_index = ::ChoosePixelFormat(intermediate_dc, - &kPixelFormatDescriptor); - if (format_index == 0) { + pixel_format_ = ::ChoosePixelFormat(intermediate_dc, + &kPixelFormatDescriptor); + if (pixel_format_ == 0) { DLOG(ERROR) << "Unable to get the pixel format for GL context."; ::ReleaseDC(intermediate_window, intermediate_dc); ::DestroyWindow(intermediate_window); @@ -825,7 +850,7 @@ bool GetWindowsPixelFormat(HWND window, module_handle); return false; } - if (!::SetPixelFormat(intermediate_dc, format_index, + if (!::SetPixelFormat(intermediate_dc, pixel_format_, &kPixelFormatDescriptor)) { DLOG(ERROR) << "Unable to set the pixel format for GL context."; ::ReleaseDC(intermediate_window, intermediate_dc); @@ -835,18 +860,14 @@ bool GetWindowsPixelFormat(HWND window, return false; } - // Store the pixel format without multisampling. - *pixel_format = format_index; + // Create a temporary GL context to query for multisampled pixel formats. HGLRC gl_context = ::wglCreateContext(intermediate_dc); if (::wglMakeCurrent(intermediate_dc, gl_context)) { // GL context was successfully created and applied to the window's DC. // Startup GLEW, the GL extensions wrangler. - GLenum glew_error = ::glewInit(); - if (glew_error == GLEW_OK) { + if (InitGlew()) { DLOG(INFO) << "Initialized GLEW " << ::glewGetString(GLEW_VERSION); } else { - DLOG(ERROR) << "Unable to initialise GLEW : " - << ::glewGetErrorString(glew_error); ::wglMakeCurrent(intermediate_dc, NULL); ::wglDeleteContext(gl_context); ::ReleaseDC(intermediate_window, intermediate_dc); @@ -887,7 +908,7 @@ bool GetWindowsPixelFormat(HWND window, 1, &msaa_pixel_format, &num_formats)) { - *pixel_format = msaa_pixel_format; + pixel_format_ = msaa_pixel_format; break; } } @@ -968,11 +989,11 @@ bool GLES2DecoderImpl::MakeCurrent() { #if defined(UNIT_TEST) return true; #elif defined(OS_WIN) - if (::wglGetCurrentDC() == device_context_ && + if (::wglGetCurrentDC() == gl_device_context_ && ::wglGetCurrentContext() == gl_context_) { return true; } - if (!::wglMakeCurrent(device_context_, gl_context_)) { + if (!::wglMakeCurrent(gl_device_context_, gl_context_)) { DLOG(ERROR) << "Unable to make gl context current."; return false; } @@ -1040,26 +1061,51 @@ void GLES2DecoderImpl::UnregisterObjects( bool GLES2DecoderImpl::InitPlatformSpecific() { #if defined(UNIT_TEST) #elif defined(OS_WIN) - device_context_ = ::GetDC(hwnd()); + // Do one-off initialization. + static bool success = InitializeOneOff(anti_aliased_); + if (!success) + return false; - int pixel_format; + if (hwnd()) { + // The GL context will render to this window. + gl_device_context_ = ::GetDC(hwnd()); - if (!GetWindowsPixelFormat(hwnd(), - anti_aliased_, - &pixel_format)) { - DLOG(ERROR) << "Unable to determine optimal pixel format for GL context."; + if (!::SetPixelFormat(gl_device_context_, + pixel_format_, + &kPixelFormatDescriptor)) { + DLOG(ERROR) << "Unable to set the pixel format for GL context."; + DestroyPlatformSpecific(); return false; - } + } + } else { + // Create a device context compatible with the primary display. + HDC display_device_context = ::CreateDC(L"DISPLAY", NULL, NULL, NULL); + + // Create a 1 x 1 pbuffer suitable for use with the device. + const int kNoAttributes[] = { 0 }; + pbuffer_ = ::wglCreatePbufferARB(display_device_context, + pixel_format_, + 1, 1, + kNoAttributes); + ::DeleteDC(display_device_context); + if (!pbuffer_) { + DLOG(ERROR) << "Unable to create pbuffer."; + DestroyPlatformSpecific(); + return false; + } - if (!::SetPixelFormat(device_context_, pixel_format, - &kPixelFormatDescriptor)) { - DLOG(ERROR) << "Unable to set the pixel format for GL context."; - return false; + gl_device_context_ = ::wglGetPbufferDCARB(pbuffer_); + if (!gl_device_context_) { + DLOG(ERROR) << "Unable to get pbuffer device context."; + DestroyPlatformSpecific(); + return false; + } } - gl_context_ = ::wglCreateContext(device_context_); + gl_context_ = ::wglCreateContext(gl_device_context_); if (!gl_context_) { DLOG(ERROR) << "Failed to create GL context."; + DestroyPlatformSpecific(); return false; } #elif defined(OS_LINUX) @@ -1072,20 +1118,20 @@ bool GLES2DecoderImpl::InitPlatformSpecific() { (CGLPixelFormatAttribute) kCGLPFAPBuffer, (CGLPixelFormatAttribute) 0 }; - CGLPixelFormatObj pixelFormat; - GLint numPixelFormats; + CGLPixelFormatObj pixel_format; + GLint num_pixel_formats; if (CGLChoosePixelFormat(attribs, - &pixelFormat, - &numPixelFormats) != kCGLNoError) { + &pixel_format, + &num_pixel_formats) != kCGLNoError) { DLOG(ERROR) << "Error choosing pixel format."; return false; } - if (!pixelFormat) { + if (!pixel_format) { return false; } CGLContextObj context; - CGLError res = CGLCreateContext(pixelFormat, 0, &context); - CGLDestroyPixelFormat(pixelFormat); + CGLError res = CGLCreateContext(pixel_format, 0, &context); + CGLDestroyPixelFormat(pixel_format); if (res != kCGLNoError) { DLOG(ERROR) << "Error creating context."; return false; @@ -1170,6 +1216,29 @@ bool GLES2DecoderImpl::InitGlew() { return true; } +void GLES2DecoderImpl::DestroyPlatformSpecific() { +#if defined(UNIT_TEST) +#elif defined(OS_WIN) + if (gl_context_) { + ::wglDeleteContext(gl_context_); + } + + if (gl_device_context_) { + if (hwnd()) + ::ReleaseDC(hwnd(), gl_device_context_); + else + ::wglReleasePbufferDCARB(pbuffer_, gl_device_context_); + + gl_device_context_ = NULL; + } + + if (pbuffer_) { + ::wglDestroyPbufferARB(pbuffer_); + pbuffer_ = NULL; + } +#endif +} + #if defined(OS_MACOSX) #if !defined(UNIT_TEST) static void AddBooleanValue(CFMutableDictionaryRef dictionary, @@ -1402,6 +1471,8 @@ void GLES2DecoderImpl::Destroy() { if (pbuffer_) CGLDestroyPBuffer(pbuffer_); #endif + + DestroyPlatformSpecific(); } const char* GLES2DecoderImpl::GetCommandName(unsigned int command_id) const { @@ -1652,7 +1723,7 @@ void GLES2DecoderImpl::DoLinkProgram(GLuint program) { void GLES2DecoderImpl::DoSwapBuffers() { #if defined(UNIT_TEST) #elif defined(OS_WIN) - ::SwapBuffers(device_context_); + ::SwapBuffers(gl_device_context_); #elif defined(OS_LINUX) DCHECK(window()); window()->SwapBuffers(); diff --git a/gpu/command_buffer/service/gpu_processor_win.cc b/gpu/command_buffer/service/gpu_processor_win.cc index bef34d8..bce783b 100644 --- a/gpu/command_buffer/service/gpu_processor_win.cc +++ b/gpu/command_buffer/service/gpu_processor_win.cc @@ -11,10 +11,8 @@ using ::base::SharedMemory; namespace gpu { bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle) { - DCHECK(handle); - // Cannot reinitialize. - if (decoder_->hwnd() != NULL) + if (parser_.get()) return false; // Map the ring buffer and create the parser. @@ -37,8 +35,8 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle) { } void GPUProcessor::Destroy() { - // Destroy GAPI if window handle has not already become invalid. - if (decoder_->hwnd()) { + // Destroy decoder if initialized. + if (parser_.get()) { decoder_->Destroy(); decoder_->set_hwnd(NULL); } diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp index 9fedfb3..81685c6 100644 --- a/gpu/gpu.gyp +++ b/gpu/gpu.gyp @@ -134,7 +134,7 @@ 'target_name': 'gles2_cmd_helper', 'type': 'static_library', 'dependencies': [ - 'command_buffer_common', + 'command_buffer_client', ], 'sources': [ 'command_buffer/client/gles2_cmd_helper.cc', diff --git a/ipc/ipc_channel_handle.h b/ipc/ipc_channel_handle.h index e3b2f3e..2342429 100644 --- a/ipc/ipc_channel_handle.h +++ b/ipc/ipc_channel_handle.h @@ -5,6 +5,8 @@ #ifndef IPC_IPC_CHANNEL_HANDLE_H_ #define IPC_IPC_CHANNEL_HANDLE_H_ +#include <string> + #include "build/build_config.h" #if defined(OS_POSIX) diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h index 9a8ccf4..670ce87 100644 --- a/ipc/ipc_message_utils.h +++ b/ipc/ipc_message_utils.h @@ -45,11 +45,12 @@ enum IPCMessageStart { WorkerMsgStart, WorkerHostMsgStart, NaClProcessMsgStart, - CommandBufferMsgStart, + GpuCommandBufferMsgStart, UtilityMsgStart, UtilityHostMsgStart, GpuMsgStart, GpuHostMsgStart, + GpuChannelMsgStart, // NOTE: When you add a new message class, also update // IPCStatusView::IPCStatusView to ensure logging works. LastMsgIndex |