diff options
author | kbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-04 17:46:23 +0000 |
---|---|---|
committer | kbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-04 17:46:23 +0000 |
commit | 77e74dbed3b57987515c260b651b72cec15825dc (patch) | |
tree | 66685b53d127093075f720f99fbb0869ab74c01d | |
parent | 1ad13a2d0dd8d03b50e6fbadd6a26ea72712d2d9 (diff) | |
download | chromium_src-77e74dbed3b57987515c260b651b72cec15825dc.zip chromium_src-77e74dbed3b57987515c260b651b72cec15825dc.tar.gz chromium_src-77e74dbed3b57987515c260b651b72cec15825dc.tar.bz2 |
Initial port of accelerated compositor to Mac OS X 10.6. Reused
infrastructure added for Pepper 3D and Core Animation plugins to
render the compositor's output. The implementation allocates a fake
"plugin window handle" on the browser side which is the "root" handle,
containing the compositor's output, and which, if present, is drawn
before any other accelerated plugin instances.
Added messages from GPU process to browser process for handling window
resizing and presentation of output. Added support to GGL for "view"
contexts on Mac OS X, used only for the accelerated compositor, and
requiring explicit resize notifications.
The remainder of this port will go into the WebKit repository under
https://bugs.webkit.org/show_bug.cgi?id=43398 after this for
dependency reasons.
Tested manually with CSS 3D and WebGL demos. Several stability and
correctness issues remain and will be addressed in following CLs;
however, the current code works for the majority of basic use cases
including switching between accelerated compositing on and off, and
scrolling of content.
BUG=38969
TEST=none
Review URL: http://codereview.chromium.org/3067026
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@54923 0039d316-1c4b-4281-b951-d872f2087c98
28 files changed, 403 insertions, 46 deletions
diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc index 2f774fd..19b0993 100644 --- a/chrome/browser/gpu_process_host.cc +++ b/chrome/browser/gpu_process_host.cc @@ -10,6 +10,8 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/gpu_process_host_ui_shim.h" +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/renderer_host/render_widget_host_view.h" #include "chrome/common/child_process_logging.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/gpu_messages.h" @@ -165,6 +167,11 @@ void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(GpuHostMsg_SynchronizeReply, OnSynchronizeReply) #if defined(OS_LINUX) IPC_MESSAGE_HANDLER(GpuHostMsg_GetViewXID, OnGetViewXID) +#elif defined(OS_MACOSX) + IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSetIOSurface, + OnAcceleratedSurfaceSetIOSurface) + IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, + OnAcceleratedSurfaceBuffersSwapped) #endif IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP() @@ -195,6 +202,36 @@ void GpuProcessHost::OnGetViewXID(gfx::NativeViewId id, unsigned long* xid) { *xid = 0; } } + +#elif defined(OS_MACOSX) +void GpuProcessHost::OnAcceleratedSurfaceSetIOSurface( + const GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params& params) { + RenderViewHost* host = RenderViewHost::FromID(params.renderer_id, + params.render_view_id); + if (!host) + return; + RenderWidgetHostView* view = host->view(); + if (!view) + return; + view->AcceleratedSurfaceSetIOSurface(params.window, + params.width, + params.height, + params.identifier); +} + +void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped( + int32 renderer_id, + int32 render_view_id, + gfx::PluginWindowHandle window) { + RenderViewHost* host = RenderViewHost::FromID(renderer_id, + render_view_id); + if (!host) + return; + RenderWidgetHostView* view = host->view(); + if (!view) + return; + view->AcceleratedSurfaceBuffersSwapped(window); +} #endif void GpuProcessHost::ReplyToRenderer( diff --git a/chrome/browser/gpu_process_host.h b/chrome/browser/gpu_process_host.h index c81b565..ddc10a4 100644 --- a/chrome/browser/gpu_process_host.h +++ b/chrome/browser/gpu_process_host.h @@ -16,6 +16,7 @@ #include "gfx/native_widget_types.h" class CommandBufferProxy; +struct GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params; namespace IPC { struct ChannelHandle; @@ -87,6 +88,12 @@ class GpuProcessHost : public BrowserChildProcessHost { void OnSynchronizeReply(); #if defined(OS_LINUX) void OnGetViewXID(gfx::NativeViewId id, unsigned long* xid); +#elif defined(OS_MACOSX) + void OnAcceleratedSurfaceSetIOSurface( + const GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params& params); + void OnAcceleratedSurfaceBuffersSwapped(int32 renderer_id, + int32 render_view_id, + gfx::PluginWindowHandle window); #endif void ReplyToRenderer(const IPC::ChannelHandle& channel, diff --git a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc index c8be132..96f09be 100644 --- a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc +++ b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc @@ -9,36 +9,59 @@ #include "webkit/glue/plugins/webplugin.h" AcceleratedSurfaceContainerManagerMac::AcceleratedSurfaceContainerManagerMac() - : current_id_(0) { + : current_id_(0), + root_container_(NULL) { } gfx::PluginWindowHandle AcceleratedSurfaceContainerManagerMac::AllocateFakePluginWindowHandle( - bool opaque) { + bool opaque, bool root) { AcceleratedSurfaceContainerMac* container = new AcceleratedSurfaceContainerMac(this, opaque); gfx::PluginWindowHandle res = static_cast<gfx::PluginWindowHandle>(++current_id_); plugin_window_to_container_map_.insert(std::make_pair(res, container)); + if (root) { + root_container_ = container; + } return res; } void AcceleratedSurfaceContainerManagerMac::DestroyFakePluginWindowHandle( gfx::PluginWindowHandle id) { AcceleratedSurfaceContainerMac* container = MapIDToContainer(id); - if (container) + if (container) { + if (container == root_container_) + root_container_ = NULL; delete container; + } plugin_window_to_container_map_.erase(id); } +bool AcceleratedSurfaceContainerManagerMac::HasRootContainer() { + return root_container_ != NULL; +} + void AcceleratedSurfaceContainerManagerMac::SetSizeAndIOSurface( gfx::PluginWindowHandle id, int32 width, int32 height, uint64 io_surface_identifier) { AcceleratedSurfaceContainerMac* container = MapIDToContainer(id); - if (container) + if (container) { container->SetSizeAndIOSurface(width, height, io_surface_identifier); + if (container == root_container_) { + // Fake up a WebPluginGeometry for the root window to set the + // container's size; we will never get a notification from the + // browser about the root window, only plugins. + webkit_glue::WebPluginGeometry geom; + gfx::Rect rect(0, 0, width, height); + geom.window_rect = rect; + geom.clip_rect = rect; + geom.visible = true; + container->MoveTo(geom); + } + } } void AcceleratedSurfaceContainerManagerMac::SetSizeAndTransportDIB( @@ -58,7 +81,8 @@ void AcceleratedSurfaceContainerManagerMac::MovePluginContainer( container->MoveTo(move); } -void AcceleratedSurfaceContainerManagerMac::Draw(CGLContextObj context) { +void AcceleratedSurfaceContainerManagerMac::Draw(CGLContextObj context, + bool draw_root_container) { // Clean up old texture objects. This is essentially a pre-emptive // cleanup, as the resources will be released when the OpenGL // context associated with the CAOpenGLLayer is destroyed. However, @@ -85,11 +109,18 @@ void AcceleratedSurfaceContainerManagerMac::Draw(CGLContextObj context) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + // Draw the root container, if any, first. + if (draw_root_container && root_container_) { + root_container_->Draw(context); + } + for (PluginWindowToContainerMap::const_iterator i = plugin_window_to_container_map_.begin(); i != plugin_window_to_container_map_.end(); ++i) { AcceleratedSurfaceContainerMac* container = i->second; - container->Draw(context); + if (container != root_container_) { + container->Draw(context); + } } // Unbind any texture from the texture target to ensure that the diff --git a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h index 8ccd3ca..7b49ccc 100644 --- a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h +++ b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h @@ -28,11 +28,17 @@ class AcceleratedSurfaceContainerManagerMac { // Allocates a new "fake" PluginWindowHandle, which is used as the // key for the other operations. - gfx::PluginWindowHandle AllocateFakePluginWindowHandle(bool opaque); + gfx::PluginWindowHandle AllocateFakePluginWindowHandle(bool opaque, + bool root); // Destroys a fake PluginWindowHandle and associated storage. void DestroyFakePluginWindowHandle(gfx::PluginWindowHandle id); + // Indicates whether a "root" PluginWindowHandle has been allocated, + // which means that we are using accelerated compositing and should + // short-circuit the normal drawing process. + bool HasRootContainer(); + // Sets the size and backing store of the plugin instance. There are two // versions: the IOSurface version is used on systems where the IOSurface // API is supported (Mac OS X 10.6 and later); the TransportDIB is used on @@ -52,7 +58,8 @@ class AcceleratedSurfaceContainerManagerMac { // Draws all of the managed plugin containers into the given OpenGL // context, which must already be current. - void Draw(CGLContextObj context); + void Draw(CGLContextObj context, + bool draw_root_container); // Causes the next Draw call on each container to trigger a texture upload. // Should be called any time the drawing context has changed. @@ -73,6 +80,17 @@ class AcceleratedSurfaceContainerManagerMac { PluginWindowToContainerMap; PluginWindowToContainerMap plugin_window_to_container_map_; + // The "root" container, which is only used to draw the output of + // the accelerated compositor if it is active. Currently, + // accelerated plugins (Core Animation and Pepper 3D) are drawn on + // top of the page's contents rather than transformed and composited + // with the rest of the page. At some point we would like them to be + // treated uniformly with other page elements; when this is done, + // the separate treatment of the root container can go away because + // there will only be one container active when the accelerated + // compositor is active. + AcceleratedSurfaceContainerMac* root_container_; + // A list of OpenGL textures waiting to be deleted std::vector<GLuint> textures_pending_deletion_; diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index 749d4c9..109e0f8 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -970,11 +970,12 @@ void RenderWidgetHost::OnMsgGetRootWindowRect(gfx::NativeViewId window_id, void RenderWidgetHost::OnAllocateFakePluginWindowHandle( bool opaque, + bool root, gfx::PluginWindowHandle* id) { // TODO(kbr): similar potential issue here as in OnMsgCreatePluginContainer. // Possibly less of an issue because this is only used for the GPU plugin. if (view_) { - *id = view_->AllocateFakePluginWindowHandle(opaque); + *id = view_->AllocateFakePluginWindowHandle(opaque, root); } else { NOTIMPLEMENTED(); } diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index 5296516..12a986d 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -501,6 +501,7 @@ class RenderWidgetHost : public IPC::Channel::Listener, void OnMsgGetWindowRect(gfx::NativeViewId window_id, gfx::Rect* results); void OnMsgGetRootWindowRect(gfx::NativeViewId window_id, gfx::Rect* results); void OnAllocateFakePluginWindowHandle(bool opaque, + bool root, gfx::PluginWindowHandle* id); void OnDestroyFakePluginWindowHandle(gfx::PluginWindowHandle id); void OnAcceleratedSurfaceSetIOSurface(gfx::PluginWindowHandle window, diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h index 4c7a16f..c4e4f00 100644 --- a/chrome/browser/renderer_host/render_widget_host_view.h +++ b/chrome/browser/renderer_host/render_widget_host_view.h @@ -197,7 +197,7 @@ class RenderWidgetHostView { // Methods associated with GPU-accelerated plug-in instances. virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle( - bool opaque) = 0; + bool opaque, bool root) = 0; virtual void DestroyFakePluginWindowHandle( gfx::PluginWindowHandle window) = 0; virtual void AcceleratedSurfaceSetIOSurface( diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h index af457b3..86396ff 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.h +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h @@ -62,7 +62,8 @@ class RWHVMEditCommandHelper; NSWindow* lastWindow_; // weak - // The Core Animation layer, if any, hosting the accelerated plugins' output. + // The Core Animation layer, if any, hosting the accelerated + // plugins' and accelerated compositor's output. scoped_nsobject<CALayer> acceleratedPluginLayer_; // Variables used by our implementaion of the NSTextInput protocol. @@ -227,8 +228,10 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { const webkit_glue::WebAccessibility& tree); virtual void OnAccessibilityFocusChange(int acc_obj_id); virtual void OnAccessibilityObjectStateChange(int acc_obj_id); - // Methods associated with GPU-accelerated plug-in instances. - virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle(bool opaque); + // Methods associated with GPU-accelerated plug-in instances and the + // accelerated compositor. + virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle(bool opaque, + bool root); virtual void DestroyFakePluginWindowHandle(gfx::PluginWindowHandle window); virtual void AcceleratedSurfaceSetIOSurface(gfx::PluginWindowHandle window, int32 width, diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm index 9512d64..647eba6 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -613,11 +613,12 @@ void RenderWidgetHostViewMac::KillSelf() { } gfx::PluginWindowHandle -RenderWidgetHostViewMac::AllocateFakePluginWindowHandle(bool opaque) { +RenderWidgetHostViewMac::AllocateFakePluginWindowHandle(bool opaque, + bool root) { // Make sure we have a layer for the plugin to draw into. [cocoa_view_ ensureAcceleratedPluginLayer]; - return plugin_container_manager_.AllocateFakePluginWindowHandle(opaque); + return plugin_container_manager_.AllocateFakePluginWindowHandle(opaque, root); } void RenderWidgetHostViewMac::DestroyFakePluginWindowHandle( @@ -650,6 +651,12 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceSetTransportDIB( void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped( gfx::PluginWindowHandle window) { [cocoa_view_ drawAcceleratedPluginLayer]; + if (GetRenderWidgetHost()->is_gpu_rendering_active()) { + // Additionally dirty the entire region of the view to make AppKit + // and Core Animation think that our CALayer needs to repaint + // itself. + [cocoa_view_ setNeedsDisplayInRect:[cocoa_view_ frame]]; + } } void RenderWidgetHostViewMac::DrawAcceleratedSurfaceInstances( @@ -664,7 +671,8 @@ void RenderWidgetHostViewMac::DrawAcceleratedSurfaceInstances( glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - plugin_container_manager_.Draw(context); + plugin_container_manager_.Draw( + context, GetRenderWidgetHost()->is_gpu_rendering_active()); } void RenderWidgetHostViewMac::AcceleratedSurfaceContextChanged() { @@ -1165,6 +1173,15 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) { return; } + if (renderWidgetHostView_->render_widget_host_->is_gpu_rendering_active()) { + // In this mode the accelerated plugin layer is considered to be + // opaque. We do not want its contents to be blended with anything + // underneath it. + acceleratedPluginLayer_.get().opaque = YES; + [acceleratedPluginLayer_.get() setNeedsDisplay]; + return; + } + DCHECK( renderWidgetHostView_->render_widget_host_->process()->HasConnection()); DCHECK(!renderWidgetHostView_->about_to_validate_and_paint_); @@ -1279,6 +1296,11 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) { renderWidgetHostView_->whiteout_start_time_ = base::TimeTicks::Now(); } + // If we get here then the accelerated plugin layer is not supposed + // to be considered opaque -- plugins overlay the browser's normal + // painting. + acceleratedPluginLayer_.get().opaque = NO; + // This helps keep accelerated plugins' output in better sync with the // window as it resizes. [acceleratedPluginLayer_.get() setNeedsDisplay]; diff --git a/chrome/browser/renderer_host/test/test_render_view_host.cc b/chrome/browser/renderer_host/test/test_render_view_host.cc index f5883ed..5409ecc 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.cc +++ b/chrome/browser/renderer_host/test/test_render_view_host.cc @@ -123,7 +123,9 @@ void TestRenderWidgetHostView::SetActive(bool active) { } gfx::PluginWindowHandle -TestRenderWidgetHostView::AllocateFakePluginWindowHandle(bool opaque) { +TestRenderWidgetHostView::AllocateFakePluginWindowHandle( + bool opaque, + bool root) { return NULL; } diff --git a/chrome/browser/renderer_host/test/test_render_view_host.h b/chrome/browser/renderer_host/test/test_render_view_host.h index b4971bd..53e10dd 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.h +++ b/chrome/browser/renderer_host/test/test_render_view_host.h @@ -94,7 +94,8 @@ class TestRenderWidgetHostView : public RenderWidgetHostView { virtual void SetWindowVisibility(bool visible) {} virtual void WindowFrameChanged() {} virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle( - bool opaque); + bool opaque, + bool root); virtual void DestroyFakePluginWindowHandle(gfx::PluginWindowHandle window); virtual void AcceleratedSurfaceSetIOSurface(gfx::PluginWindowHandle window, int32 width, diff --git a/chrome/common/gpu_messages.h b/chrome/common/gpu_messages.h index 508c599..1ff1741 100644 --- a/chrome/common/gpu_messages.h +++ b/chrome/common/gpu_messages.h @@ -18,7 +18,68 @@ #include "gfx/size.h" #include "gpu/command_buffer/common/command_buffer.h" +#if defined(OS_MACOSX) +// Parameters for the GpuHostMsg_AcceleratedSurfaceSetIOSurface +// message, which has too many parameters to be sent with the +// predefined IPC macros. +struct GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params { + int32 renderer_id; + int32 render_view_id; + gfx::PluginWindowHandle window; + int32 width; + int32 height; + uint64 identifier; + + GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params() + : renderer_id(0), + render_view_id(0), + window(NULL), + width(0), + height(0), + identifier(0) { + } +}; +#endif + namespace IPC { +#if defined(OS_MACOSX) +template <> +struct ParamTraits<GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params> { + typedef GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.renderer_id); + WriteParam(m, p.render_view_id); + WriteParam(m, p.window); + WriteParam(m, p.width); + WriteParam(m, p.height); + WriteParam(m, p.identifier); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->renderer_id) && + ReadParam(m, iter, &p->render_view_id) && + ReadParam(m, iter, &p->window) && + ReadParam(m, iter, &p->width) && + ReadParam(m, iter, &p->height) && + ReadParam(m, iter, &p->identifier); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.renderer_id, l); + l->append(L", "); + LogParam(p.render_view_id, l); + l->append(L", "); + LogParam(p.window, l); + l->append(L", "); + LogParam(p.width, l); + l->append(L", "); + LogParam(p.height, l); + l->append(L", "); + LogParam(p.identifier, l); + l->append(L")"); + } +}; +#endif + template <> struct ParamTraits<GPUInfo> { typedef GPUInfo param_type; diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h index fa9a83f..ac669aa 100644 --- a/chrome/common/gpu_messages_internal.h +++ b/chrome/common/gpu_messages_internal.h @@ -103,6 +103,22 @@ IPC_BEGIN_MESSAGES(GpuHost) IPC_SYNC_MESSAGE_CONTROL1_1(GpuHostMsg_GetViewXID, gfx::NativeViewId, /* view */ unsigned long /* xid */) +#elif defined(OS_MACOSX) + // This message, used on Mac OS X 10.6 and later (where IOSurface is + // supported), is sent from the GPU process to the browser to indicate that a + // new backing store was allocated for the given "window" (fake + // PluginWindowHandle). The renderer ID and render view ID are needed in + // order to uniquely identify the RenderWidgetHostView on the browser side. + IPC_MESSAGE_CONTROL1(GpuHostMsg_AcceleratedSurfaceSetIOSurface, + GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params) + + // This message notifies the browser process that the renderer + // swapped the buffers associated with the given "window", which + // should cause the browser to redraw the compositor's contents. + IPC_MESSAGE_CONTROL3(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, + int32, /* renderer_id */ + int32, /* render_view_id */ + gfx::PluginWindowHandle /* window */) #endif IPC_END_MESSAGES(GpuHost) @@ -113,9 +129,12 @@ IPC_END_MESSAGES(GpuHost) IPC_BEGIN_MESSAGES(GpuChannel) // Tells the GPU process to create a new command buffer that renders directly - // to a native view. A corresponding GpuCommandBufferStub is created. - IPC_SYNC_MESSAGE_CONTROL1_1(GpuChannelMsg_CreateViewCommandBuffer, + // to a native view. The |render_view_id| is currently needed only on Mac OS + // X in order to identify the window on the browser side into which the + // rendering results go. A corresponding GpuCommandBufferStub is created. + IPC_SYNC_MESSAGE_CONTROL2_1(GpuChannelMsg_CreateViewCommandBuffer, gfx::NativeViewId, /* view */ + int32, /* render_view_id */ int32 /* route_id */) // Tells the GPU process to create a new command buffer that renders to an @@ -171,7 +190,8 @@ IPC_BEGIN_MESSAGES(GpuCommandBuffer) int32 /* put_offset */) // Return the current state of the command buffer following a request via - // an AsyncGetState or AsyncFlush message. + // an AsyncGetState or AsyncFlush message. (This message is sent from the + // GPU process to the renderer process.) IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_UpdateState, gpu::CommandBuffer::State /* state */) @@ -208,6 +228,13 @@ IPC_BEGIN_MESSAGES(GpuCommandBuffer) // browser. This message is currently used only on 10.6 and later. IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_SetWindowSize, gfx::Size /* size */) + + // This message is sent from the GPU process to the renderer process (and + // from there the browser process) that the buffers associated with the + // given "window" were swapped, which should cause the browser to redraw + // the various accelerated surfaces. + IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_AcceleratedSurfaceBuffersSwapped, + gfx::PluginWindowHandle /* window */) #endif IPC_END_MESSAGES(GpuCommandBuffer) diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 55f9037..89afec0 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1994,9 +1994,13 @@ IPC_BEGIN_MESSAGES(ViewHost) // PluginWindowHandle on the browser side which is used to identify // the plugin to the browser later when backing store is allocated // or reallocated. |opaque| indicates whether the plugin's output is - // considered to be opaque, as opposed to translucent. - IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_AllocateFakePluginWindowHandle, + // considered to be opaque, as opposed to translucent. This message + // is reused for rendering the accelerated compositor's output. + // |root| indicates whether the output is supposed to cover the + // entire window. + IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_AllocateFakePluginWindowHandle, bool /* opaque */, + bool /* root */, gfx::PluginWindowHandle /* id */) // Destroys a fake window handle previously allocated using diff --git a/chrome/gpu/gpu_channel.cc b/chrome/gpu/gpu_channel.cc index ed0bfc3..36dbe3a 100644 --- a/chrome/gpu/gpu_channel.cc +++ b/chrome/gpu/gpu_channel.cc @@ -100,6 +100,7 @@ int GpuChannel::GenerateRouteID() { } void GpuChannel::OnCreateViewCommandBuffer(gfx::NativeViewId view_id, + int32 render_view_id, int32* route_id) { *route_id = 0; @@ -124,6 +125,13 @@ void GpuChannel::OnCreateViewCommandBuffer(gfx::NativeViewId view_id, // alternative would be to add a socket/plug pair like with plugins but that // has issues with events and focus. gpu_thread->Send(new GpuHostMsg_GetViewXID(view_id, &handle)); +#elif defined(OS_MACOSX) + // On Mac OS X we currently pass a (fake) PluginWindowHandle for the + // NativeViewId. We could allocate fake NativeViewIds on the browser + // side as well, and map between those and PluginWindowHandles, but + // this seems excessive. + handle = static_cast<gfx::PluginWindowHandle>( + static_cast<intptr_t>(view_id)); #else // TODO(apatrick): This needs to be something valid for mac and linux. // Offscreen rendering will work on these platforms but not rendering to the @@ -133,7 +141,8 @@ void GpuChannel::OnCreateViewCommandBuffer(gfx::NativeViewId view_id, *route_id = GenerateRouteID(); scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub( - this, handle, NULL, gfx::Size(), 0, *route_id)); + this, handle, NULL, gfx::Size(), 0, *route_id, + renderer_id_, render_view_id)); router_.AddRoute(*route_id, stub.get()); stubs_.AddWithID(stub.release(), *route_id); #endif // ENABLE_GPU @@ -155,7 +164,8 @@ void GpuChannel::OnCreateOffscreenCommandBuffer(int32 parent_route_id, parent_stub, size, parent_texture_id, - *route_id)); + *route_id, + 0, 0)); router_.AddRoute(*route_id, stub.get()); stubs_.AddWithID(stub.release(), *route_id); #else diff --git a/chrome/gpu/gpu_channel.h b/chrome/gpu/gpu_channel.h index e5522da..da6601f 100644 --- a/chrome/gpu/gpu_channel.h +++ b/chrome/gpu/gpu_channel.h @@ -64,6 +64,7 @@ class GpuChannel : public IPC::Channel::Listener, // Message handlers. void OnCreateViewCommandBuffer(gfx::NativeViewId view, + int32 render_view_id, int32* route_id); void OnCreateOffscreenCommandBuffer(int32 parent_route_id, const gfx::Size& size, diff --git a/chrome/gpu/gpu_command_buffer_stub.cc b/chrome/gpu/gpu_command_buffer_stub.cc index 1c372b8..3ed834f 100644 --- a/chrome/gpu/gpu_command_buffer_stub.cc +++ b/chrome/gpu/gpu_command_buffer_stub.cc @@ -7,6 +7,7 @@ #include "base/process_util.h" #include "base/shared_memory.h" #include "build/build_config.h" +#include "chrome/common/child_thread.h" #include "chrome/common/gpu_messages.h" #include "chrome/gpu/gpu_channel.h" #include "chrome/gpu/gpu_command_buffer_stub.h" @@ -18,14 +19,18 @@ GpuCommandBufferStub::GpuCommandBufferStub(GpuChannel* channel, GpuCommandBufferStub* parent, const gfx::Size& size, uint32 parent_texture_id, - int32 route_id) + int32 route_id, + int32 renderer_id, + int32 render_view_id) : channel_(channel), handle_(handle), parent_( parent ? parent->AsWeakPtr() : base::WeakPtr<GpuCommandBufferStub>()), initial_size_(size), parent_texture_id_(parent_texture_id), - route_id_(route_id) { + route_id_(route_id), + renderer_id_(renderer_id), + render_view_id_(render_view_id) { } GpuCommandBufferStub::~GpuCommandBufferStub() { @@ -49,6 +54,9 @@ void GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) { OnGetTransferBuffer); IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_ResizeOffscreenFrameBuffer, OnResizeOffscreenFrameBuffer); +#if defined(OS_MACOSX) + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SetWindowSize, OnSetWindowSize); +#endif IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP() } @@ -86,6 +94,17 @@ void GpuCommandBufferStub::OnInitialize( // calling process. buffer.shared_memory->ShareToProcess(channel_->renderer_handle(), ring_buffer); +#if defined(OS_MACOSX) + if (handle_) { + // This context conceptually puts its output directly on the + // screen, rendered by the accelerated plugin layer in + // RenderWidgetHostViewMac. Set up a pathway to notify the + // browser process when its contents change. + processor_->SetSwapBuffersCallback( + NewCallback(this, + &GpuCommandBufferStub::SwapBuffersCallback)); + } +#endif } else { processor_.reset(); command_buffer_.reset(); @@ -142,4 +161,35 @@ void GpuCommandBufferStub::OnResizeOffscreenFrameBuffer(const gfx::Size& size) { processor_->ResizeOffscreenFrameBuffer(size); } +#if defined(OS_MACOSX) +void GpuCommandBufferStub::OnSetWindowSize(const gfx::Size& size) { + ChildThread* gpu_thread = ChildThread::current(); + // Try using the IOSurface version first. + uint64 new_backing_store = processor_->SetWindowSizeForIOSurface(size); + if (new_backing_store) { + GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params params; + params.renderer_id = renderer_id_; + params.render_view_id = render_view_id_; + params.window = handle_; + params.width = size.width(); + params.height = size.height(); + params.identifier = new_backing_store; + gpu_thread->Send(new GpuHostMsg_AcceleratedSurfaceSetIOSurface(params)); + } else { + // TODO(kbr): figure out what to do here. It wouldn't be difficult + // to support the compositor on 10.5, but the performance would be + // questionable. + NOTREACHED(); + } +} + +void GpuCommandBufferStub::SwapBuffersCallback() { + ChildThread* gpu_thread = ChildThread::current(); + gpu_thread->Send( + new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(renderer_id_, + render_view_id_, + handle_)); +} +#endif // defined(OS_MACOSX) + #endif // ENABLE_GPU diff --git a/chrome/gpu/gpu_command_buffer_stub.h b/chrome/gpu/gpu_command_buffer_stub.h index 3abf0fb..621c8de 100644 --- a/chrome/gpu/gpu_command_buffer_stub.h +++ b/chrome/gpu/gpu_command_buffer_stub.h @@ -29,7 +29,9 @@ class GpuCommandBufferStub GpuCommandBufferStub* parent, const gfx::Size& size, uint32 parent_texture_id, - int32 route_id); + int32 route_id, + int32 renderer_id, + int32 render_view_id); virtual ~GpuCommandBufferStub(); @@ -55,6 +57,11 @@ class GpuCommandBufferStub uint32* size); void OnResizeOffscreenFrameBuffer(const gfx::Size& size); +#if defined(OS_MACOSX) + void OnSetWindowSize(const gfx::Size& size); + void SwapBuffersCallback(); +#endif + // The lifetime of objects of this class is managed by a GpuChannel. The // GpuChannels destroy all the GpuCommandBufferStubs that they own when they // are destroyed. So a raw pointer is safe. @@ -66,6 +73,11 @@ class GpuCommandBufferStub uint32 parent_texture_id_; int32 route_id_; + // The following two fields are used on Mac OS X to identify the window + // for the rendering results on the browser side. + int32 renderer_id_; + int32 render_view_id_; + scoped_ptr<gpu::CommandBufferService> command_buffer_; scoped_ptr<gpu::GPUProcessor> processor_; diff --git a/chrome/renderer/ggl/ggl.cc b/chrome/renderer/ggl/ggl.cc index db7eb1b..011b5f5 100644 --- a/chrome/renderer/ggl/ggl.cc +++ b/chrome/renderer/ggl/ggl.cc @@ -59,7 +59,14 @@ class Context : public base::SupportsWeakPtr<Context> { // Initialize a GGL context that can be used in association with a a GPU // channel acquired from a RenderWidget or RenderView. - bool Initialize(gfx::NativeViewId view, const gfx::Size& size); + bool Initialize(gfx::NativeViewId view, + int render_view_id, + const gfx::Size& size); + +#if defined(OS_MACOSX) + // Asynchronously resizes an onscreen frame buffer. + void ResizeOnscreen(const gfx::Size& size); +#endif // Asynchronously resizes an offscreen frame buffer. void ResizeOffscreen(const gfx::Size& size); @@ -114,7 +121,9 @@ Context::~Context() { Destroy(); } -bool Context::Initialize(gfx::NativeViewId view, const gfx::Size& size) { +bool Context::Initialize(gfx::NativeViewId view, + int render_view_id, + const gfx::Size& size) { DCHECK(size.width() >= 0 && size.height() >= 0); if (channel_->state() != GpuChannelHost::CONNECTED) @@ -134,7 +143,8 @@ bool Context::Initialize(gfx::NativeViewId view, const gfx::Size& size) { // Create a proxy to a command buffer in the GPU process. if (view) { - command_buffer_ = channel_->CreateViewCommandBuffer(view); + command_buffer_ = + channel_->CreateViewCommandBuffer(view, render_view_id); } else { CommandBufferProxy* parent_command_buffer = parent_.get() ? parent_->command_buffer_ : NULL; @@ -189,6 +199,13 @@ bool Context::Initialize(gfx::NativeViewId view, const gfx::Size& size) { return true; } +#if defined(OS_MACOSX) +void Context::ResizeOnscreen(const gfx::Size& size) { + DCHECK(size.width() > 0 && size.height() > 0); + command_buffer_->SetWindowSize(size); +} +#endif + void Context::ResizeOffscreen(const gfx::Size& size) { DCHECK(size.width() > 0 && size.height() > 0); command_buffer_->ResizeOffscreenFrameBuffer(size); @@ -264,10 +281,12 @@ void Context::DisableShaderTranslation() { #endif // ENABLE_GPU -Context* CreateViewContext(GpuChannelHost* channel, gfx::NativeViewId view) { +Context* CreateViewContext(GpuChannelHost* channel, + gfx::NativeViewId view, + int render_view_id) { #if defined(ENABLE_GPU) scoped_ptr<Context> context(new Context(channel, NULL)); - if (!context->Initialize(view, gfx::Size())) + if (!context->Initialize(view, render_view_id, gfx::Size())) return NULL; return context.release(); @@ -276,12 +295,20 @@ Context* CreateViewContext(GpuChannelHost* channel, gfx::NativeViewId view) { #endif } +#if defined(OS_MACOSX) +void ResizeOnscreenContext(Context* context, const gfx::Size& size) { +#if defined(ENABLE_GPU) + context->ResizeOnscreen(size); +#endif +} +#endif + Context* CreateOffscreenContext(GpuChannelHost* channel, Context* parent, const gfx::Size& size) { #if defined(ENABLE_GPU) scoped_ptr<Context> context(new Context(channel, parent)); - if (!context->Initialize(0, size)) + if (!context->Initialize(0, 0, size)) return NULL; return context.release(); diff --git a/chrome/renderer/ggl/ggl.h b/chrome/renderer/ggl/ggl.h index bf2d87d..ce34c7f 100644 --- a/chrome/renderer/ggl/ggl.h +++ b/chrome/renderer/ggl/ggl.h @@ -37,7 +37,29 @@ bool Initialize(); bool Terminate(); // Create a GGL context that renders directly to a view. -Context* CreateViewContext(GpuChannelHost* channel, gfx::NativeViewId view); +// +// NOTE: on Mac OS X, this entry point is only used to set up the +// accelerated compositor's output. On this platform, we actually pass +// a gfx::PluginWindowHandle in place of the gfx::NativeViewId, +// because the facility to allocate a fake PluginWindowHandle is +// already in place. We could add more entry points and messages to +// allocate both fake PluginWindowHandles and NativeViewIds and map +// from fake NativeViewIds to PluginWindowHandles, but this seems like +// unnecessary complexity at the moment. +// +// The render_view_id is currently also only used on Mac OS X. +// TODO(kbr): clean up the arguments to this function and make them +// more cross-platform. +Context* CreateViewContext(GpuChannelHost* channel, + gfx::NativeViewId view, + int render_view_id); + +#if defined(OS_MACOSX) +// On Mac OS X only, view contexts actually behave like offscreen contexts, and +// require an explicit resize operation which is slightly different from that +// of offscreen contexts. +void ResizeOnscreenContext(Context* context, const gfx::Size& size); +#endif // Create a GGL context that renders to an offscreen frame buffer. If parent is // not NULL, that context can access a copy of the created diff --git a/chrome/renderer/gpu_channel_host.cc b/chrome/renderer/gpu_channel_host.cc index 1f2eb21..70a5224 100644 --- a/chrome/renderer/gpu_channel_host.cc +++ b/chrome/renderer/gpu_channel_host.cc @@ -68,14 +68,16 @@ bool GpuChannelHost::Send(IPC::Message* message) { } CommandBufferProxy* GpuChannelHost::CreateViewCommandBuffer( - gfx::NativeViewId view) { + gfx::NativeViewId view, int render_view_id) { #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_CreateViewCommandBuffer(view, &route_id)) && + if (!Send(new GpuChannelMsg_CreateViewCommandBuffer(view, + render_view_id, + &route_id)) && route_id != MSG_ROUTING_NONE) { return NULL; } diff --git a/chrome/renderer/gpu_channel_host.h b/chrome/renderer/gpu_channel_host.h index 854aea5..6c33acb 100644 --- a/chrome/renderer/gpu_channel_host.h +++ b/chrome/renderer/gpu_channel_host.h @@ -53,7 +53,8 @@ class GpuChannelHost : public IPC::Channel::Listener, virtual bool Send(IPC::Message* msg); // Create and connect to a command buffer in the GPU process. - CommandBufferProxy* CreateViewCommandBuffer(gfx::NativeViewId view); + CommandBufferProxy* CreateViewCommandBuffer(gfx::NativeViewId view, + int render_view_id); // Create and connect to a command buffer in the GPU process. CommandBufferProxy* CreateOffscreenCommandBuffer(CommandBufferProxy* parent, diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index a7787a5..39c4193 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -5169,10 +5169,10 @@ void RenderView::EnsureDocumentTag() { #if defined(OS_MACOSX) gfx::PluginWindowHandle RenderView::AllocateFakePluginWindowHandle( - bool opaque) { + bool opaque, bool root) { gfx::PluginWindowHandle window = NULL; Send(new ViewHostMsg_AllocateFakePluginWindowHandle( - routing_id(), opaque, &window)); + routing_id(), opaque, root, &window)); return window; } diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 82a293a..3d3cdbd 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -287,7 +287,8 @@ class RenderView : public RenderWidget, #if defined(OS_MACOSX) // Helper routines for GPU plugin support. Used by the // WebPluginDelegateProxy, which has a pointer to the RenderView. - gfx::PluginWindowHandle AllocateFakePluginWindowHandle(bool opaque); + gfx::PluginWindowHandle AllocateFakePluginWindowHandle(bool opaque, + bool root); void DestroyFakePluginWindowHandle(gfx::PluginWindowHandle window); void AcceleratedSurfaceSetIOSurface(gfx::PluginWindowHandle window, int32 width, diff --git a/chrome/renderer/webgles2context_impl.cc b/chrome/renderer/webgles2context_impl.cc index a14e0e3..d0e35d7 100644 --- a/chrome/renderer/webgles2context_impl.cc +++ b/chrome/renderer/webgles2context_impl.cc @@ -45,8 +45,16 @@ bool WebGLES2ContextImpl::initialize( RenderView* renderview = RenderView::FromWebView(web_view); if (!renderview) return false; - gfx::NativeViewId view_id = renderview->host_window(); - context_ = ggl::CreateViewContext(host, view_id); + gfx::NativeViewId view_id; +#if !defined(OS_MACOSX) + view_id = renderview->host_window(); +#else + view_id = static_cast<gfx::NativeViewId>( + renderview->AllocateFakePluginWindowHandle(true, true)); +#endif + context_ = ggl::CreateViewContext( + host, view_id, + renderview->routing_id()); } else { ggl::Context* parent_context = NULL; @@ -83,5 +91,11 @@ unsigned WebGLES2ContextImpl::getOffscreenContentParentTextureId() { return ggl::GetParentTextureId(context_); } +#if defined(OS_MACOSX) +void WebGLES2ContextImpl::resizeOnscreenContent(const WebKit::WebSize& size) { + ggl::ResizeOnscreenContext(context_, size); +} +#endif + #endif // defined(ENABLE_GPU) diff --git a/chrome/renderer/webgles2context_impl.h b/chrome/renderer/webgles2context_impl.h index 3183634..e8c267e 100644 --- a/chrome/renderer/webgles2context_impl.h +++ b/chrome/renderer/webgles2context_impl.h @@ -27,6 +27,10 @@ class WebGLES2ContextImpl : public WebKit::WebGLES2Context { virtual void resizeOffscreenContent(const WebKit::WebSize&); virtual unsigned getOffscreenContentParentTextureId(); +#if defined(OS_MACOSX) + virtual void resizeOnscreenContent(const WebKit::WebSize&); +#endif + ggl::Context* context() { return context_; } private: diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index fb35163..1be5f5d 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -1399,7 +1399,7 @@ void WebPluginDelegateProxy::OnBindFakePluginWindowHandle(bool opaque) { bool WebPluginDelegateProxy::BindFakePluginWindowHandle(bool opaque) { gfx::PluginWindowHandle fake_window = NULL; if (render_view_) - fake_window = render_view_->AllocateFakePluginWindowHandle(opaque); + fake_window = render_view_->AllocateFakePluginWindowHandle(opaque, false); // If we aren't running on 10.6, this allocation will fail. if (!fake_window) return false; diff --git a/gpu/command_buffer/service/gpu_processor_mac.cc b/gpu/command_buffer/service/gpu_processor_mac.cc index 61a45da..7862d76 100644 --- a/gpu/command_buffer/service/gpu_processor_mac.cc +++ b/gpu/command_buffer/service/gpu_processor_mac.cc @@ -51,8 +51,6 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle window, size, parent_decoder, parent_texture_id); - - return true; } void GPUProcessor::Destroy() { |