diff options
author | kbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-26 20:16:18 +0000 |
---|---|---|
committer | kbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-26 20:16:18 +0000 |
commit | 33da8041706bbe87ec9ff8d95854bf7075ab2d7a (patch) | |
tree | 518fd9b01ac6355816acd64bfb7f9ce037274598 /chrome | |
parent | 76d20290e1a84f5a18c63c0f905062b986f01f55 (diff) | |
download | chromium_src-33da8041706bbe87ec9ff8d95854bf7075ab2d7a.zip chromium_src-33da8041706bbe87ec9ff8d95854bf7075ab2d7a.tar.gz chromium_src-33da8041706bbe87ec9ff8d95854bf7075ab2d7a.tar.bz2 |
Add flow control between renderer and GPU processes, and, on Mac OS X,
between GPU process and browser process. Thanks to Al Patrick for the
renderer<->GPU flow control mechanism.
This CL prevents the renderer from issuing more OpenGL work than the
GPU process can execute, and, on the Mac, prevents the combination of
the renderer and GPU processes from transmitting more frames via
IOSurfaces from the GPU to the browser process than can be handled by
the GPU.
This fix causes the renderer to block inside ggl::SwapBuffers() when
it gets too far ahead. Different strategies can be considered going
forward, including measuring frame rates in the GPU and renderer
processes and trying to match them via techniques such as delaying the
execution of some timers. However, despite the general undesirability
of blocking the render thread, this fix results in a significant
performance improvement.
With this fix integrated, a fill-limited test case from Chris Rogers
displays at 60 FPS instead of 15 FPS on a Mac Pro. Gregg Tavares'
aquarium from webglsamples.googlecode.com displays at 30 FPS instead
of 4 or 5 FPS on a MacBook Pro. The frame rates measured at the
JavaScript level now match the actual frame rate of the browser, where
previously they were much higher since they were issuing more work
than the browser could render.
A few other minor OpenGL bugs potentially impacting the correctness of
the Mac compositor are being fixed as well in this CL.
Verified that WebGL, CSS 3D and YouTube (Core Animation plugin)
content all work.
BUG=63539
TEST=none
Review URL: http://codereview.chromium.org/5317007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@67470 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
19 files changed, 335 insertions, 44 deletions
diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc index bf9c1c9..afa904c 100644 --- a/chrome/browser/gpu_process_host.cc +++ b/chrome/browser/gpu_process_host.cc @@ -308,11 +308,15 @@ class BuffersSwappedDispatcher : public Task { int32 renderer_id, int32 render_view_id, gfx::PluginWindowHandle window, - uint64 surface_id) + uint64 surface_id, + int32 route_id, + uint64 swap_buffers_count) : renderer_id_(renderer_id), render_view_id_(render_view_id), window_(window), - surface_id_(surface_id) { + surface_id_(surface_id), + route_id_(route_id), + swap_buffers_count_(swap_buffers_count) { } void Run() { @@ -323,7 +327,14 @@ class BuffersSwappedDispatcher : public Task { RenderWidgetHostView* view = host->view(); if (!view) return; - view->AcceleratedSurfaceBuffersSwapped(window_, surface_id_); + view->AcceleratedSurfaceBuffersSwapped( + // Parameters needed to swap the IOSurface. + window_, + surface_id_, + // Parameters needed to formulate an acknowledgment. + renderer_id_, + route_id_, + swap_buffers_count_); } private: @@ -331,6 +342,8 @@ class BuffersSwappedDispatcher : public Task { int32 render_view_id_; gfx::PluginWindowHandle window_; uint64 surface_id_; + int32 route_id_; + uint64 swap_buffers_count_; DISALLOW_COPY_AND_ASSIGN(BuffersSwappedDispatcher); }; @@ -338,14 +351,20 @@ class BuffersSwappedDispatcher : public Task { } // namespace void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped( - int32 renderer_id, - int32 render_view_id, - gfx::PluginWindowHandle window, - uint64 surface_id) { + const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, new BuffersSwappedDispatcher( - renderer_id, render_view_id, window, surface_id)); + // These are the parameters needed to look up the IOSurface + // on this side. + params.renderer_id, + params.render_view_id, + params.window, + params.surface_id, + // These are additional parameters needed to formulate an + // acknowledgment. + params.route_id, + params.swap_buffers_count)); } #endif diff --git a/chrome/browser/gpu_process_host.h b/chrome/browser/gpu_process_host.h index 69969c6..4b40a25 100644 --- a/chrome/browser/gpu_process_host.h +++ b/chrome/browser/gpu_process_host.h @@ -15,6 +15,7 @@ #include "gfx/native_widget_types.h" struct GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params; +struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params; class GPUInfo; class ResourceMessageFilter; @@ -90,10 +91,8 @@ class GpuProcessHost : public BrowserChildProcessHost, public NonThreadSafe { #elif defined(OS_MACOSX) void OnAcceleratedSurfaceSetIOSurface( const GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params& params); - void OnAcceleratedSurfaceBuffersSwapped(int32 renderer_id, - int32 render_view_id, - gfx::PluginWindowHandle window, - uint64 surface_id); + void OnAcceleratedSurfaceBuffersSwapped( + const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params); #endif // Sends the response for establish channel request to the renderer. 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 6b76b03..1ad09ba 100644 --- a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc +++ b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc @@ -100,7 +100,7 @@ void AcceleratedSurfaceContainerManagerMac::Draw(CGLContextObj context, glColorMask(true, true, true, true); // Should match the clear color of RenderWidgetHostViewMac. - glClearColor(255, 255, 255, 255); + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // TODO(thakis): Clearing the whole color buffer is wasteful, since most of // it is overwritten by the surface. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index 2617cbd..4482bbd 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -1062,7 +1062,11 @@ void RenderWidgetHost::OnAcceleratedSurfaceSetTransportDIB( void RenderWidgetHost::OnAcceleratedSurfaceBuffersSwapped( gfx::PluginWindowHandle window, uint64 surface_id) { if (view_) { - view_->AcceleratedSurfaceBuffersSwapped(window, surface_id); + // This code path could be updated to implement flow control for + // updating of accelerated plugins as well. However, if we add support + // for composited plugins then this is not necessary. + view_->AcceleratedSurfaceBuffersSwapped(window, surface_id, + 0, 0, 0); } } #elif defined(OS_POSIX) diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h index 2c99926..4ad2c41 100644 --- a/chrome/browser/renderer_host/render_widget_host_view.h +++ b/chrome/browser/renderer_host/render_widget_host_view.h @@ -225,8 +225,18 @@ class RenderWidgetHostView { int32 width, int32 height, TransportDIB::Handle transport_dib) = 0; + // |window| and |surface_id| indicate which accelerated surface's + // buffers swapped. |renderer_id|, |route_id| and + // |swap_buffers_count| are used to formulate a reply to the GPU + // process to prevent it from getting too far ahead. They may all be + // zero, in which case no flow control is enforced; this case is + // currently used for accelerated plugins. virtual void AcceleratedSurfaceBuffersSwapped( - gfx::PluginWindowHandle window, uint64 surface_id) = 0; + gfx::PluginWindowHandle window, + uint64 surface_id, + int renderer_id, + int32 route_id, + uint64 swap_buffers_count) = 0; virtual void GpuRenderingStateDidChange() = 0; #endif 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 154c0c5..e539f14 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.h +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h @@ -243,8 +243,12 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { int32 width, int32 height, TransportDIB::Handle transport_dib); - virtual void AcceleratedSurfaceBuffersSwapped(gfx::PluginWindowHandle window, - uint64 surface_id); + virtual void AcceleratedSurfaceBuffersSwapped( + gfx::PluginWindowHandle window, + uint64 surface_id, + int32 renderer_id, + int32 route_id, + uint64 swap_buffers_count); virtual void GpuRenderingStateDidChange(); void DrawAcceleratedSurfaceInstance( CGLContextObj context, @@ -273,6 +277,12 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { // should be called after the software backing store has been painted to. void HandleDelayedGpuViewHiding(); + // This is called from the display link thread, and provides the GPU + // process a notion of how quickly the browser is able to keep up with it. + void AcknowledgeSwapBuffers(int renderer_id, + int32 route_id, + uint64 swap_buffers_count); + // These member variables should be private, but the associated ObjC class // needs access to them and can't be made a friend. 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 bb4b57b..307eb2e 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -24,6 +24,7 @@ #include "chrome/browser/browser_trial.h" #import "chrome/browser/cocoa/rwhvm_editcommand_helper.h" #import "chrome/browser/cocoa/view_id_util.h" +#include "chrome/browser/gpu_process_host.h" #include "chrome/browser/plugin_process_host.h" #include "chrome/browser/renderer_host/backing_store_mac.h" #include "chrome/browser/renderer_host/render_process_host.h" @@ -33,6 +34,7 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/native_web_keyboard_event.h" #include "chrome/common/edit_command.h" +#include "chrome/common/gpu_messages.h" #include "chrome/common/plugin_messages.h" #include "chrome/common/render_messages.h" #include "skia/ext/platform_canvas.h" @@ -170,8 +172,21 @@ void DisablePasswordInput() { RenderWidgetHostViewMac* renderWidgetHostView_; // weak gfx::PluginWindowHandle pluginHandle_; // weak - // True if the backing IO surface was updated since we last painted. - BOOL surfaceWasSwapped_; + // The number of swap buffers calls that have been requested by the + // GPU process, or a monotonically increasing number of calls to + // updateSwapBuffersCount:fromRenderer:routeId: if the update came + // from an accelerated plugin. + uint64 swapBuffersCount_; + // The number of swap buffers calls that have been processed by the + // display link thread. This is only used with the GPU process + // update path. + volatile uint64 acknowledgedSwapBuffersCount_; + + // Auxiliary information needed to formulate an acknowledgment to + // the GPU process. These are constant after the first message. + // These are both zero for updates coming from a plugin process. + volatile int rendererId_; + volatile int32 routeId_; // Cocoa methods can only be called on the main thread, so have a copy of the // view's size, since it's required on the displaylink thread. @@ -186,6 +201,15 @@ void DisablePasswordInput() { pluginHandle:(gfx::PluginWindowHandle)pluginHandle; - (void)drawView; +// Updates the number of swap buffers calls that have been requested. +// This is currently called with non-zero values only in response to +// updates from the GPU process. For accelerated plugins, all zeros +// are passed, and the view takes this as a hint that no flow control +// or acknowledgment of the swap buffers are desired. +- (void)updateSwapBuffersCount:(uint64)count + fromRenderer:(int)rendererId + routeId:(int32)routeId; + // NSViews autorelease subviews when they die. The RWHVMac gets destroyed when // RHWVCocoa gets dealloc'd, which means the AcceleratedPluginView child views // can be around a little longer than the RWHVMac. This is called when the @@ -193,14 +217,10 @@ void DisablePasswordInput() { - (void)onRenderWidgetHostViewGone; // This _must_ be atomic, since it's accessed from several threads. -@property BOOL surfaceWasSwapped; - -// This _must_ be atomic, since it's accessed from several threads. @property NSSize cachedSize; @end @implementation AcceleratedPluginView -@synthesize surfaceWasSwapped = surfaceWasSwapped_; @synthesize cachedSize = cachedSize_; - (CVReturn)getFrameForTime:(const CVTimeStamp*)outputTime { @@ -208,11 +228,22 @@ void DisablePasswordInput() { // called from a background thread. base::mac::ScopedNSAutoreleasePool pool; - if (![self surfaceWasSwapped]) + bool sendAck = (rendererId_ != 0 || routeId_ != 0); + uint64 currentSwapBuffersCount = swapBuffersCount_; + if (currentSwapBuffersCount == acknowledgedSwapBuffersCount_) { return kCVReturnSuccess; + } [self drawView]; - [self setSurfaceWasSwapped:NO]; + + acknowledgedSwapBuffersCount_ = currentSwapBuffersCount; + if (sendAck && renderWidgetHostView_) { + renderWidgetHostView_->AcknowledgeSwapBuffers( + rendererId_, + routeId_, + acknowledgedSwapBuffersCount_); + } + return kCVReturnSuccess; } @@ -235,6 +266,10 @@ static CVReturn DrawOneAcceleratedPluginCallback( renderWidgetHostView_ = r; pluginHandle_ = pluginHandle; cachedSize_ = NSZeroSize; + swapBuffersCount_ = 0; + acknowledgedSwapBuffersCount_ = 0; + rendererId_ = 0; + routeId_ = 0; [self setAutoresizingMask:NSViewMaxXMargin|NSViewMinYMargin]; @@ -290,9 +325,25 @@ static CVReturn DrawOneAcceleratedPluginCallback( } CGLFlushDrawable(cglContext_); + CGLSetCurrentContext(0); CGLUnlockContext(cglContext_); } +- (void)updateSwapBuffersCount:(uint64)count + fromRenderer:(int)rendererId + routeId:(int32)routeId { + if (rendererId == 0 && routeId == 0) { + // This notification is coming from a plugin process, for which we + // don't have flow control implemented right now. Fake up a swap + // buffers count so that we can at least skip useless renders. + ++swapBuffersCount_; + } else { + rendererId_ = rendererId; + routeId_ = routeId; + swapBuffersCount_ = count; + } +} + - (void)onRenderWidgetHostViewGone { if (!renderWidgetHostView_) return; @@ -340,6 +391,7 @@ static CVReturn DrawOneAcceleratedPluginCallback( NSSize size = [self frame].size; glViewport(0, 0, size.width, size.height); + CGLSetCurrentContext(0); CGLUnlockContext(cglContext_); globalFrameDidChangeCGLLockCount_--; @@ -938,7 +990,11 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceSetTransportDIB( } void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped( - gfx::PluginWindowHandle window, uint64 surface_id) { + gfx::PluginWindowHandle window, + uint64 surface_id, + int renderer_id, + int32 route_id, + uint64 swap_buffers_count) { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); PluginViewMap::iterator it = plugin_views_.find(window); DCHECK(plugin_views_.end() != it); @@ -953,7 +1009,9 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped( // The surface is hidden until its first paint, to not show gargabe. if (plugin_container_manager_.SurfaceShouldBeVisible(window)) [view setHidden:NO]; - [view setSurfaceWasSwapped:YES]; + [view updateSwapBuffersCount:swap_buffers_count + fromRenderer:renderer_id + routeId:route_id]; } void RenderWidgetHostViewMac::UpdateRootGpuViewVisibility( @@ -988,6 +1046,43 @@ void RenderWidgetHostViewMac::HandleDelayedGpuViewHiding() { } } +namespace { +class BuffersSwappedAcknowledger : public Task { + public: + BuffersSwappedAcknowledger( + int renderer_id, + int32 route_id, + uint64 swap_buffers_count) + : renderer_id_(renderer_id), + route_id_(route_id), + swap_buffers_count_(swap_buffers_count) { + } + + void Run() { + GpuProcessHost::Get()->Send( + new GpuMsg_AcceleratedSurfaceBuffersSwappedACK( + renderer_id_, route_id_, swap_buffers_count_)); + } + + private: + int renderer_id_; + int32 route_id_; + uint64 swap_buffers_count_; + + DISALLOW_COPY_AND_ASSIGN(BuffersSwappedAcknowledger); +}; +} // anonymous namespace + +void RenderWidgetHostViewMac::AcknowledgeSwapBuffers( + int renderer_id, + int32 route_id, + uint64 swap_buffers_count) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + new BuffersSwappedAcknowledger( + renderer_id, route_id, swap_buffers_count)); +} + void RenderWidgetHostViewMac::GpuRenderingStateDidChange() { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (GetRenderWidgetHost()->is_gpu_rendering_active()) { 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 f3988e1..65d82e9 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.cc +++ b/chrome/browser/renderer_host/test/test_render_view_host.cc @@ -172,7 +172,11 @@ void TestRenderWidgetHostView::AcceleratedSurfaceSetTransportDIB( } void TestRenderWidgetHostView::AcceleratedSurfaceBuffersSwapped( - gfx::PluginWindowHandle window, uint64 surface_id) { + gfx::PluginWindowHandle window, + uint64 surface_id, + int renderer_id, + int32 route_id, + uint64 swap_buffers_count) { } void TestRenderWidgetHostView::GpuRenderingStateDidChange() { 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 4f262f4..fe6daa7 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.h +++ b/chrome/browser/renderer_host/test/test_render_view_host.h @@ -117,8 +117,12 @@ class TestRenderWidgetHostView : public RenderWidgetHostView { int32 width, int32 height, TransportDIB::Handle transport_dib); - virtual void AcceleratedSurfaceBuffersSwapped(gfx::PluginWindowHandle window, - uint64 surface_id); + virtual void AcceleratedSurfaceBuffersSwapped( + gfx::PluginWindowHandle window, + uint64 surface_id, + int renderer_id, + int32 route_id, + uint64 swap_buffers_count); virtual void GpuRenderingStateDidChange(); #endif virtual void SetVisuallyDeemphasized(bool deemphasized) { } diff --git a/chrome/common/gpu_messages.cc b/chrome/common/gpu_messages.cc index 1ba2efa..bd850a1 100644 --- a/chrome/common/gpu_messages.cc +++ b/chrome/common/gpu_messages.cc @@ -31,6 +31,15 @@ GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params:: identifier(0) { } +GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params:: + GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params() + : renderer_id(0), + render_view_id(0), + window(NULL), + surface_id(0), + route_id(0), + swap_buffers_count(0) { +} #endif namespace IPC { @@ -78,6 +87,46 @@ void ParamTraits<GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params> ::Log( l->append(")"); } +void ParamTraits<GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params> ::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.surface_id); + WriteParam(m, p.route_id); + WriteParam(m, p.swap_buffers_count); +} + +bool ParamTraits<GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params> ::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->surface_id) && + ReadParam(m, iter, &p->route_id) && + ReadParam(m, iter, &p->swap_buffers_count); +} + +void ParamTraits<GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params> ::Log( + const param_type& p, + std::string* l) { + l->append("("); + LogParam(p.renderer_id, l); + l->append(", "); + LogParam(p.render_view_id, l); + l->append(", "); + LogParam(p.window, l); + l->append(", "); + LogParam(p.surface_id, l); + l->append(", "); + LogParam(p.route_id, l); + l->append(", "); + LogParam(p.swap_buffers_count, l); + l->append(")"); +} #endif // if defined(OS_MACOSX) void ParamTraits<GPUInfo> ::Write(Message* m, const param_type& p) { diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h index 300cbef..c124530 100644 --- a/chrome/common/gpu_messages_internal.h +++ b/chrome/common/gpu_messages_internal.h @@ -51,6 +51,18 @@ IPC_BEGIN_MESSAGES(Gpu) // information. IPC_MESSAGE_CONTROL0(GpuMsg_CollectGraphicsInfo) +#if defined(OS_MACOSX) + // Tells the GPU process that the browser process handled the swap + // buffers request with the given number. Note that it is possible + // for the browser process to coalesce frames; it is not guaranteed + // that every GpuHostMsg_AcceleratedSurfaceBuffersSwapped message + // will result in a buffer swap on the browser side. + IPC_MESSAGE_CONTROL3(GpuMsg_AcceleratedSurfaceBuffersSwappedACK, + int /* renderer_id */, + int32 /* route_id */, + uint64 /* swap_buffers_count */) +#endif + // Tells the GPU process to crash. IPC_MESSAGE_CONTROL0(GpuMsg_Crash) @@ -99,11 +111,8 @@ IPC_BEGIN_MESSAGES(GpuHost) // 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_CONTROL4(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, - int32, /* renderer_id */ - int32, /* render_view_id */ - gfx::PluginWindowHandle /* window */, - uint64 /* surface_id */) + IPC_MESSAGE_CONTROL1(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, + GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params) #endif IPC_END_MESSAGES(GpuHost) @@ -231,13 +240,6 @@ 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/gpu_param_traits.h b/chrome/common/gpu_param_traits.h index 2aac31a..3ebaca0 100644 --- a/chrome/common/gpu_param_traits.h +++ b/chrome/common/gpu_param_traits.h @@ -31,6 +31,17 @@ struct GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params { GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params(); }; + +struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params { + int32 renderer_id; + int32 render_view_id; + gfx::PluginWindowHandle window; + uint64 surface_id; + int32 route_id; + uint64 swap_buffers_count; + + GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params(); +}; #endif namespace IPC { @@ -42,6 +53,14 @@ struct ParamTraits<GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params> { static bool Read(const Message* m, void** iter, param_type* p); static void Log(const param_type& p, std::string* l); }; + +template <> +struct ParamTraits<GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params> { + typedef GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* p); + static void Log(const param_type& p, std::string* l); +}; #endif template <> diff --git a/chrome/gpu/gpu_channel.cc b/chrome/gpu/gpu_channel.cc index 35b530e..7cd06d2 100644 --- a/chrome/gpu/gpu_channel.cc +++ b/chrome/gpu/gpu_channel.cc @@ -83,6 +83,16 @@ bool GpuChannel::Send(IPC::Message* message) { return channel_->Send(message); } +#if defined(OS_MACOSX) +void GpuChannel::AcceleratedSurfaceBuffersSwapped( + int32 route_id, uint64 swap_buffers_count) { + GpuCommandBufferStub* stub = stubs_.Lookup(route_id); + if (stub == NULL) + return; + stub->AcceleratedSurfaceBuffersSwapped(swap_buffers_count); +} +#endif + void GpuChannel::OnControlMessageReceived(const IPC::Message& msg) { IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg) IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateViewCommandBuffer, diff --git a/chrome/gpu/gpu_channel.h b/chrome/gpu/gpu_channel.h index f359777..3d64355 100644 --- a/chrome/gpu/gpu_channel.h +++ b/chrome/gpu/gpu_channel.h @@ -60,6 +60,11 @@ class GpuChannel : public IPC::Channel::Listener, // IPC::Message::Sender implementation: virtual bool Send(IPC::Message* msg); +#if defined(OS_MACOSX) + virtual void AcceleratedSurfaceBuffersSwapped( + int32 route_id, uint64 swap_buffers_count); +#endif + private: void OnControlMessageReceived(const IPC::Message& msg); diff --git a/chrome/gpu/gpu_command_buffer_stub.cc b/chrome/gpu/gpu_command_buffer_stub.cc index 1adb22c..1872246 100644 --- a/chrome/gpu/gpu_command_buffer_stub.cc +++ b/chrome/gpu/gpu_command_buffer_stub.cc @@ -205,9 +205,25 @@ void GpuCommandBufferStub::OnSetWindowSize(const gfx::Size& size) { } void GpuCommandBufferStub::SwapBuffersCallback() { + OnSwapBuffers(); ChildThread* gpu_thread = ChildThread::current(); - gpu_thread->Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped( - renderer_id_, render_view_id_, handle_, processor_->GetSurfaceId())); + GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; + params.renderer_id = renderer_id_; + params.render_view_id = render_view_id_; + params.window = handle_; + params.surface_id = processor_->GetSurfaceId(); + params.route_id = route_id(); +#if defined(OS_MACOSX) + params.swap_buffers_count = processor_->swap_buffers_count(); +#endif + gpu_thread->Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params)); +} + +void GpuCommandBufferStub::AcceleratedSurfaceBuffersSwapped( + uint64 swap_buffers_count) { + processor_->set_acknowledged_swap_buffers_count(swap_buffers_count); + // Wake up the GpuProcessor to start doing work again. + processor_->ScheduleProcessCommands(); } #endif // defined(OS_MACOSX) diff --git a/chrome/gpu/gpu_command_buffer_stub.h b/chrome/gpu/gpu_command_buffer_stub.h index 1a1e9be..ef57715 100644 --- a/chrome/gpu/gpu_command_buffer_stub.h +++ b/chrome/gpu/gpu_command_buffer_stub.h @@ -51,6 +51,11 @@ class GpuCommandBufferStub int32 route_id() const { return route_id_; } +#if defined(OS_MACOSX) + // Called only by the GpuChannel. + void AcceleratedSurfaceBuffersSwapped(uint64 swap_buffers_count); +#endif + private: // Message handlers: void OnInitialize(int32 size, base::SharedMemoryHandle* ring_buffer); diff --git a/chrome/gpu/gpu_thread.cc b/chrome/gpu/gpu_thread.cc index dc12737..d81a09a 100644 --- a/chrome/gpu/gpu_thread.cc +++ b/chrome/gpu/gpu_thread.cc @@ -61,6 +61,10 @@ void GpuThread::OnControlMessageReceived(const IPC::Message& msg) { OnSynchronize) IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo, OnCollectGraphicsInfo) +#if defined(OS_MACOSX) + IPC_MESSAGE_HANDLER(GpuMsg_AcceleratedSurfaceBuffersSwappedACK, + OnAcceleratedSurfaceBuffersSwappedACK) +#endif IPC_MESSAGE_HANDLER(GpuMsg_Crash, OnCrash) IPC_MESSAGE_HANDLER(GpuMsg_Hang, @@ -107,6 +111,17 @@ void GpuThread::OnCollectGraphicsInfo() { Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_)); } +#if defined(OS_MACOSX) +void GpuThread::OnAcceleratedSurfaceBuffersSwappedACK( + int renderer_id, int32 route_id, uint64 swap_buffers_count) { + GpuChannelMap::const_iterator iter = gpu_channels_.find(renderer_id); + if (iter == gpu_channels_.end()) + return; + scoped_refptr<GpuChannel> channel = iter->second; + channel->AcceleratedSurfaceBuffersSwapped(route_id, swap_buffers_count); +} +#endif + void GpuThread::OnCrash() { // Good bye, cruel world. volatile int* it_s_the_end_of_the_world_as_we_know_it = NULL; diff --git a/chrome/gpu/gpu_thread.h b/chrome/gpu/gpu_thread.h index 275fa12..26b7966 100644 --- a/chrome/gpu/gpu_thread.h +++ b/chrome/gpu/gpu_thread.h @@ -35,6 +35,10 @@ class GpuThread : public ChildThread { void OnEstablishChannel(int renderer_id); void OnSynchronize(); void OnCollectGraphicsInfo(); +#if defined(OS_MACOSX) + void OnAcceleratedSurfaceBuffersSwappedACK( + int renderer_id, int32 route_id, uint64 swap_buffers_count); +#endif void OnCrash(); void OnHang(); diff --git a/chrome/renderer/ggl/ggl.cc b/chrome/renderer/ggl/ggl.cc index b983514..6cd9a33 100644 --- a/chrome/renderer/ggl/ggl.cc +++ b/chrome/renderer/ggl/ggl.cc @@ -34,6 +34,12 @@ const int32 kCommandBufferSize = 1024 * 1024; // creation attributes. const int32 kTransferBufferSize = 1024 * 1024; +// TODO(kbr) / TODO(apatrick): determine the best number of pending frames +// in the general case. On Mac OS X it seems we really want this to be 1, +// because otherwise the renderer process produces frames that do not +// actually reach the screen. +const int kMaxFramesPending = 1; + // Singleton used to initialize and terminate the gles2 library. class GLES2Initializer { public: @@ -132,6 +138,8 @@ class Context : public base::SupportsWeakPtr<Context> { gpu::gles2::GLES2Implementation* gles2_implementation_; gfx::Size size_; + int32 swap_buffer_tokens_[kMaxFramesPending]; + Error last_error_; DISALLOW_COPY_AND_ASSIGN(Context); @@ -147,6 +155,8 @@ Context::Context(GpuChannelHost* channel, Context* parent) gles2_implementation_(NULL), last_error_(SUCCESS) { DCHECK(channel); + for (int i = 0; i < kMaxFramesPending; ++i) + swap_buffer_tokens_[i] = -1; } Context::~Context() { @@ -376,7 +386,18 @@ bool Context::SwapBuffers() { if (command_buffer_->GetLastState().error != gpu::error::kNoError) return false; + // Throttle until there are not too many frames pending. + if (swap_buffer_tokens_[0] != -1) { + gles2_helper_->WaitForToken(swap_buffer_tokens_[0]); + } + gles2_implementation_->SwapBuffers(); + + // Insert a new token to throttle against for this frame. + for (int i = 0; i < kMaxFramesPending - 1; ++i) + swap_buffer_tokens_[i] = swap_buffer_tokens_[i + 1]; + swap_buffer_tokens_[kMaxFramesPending - 1] = gles2_helper_->InsertToken(); + return true; } |