diff options
37 files changed, 466 insertions, 273 deletions
diff --git a/ash/wm/window_animations.cc b/ash/wm/window_animations.cc index 282567c..48ee701 100644 --- a/ash/wm/window_animations.cc +++ b/ash/wm/window_animations.cc @@ -573,8 +573,6 @@ class CrossFadeObserver : public ui::CompositorObserver, // ui::CompositorObserver overrides: virtual void OnCompositingDidCommit(ui::Compositor* compositor) OVERRIDE { } - virtual void OnCompositingWillStart(ui::Compositor* compositor) OVERRIDE { - } virtual void OnCompositingStarted(ui::Compositor* compositor) OVERRIDE { } virtual void OnCompositingEnded(ui::Compositor* compositor) OVERRIDE { @@ -583,6 +581,9 @@ class CrossFadeObserver : public ui::CompositorObserver, // Triggers OnImplicitAnimationsCompleted() to be called and deletes us. layer_->GetAnimator()->StopAnimating(); } + virtual void OnCompositingLockStateChanged( + ui::Compositor* compositor) OVERRIDE { + } // aura::WindowObserver overrides: virtual void OnWindowDestroying(Window* window) OVERRIDE { diff --git a/cc/layer_tree_host.cc b/cc/layer_tree_host.cc index aead25f..7c70ef9 100644 --- a/cc/layer_tree_host.cc +++ b/cc/layer_tree_host.cc @@ -345,6 +345,15 @@ void LayerTreeHost::finishAllRendering() m_proxy->finishAllRendering(); } +void LayerTreeHost::setDeferCommits(bool deferCommits) +{ + m_proxy->setDeferCommits(deferCommits); +} + +void LayerTreeHost::didDeferCommit() +{ +} + void LayerTreeHost::renderingStats(RenderingStats* stats) const { *stats = m_renderingStats; diff --git a/cc/layer_tree_host.h b/cc/layer_tree_host.h index f64862e..12e7750 100644 --- a/cc/layer_tree_host.h +++ b/cc/layer_tree_host.h @@ -143,6 +143,11 @@ public: void finishAllRendering(); + void setDeferCommits(bool deferCommits); + + // Test only hook + virtual void didDeferCommit(); + int commitNumber() const { return m_commitNumber; } void renderingStats(RenderingStats*) const; diff --git a/cc/layer_tree_host_unittest.cc b/cc/layer_tree_host_unittest.cc index 72b094a..f85111e 100644 --- a/cc/layer_tree_host_unittest.cc +++ b/cc/layer_tree_host_unittest.cc @@ -3183,4 +3183,57 @@ TEST_F(LayerTreeHostTestContinuousAnimate, runMultiThread) runTest(true); } +class LayerTreeHostTestDeferCommits : public LayerTreeHostTest { +public: + LayerTreeHostTestDeferCommits() + : m_numCommitsDeferred(0) + , m_numCompleteCommits(0) + { + } + + virtual void beginTest() OVERRIDE + { + postSetNeedsCommitToMainThread(); + } + + virtual void didDeferCommit() OVERRIDE + { + m_numCommitsDeferred++; + m_layerTreeHost->setDeferCommits(false); + } + + virtual void didCommit() OVERRIDE + { + m_numCompleteCommits++; + switch (m_numCompleteCommits) { + case 1: + EXPECT_EQ(0, m_numCommitsDeferred); + m_layerTreeHost->setDeferCommits(true); + postSetNeedsCommitToMainThread(); + break; + case 2: + endTest(); + break; + default: + NOTREACHED(); + break; + } + } + + virtual void afterTest() OVERRIDE + { + EXPECT_EQ(1, m_numCommitsDeferred); + EXPECT_EQ(2, m_numCompleteCommits); + } + +private: + int m_numCommitsDeferred; + int m_numCompleteCommits; +}; + +TEST_F(LayerTreeHostTestDeferCommits, runMultiThread) +{ + runTest(true); +} + } // namespace @@ -65,6 +65,10 @@ public: virtual void setNeedsCommit() = 0; virtual void setNeedsRedraw() = 0; + // Defers commits until it is reset. It is only supported when in threaded mode. It's an error to make a sync call + // like compositeAndReadback while commits are deferred. + virtual void setDeferCommits(bool) = 0; + virtual void didAddAnimation() = 0; virtual bool commitRequested() const = 0; diff --git a/cc/single_thread_proxy.cc b/cc/single_thread_proxy.cc index 5cbe3d2..9433e1a 100644 --- a/cc/single_thread_proxy.cc +++ b/cc/single_thread_proxy.cc @@ -231,6 +231,12 @@ void SingleThreadProxy::setNeedsRedraw() setNeedsCommit(); } +void SingleThreadProxy::setDeferCommits(bool deferCommits) +{ + // Thread-only feature. + NOTREACHED(); +} + bool SingleThreadProxy::commitRequested() const { return false; diff --git a/cc/single_thread_proxy.h b/cc/single_thread_proxy.h index 2a27e32..ca6769f 100644 --- a/cc/single_thread_proxy.h +++ b/cc/single_thread_proxy.h @@ -37,6 +37,7 @@ public: virtual void setNeedsAnimate() OVERRIDE; virtual void setNeedsCommit() OVERRIDE; virtual void setNeedsRedraw() OVERRIDE; + virtual void setDeferCommits(bool) OVERRIDE; virtual bool commitRequested() const OVERRIDE; virtual void didAddAnimation() OVERRIDE; virtual void start() OVERRIDE; diff --git a/cc/test/layer_tree_test_common.cc b/cc/test/layer_tree_test_common.cc index 686cd27..846e807 100644 --- a/cc/test/layer_tree_test_common.cc +++ b/cc/test/layer_tree_test_common.cc @@ -181,6 +181,11 @@ public: void setTestStarted(bool started) { m_testStarted = started; } + virtual void didDeferCommit() OVERRIDE + { + m_testHooks->didDeferCommit(); + } + private: MockLayerTreeHost(TestHooks* testHooks, cc::LayerTreeHostClient* client, const cc::LayerTreeSettings& settings) : LayerTreeHost(client, settings) diff --git a/cc/test/layer_tree_test_common.h b/cc/test/layer_tree_test_common.h index 91f9525..d1378c8 100644 --- a/cc/test/layer_tree_test_common.h +++ b/cc/test/layer_tree_test_common.h @@ -40,6 +40,7 @@ public: virtual void didCommit() { } virtual void didCommitAndDrawFrame() { } virtual void scheduleComposite() { } + virtual void didDeferCommit() { } // Implementation of WebAnimationDelegate virtual void notifyAnimationStarted(double time) OVERRIDE { } diff --git a/cc/thread_proxy.cc b/cc/thread_proxy.cc index 666c03f..e8229ca 100644 --- a/cc/thread_proxy.cc +++ b/cc/thread_proxy.cc @@ -53,6 +53,8 @@ ThreadProxy::ThreadProxy(LayerTreeHost* layerTreeHost) , m_nextFrameIsNewlyCommittedFrameOnImplThread(false) , m_renderVSyncEnabled(layerTreeHost->settings().renderVSyncEnabled) , m_totalCommitCount(0) + , m_deferCommits(false) + , m_deferredCommitPending(false) { TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy"); DCHECK(isMainThread()); @@ -70,6 +72,7 @@ bool ThreadProxy::compositeAndReadback(void *pixels, const IntRect& rect) TRACE_EVENT0("cc", "ThreadPRoxy::compositeAndReadback"); DCHECK(isMainThread()); DCHECK(m_layerTreeHost); + DCHECK(!m_deferCommits); if (!m_layerTreeHost->initializeRendererIfNeeded()) { TRACE_EVENT0("cc", "compositeAndReadback_EarlyOut_LR_Uninitialized"); @@ -131,6 +134,7 @@ void ThreadProxy::requestStartPageScaleAnimationOnImplThread(IntSize targetPosit void ThreadProxy::finishAllRendering() { DCHECK(Proxy::isMainThread()); + DCHECK(!m_deferCommits); // Make sure all GL drawing is finished on the impl thread. DebugScopedSetMainThreadBlocked mainThreadBlocked; @@ -386,6 +390,23 @@ void ThreadProxy::setNeedsRedraw() Proxy::implThread()->postTask(createThreadTask(this, &ThreadProxy::setNeedsRedrawOnImplThread)); } +void ThreadProxy::setDeferCommits(bool deferCommits) +{ + DCHECK(isMainThread()); + DCHECK_NE(m_deferCommits, deferCommits); + m_deferCommits = deferCommits; + + if (m_deferCommits) + TRACE_EVENT_ASYNC_BEGIN0("cc", "ThreadProxy::setDeferCommits", this); + else + TRACE_EVENT_ASYNC_END0("cc", "ThreadProxy::setDeferCommits", this); + + if (!m_deferCommits && m_deferredCommitPending) { + m_deferredCommitPending = false; + m_mainThreadProxy->postTask(createThreadTask(this, &ThreadProxy::beginFrame)); + } +} + bool ThreadProxy::commitRequested() const { DCHECK(isMainThread()); @@ -500,6 +521,13 @@ void ThreadProxy::beginFrame() if (!m_layerTreeHost) return; + if (m_deferCommits) { + m_deferredCommitPending = true; + m_layerTreeHost->didDeferCommit(); + TRACE_EVENT0("cc", "EarlyOut_DeferCommits"); + return; + } + if (!m_pendingBeginFrameRequest) { TRACE_EVENT0("cc", "EarlyOut_StaleBeginFrameMessage"); return; diff --git a/cc/thread_proxy.h b/cc/thread_proxy.h index 58e327c..695ac80 100644 --- a/cc/thread_proxy.h +++ b/cc/thread_proxy.h @@ -45,6 +45,7 @@ public: virtual void setNeedsAnimate() OVERRIDE; virtual void setNeedsCommit() OVERRIDE; virtual void setNeedsRedraw() OVERRIDE; + virtual void setDeferCommits(bool) OVERRIDE; virtual bool commitRequested() const OVERRIDE; virtual void didAddAnimation() OVERRIDE { } virtual void start() OVERRIDE; @@ -174,6 +175,9 @@ private: base::TimeDelta m_totalCommitTime; size_t m_totalCommitCount; + + bool m_deferCommits; + bool m_deferredCommitPending; }; } diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index 5f964c0..2e99d2e 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc @@ -108,7 +108,8 @@ void SendGpuProcessMessage(GpuProcessHost::GpuProcessKind kind, void AcceleratedSurfaceBuffersSwappedCompletedForGPU(int host_id, int route_id, - bool alive) { + bool alive, + bool did_swap) { if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { BrowserThread::PostTask( BrowserThread::IO, @@ -116,14 +117,16 @@ void AcceleratedSurfaceBuffersSwappedCompletedForGPU(int host_id, base::Bind(&AcceleratedSurfaceBuffersSwappedCompletedForGPU, host_id, route_id, - alive)); + alive, + did_swap)); return; } GpuProcessHost* host = GpuProcessHost::FromID(host_id); if (host) { if (alive) - host->Send(new AcceleratedSurfaceMsg_BufferPresented(route_id, 0)); + host->Send(new AcceleratedSurfaceMsg_BufferPresented( + route_id, did_swap, 0)); else host->ForceShutdown(); } @@ -168,7 +171,8 @@ void AcceleratedSurfaceBuffersSwappedCompleted(int host_id, bool alive, base::TimeTicks timebase, base::TimeDelta interval) { - AcceleratedSurfaceBuffersSwappedCompletedForGPU(host_id, route_id, alive); + AcceleratedSurfaceBuffersSwappedCompletedForGPU(host_id, route_id, + alive, true /* presented */); AcceleratedSurfaceBuffersSwappedCompletedForRenderer(surface_id, timebase, interval); } @@ -680,7 +684,8 @@ void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped( base::ScopedClosureRunner scoped_completion_runner( base::Bind(&AcceleratedSurfaceBuffersSwappedCompletedForGPU, - host_id_, params.route_id, true)); + host_id_, params.route_id, + true /* alive */, false /* presented */)); int render_process_id = 0; int render_widget_id = 0; diff --git a/content/browser/gpu/gpu_process_host_ui_shim.cc b/content/browser/gpu/gpu_process_host_ui_shim.cc index 766157b..13a0cd1 100644 --- a/content/browser/gpu/gpu_process_host_ui_shim.cc +++ b/content/browser/gpu/gpu_process_host_ui_shim.cc @@ -307,7 +307,7 @@ void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped( ScopedSendOnIOThread delayed_send( host_id_, - new AcceleratedSurfaceMsg_BufferPresented(params.route_id, 0)); + new AcceleratedSurfaceMsg_BufferPresented(params.route_id, false, 0)); RenderWidgetHostViewPort* view = GetRenderWidgetHostViewFromSurfaceID( params.surface_id); @@ -331,7 +331,7 @@ void GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer( ScopedSendOnIOThread delayed_send( host_id_, - new AcceleratedSurfaceMsg_BufferPresented(params.route_id, 0)); + new AcceleratedSurfaceMsg_BufferPresented(params.route_id, false, 0)); RenderWidgetHostViewPort* view = GetRenderWidgetHostViewFromSurfaceID(params.surface_id); diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index d43f338..6666079 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -1595,6 +1595,7 @@ void RenderProcessHostImpl::OnCompositorSurfaceBuffersSwappedNoHost( "RenderWidgetHostImpl::OnCompositorSurfaceBuffersSwappedNoHost"); RenderWidgetHostImpl::AcknowledgeBufferPresent(route_id, gpu_process_host_id, + false, 0); } diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index d6131a5..404ec650 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc @@ -1391,6 +1391,7 @@ void RenderWidgetHostImpl::OnCompositorSurfaceBuffersSwapped( if (!view_) { RenderWidgetHostImpl::AcknowledgeBufferPresent(route_id, gpu_process_host_id, + false, 0); return; } @@ -2130,10 +2131,11 @@ bool RenderWidgetHostImpl::GotResponseToLockMouseRequest(bool allowed) { // static void RenderWidgetHostImpl::AcknowledgeBufferPresent( - int32 route_id, int gpu_host_id, uint32 sync_point) { + int32 route_id, int gpu_host_id, bool presented, uint32 sync_point) { GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(gpu_host_id); if (ui_shim) ui_shim->Send(new AcceleratedSurfaceMsg_BufferPresented(route_id, + presented, sync_point)); } diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index b2e8591..db354a4 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h @@ -393,6 +393,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, static void AcknowledgeBufferPresent( int32 route_id, int gpu_host_id, + bool presented, uint32 sync_point); // Called by the view in response to AcceleratedSurfaceBuffersSwapped for diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 825c241..a4e90b6 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc @@ -379,7 +379,7 @@ void RenderWidgetHostViewAndroid::AcceleratedSurfaceBuffersSwapped( uint32 sync_point = ImageTransportFactoryAndroid::GetInstance()->InsertSyncPoint(); RenderWidgetHostImpl::AcknowledgeBufferPresent( - params.route_id, gpu_host_id, sync_point); + params.route_id, gpu_host_id, true, sync_point); } void RenderWidgetHostViewAndroid::AcceleratedSurfacePostSubBuffer( diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index f8565ee..6987fcc 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc @@ -198,11 +198,16 @@ class RenderWidgetHostViewAura::WindowObserver : public aura::WindowObserver { class RenderWidgetHostViewAura::ResizeLock { public: - ResizeLock(aura::RootWindow* root_window, const gfx::Size new_size) + ResizeLock(aura::RootWindow* root_window, + const gfx::Size new_size, + bool defer_compositor_lock) : root_window_(root_window), new_size_(new_size), - compositor_lock_(root_window_->GetCompositorLock()), - weak_ptr_factory_(this) { + compositor_lock_(defer_compositor_lock ? + NULL : + root_window_->compositor()->GetCompositorLock()), + weak_ptr_factory_(this), + defer_compositor_lock_(defer_compositor_lock) { root_window_->HoldMouseMoves(); BrowserThread::PostDelayedTask( @@ -217,6 +222,7 @@ class RenderWidgetHostViewAura::ResizeLock { } void UnlockCompositor() { + defer_compositor_lock_ = false; compositor_lock_ = NULL; } @@ -232,11 +238,21 @@ class RenderWidgetHostViewAura::ResizeLock { return new_size_; } + bool GrabDeferredLock() { + if (root_window_ && defer_compositor_lock_) { + compositor_lock_ = root_window_->compositor()->GetCompositorLock(); + defer_compositor_lock_ = false; + return true; + } + return false; + } + private: aura::RootWindow* root_window_; gfx::Size new_size_; - scoped_refptr<aura::CompositorLock> compositor_lock_; + scoped_refptr<ui::CompositorLock> compositor_lock_; base::WeakPtrFactory<ResizeLock> weak_ptr_factory_; + bool defer_compositor_lock_; DISALLOW_COPY_AND_ASSIGN(ResizeLock); }; @@ -263,7 +279,8 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host) surface_route_id_(0), paint_canvas_(NULL), synthetic_move_sent_(false), - accelerated_compositing_state_changed_(false) { + accelerated_compositing_state_changed_(false), + can_lock_compositor_(YES) { host_->SetView(this); window_observer_.reset(new WindowObserver(this)); window_->AddObserver(window_observer_.get()); @@ -343,7 +360,7 @@ void RenderWidgetHostViewAura::WasShown() { if (!current_surface_ && host_->is_accelerated_compositing_active() && !released_front_lock_.get()) { - released_front_lock_ = window_->GetRootWindow()->GetCompositorLock(); + released_front_lock_ = GetCompositor()->GetCompositorLock(); } AdjustSurfaceProtection(); @@ -388,9 +405,22 @@ void RenderWidgetHostViewAura::SetBounds(const gfx::Rect& rect) { if (window_->bounds().size() != rect.size() && host_->is_accelerated_compositing_active()) { aura::RootWindow* root_window = window_->GetRootWindow(); - if (root_window) { + ui::Compositor* compositor = root_window ? + root_window->compositor() : NULL; + if (root_window && compositor) { + // Listen to changes in the compositor lock state. + if (!compositor->HasObserver(this)) + compositor->AddObserver(this); + + bool defer_compositor_lock = + can_lock_compositor_ == NO_PENDING_RENDERER_FRAME || + can_lock_compositor_ == NO_PENDING_COMMIT; + + if (can_lock_compositor_ == YES) + can_lock_compositor_ = YES_DID_LOCK; + resize_locks_.push_back(make_linked_ptr( - new ResizeLock(root_window, rect.size()))); + new ResizeLock(root_window, rect.size(), defer_compositor_lock))); } } window_->SetBounds(rect); @@ -695,6 +725,28 @@ void RenderWidgetHostViewAura::OnAcceleratedCompositingStateChange() { accelerated_compositing_state_changed_ = true; } +bool RenderWidgetHostViewAura::ShouldFastACK(uint64 surface_id) { + ui::Texture* container = image_transport_clients_[surface_id]; + DCHECK(container); + + if (can_lock_compositor_ == NO_PENDING_RENDERER_FRAME || + can_lock_compositor_ == NO_PENDING_COMMIT || + resize_locks_.empty()) + return false; + + gfx::Size container_size = ConvertSizeToDIP(this, container->size()); + ResizeLockList::iterator it = resize_locks_.begin(); + while (it != resize_locks_.end()) { + if ((*it)->expected_size() == container_size) + break; + ++it; + } + + // We could be getting an unexpected frame due to an animation + // (i.e. we start resizing but we get an old size frame first). + return it == resize_locks_.end() || ++it != resize_locks_.end(); +} + void RenderWidgetHostViewAura::UpdateExternalTexture() { // Delay processing accelerated compositing state change till here where we // act upon the state change. (Clear the external texture if switching to @@ -710,7 +762,6 @@ void RenderWidgetHostViewAura::UpdateExternalTexture() { if (!container) { resize_locks_.clear(); } else { - typedef std::vector<linked_ptr<ResizeLock> > ResizeLockList; ResizeLockList::iterator it = resize_locks_.begin(); while (it != resize_locks_.end()) { gfx::Size container_size = ConvertSizeToDIP(this, @@ -726,8 +777,8 @@ void RenderWidgetHostViewAura::UpdateExternalTexture() { // Delay the release of the lock until we've kicked a frame with the // new texture, to avoid resizing the UI before we have a chance to // draw a "good" frame. - locks_pending_draw_.insert( - locks_pending_draw_.begin(), resize_locks_.begin(), it); + locks_pending_commit_.insert( + locks_pending_commit_.begin(), resize_locks_.begin(), it); // However since we got the size we were looking for, unlock the // compositor. for (ResizeLockList::iterator it2 = resize_locks_.begin(); @@ -744,12 +795,12 @@ void RenderWidgetHostViewAura::UpdateExternalTexture() { window_->SetExternalTexture(NULL); if (ShouldReleaseFrontSurface() && host_->is_accelerated_compositing_active()) { - // The current surface may have pipelined gl commands, so always wait for - // the next composite to start. If the current surface is still null, - // then we really know its no longer in use. + // We need to wait for a commit to clear to guarantee that all we + // will not issue any more GL referencing the previous surface. ui::Compositor* compositor = GetCompositor(); if (compositor) { - on_compositing_will_start_callbacks_.push_back( + can_lock_compositor_ = NO_PENDING_COMMIT; + on_compositing_did_commit_callbacks_.push_back( base::Bind(&RenderWidgetHostViewAura:: SetSurfaceNotInUseByCompositor, AsWeakPtr())); @@ -771,15 +822,22 @@ void RenderWidgetHostViewAura::AcceleratedSurfaceBuffersSwapped( params_in_pixel.protection_state_id != protection_state_id_) { DCHECK(!current_surface_); if (!params_in_pixel.skip_ack) - InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, NULL); + InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, false, NULL); + return; + } + + if (ShouldFastACK(params_in_pixel.surface_handle)) { + if (!params_in_pixel.skip_ack) + InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, false, NULL); return; } + current_surface_ = params_in_pixel.surface_handle; // If we don't require an ACK that means the content is not a fresh updated - // new frame, rather we are just resetting our handle to some old content that - // we still hadn't discarded. Although we could display immediately, by not - // resetting the compositor lock here, we give us some time to get a fresh - // frame which means fewer content flashes. + // new frame, rather we are just resetting our handle to some old content + // that we still hadn't discarded. Although we could display immediately, + // by not resetting the compositor lock here, we give us some time to get + // a fresh frame which means fewer content flashes. if (!params_in_pixel.skip_ack) released_front_lock_ = NULL; @@ -787,46 +845,26 @@ void RenderWidgetHostViewAura::AcceleratedSurfaceBuffersSwapped( ui::Compositor* compositor = GetCompositor(); if (!compositor) { - // We have no compositor, so we have no way to display the surface. - // Must still send the ACK. if (!params_in_pixel.skip_ack) - InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, NULL); + InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, false, NULL); } else { DCHECK(image_transport_clients_.find(params_in_pixel.surface_handle) != image_transport_clients_.end()); gfx::Size surface_size_in_pixel = image_transport_clients_[params_in_pixel.surface_handle]->size(); - gfx::Size surface_size = ConvertSizeToDIP(this, - surface_size_in_pixel); + gfx::Size surface_size = ConvertSizeToDIP(this, surface_size_in_pixel); window_->SchedulePaintInRect(gfx::Rect(surface_size)); if (!params_in_pixel.skip_ack) { - if (!resize_locks_.empty()) { - // If we are waiting for the resize, fast-track the ACK. - if (compositor->IsThreaded()) { - // We need the compositor thread to pick up the active buffer before - // ACKing. - on_compositing_did_commit_callbacks_.push_back( - base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, - params_in_pixel.route_id, - gpu_host_id)); - if (!compositor->HasObserver(this)) - compositor->AddObserver(this); - } else { - // The compositor will pickup the active buffer during a draw, so we - // can ACK immediately. - InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, - compositor); - } - } else { - // Add sending an ACK to the list of things to do OnCompositingWillStart - on_compositing_will_start_callbacks_.push_back( - base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, - params_in_pixel.route_id, - gpu_host_id)); - if (!compositor->HasObserver(this)) - compositor->AddObserver(this); - } + // Add sending an ACK to the list of things to do OnCompositingDidCommit + can_lock_compositor_ = NO_PENDING_COMMIT; + on_compositing_did_commit_callbacks_.push_back( + base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, + params_in_pixel.route_id, + gpu_host_id, + true)); + if (!compositor->HasObserver(this)) + compositor->AddObserver(this); } } } @@ -840,9 +878,15 @@ void RenderWidgetHostViewAura::AcceleratedSurfacePostSubBuffer( if (params_in_pixel.protection_state_id && params_in_pixel.protection_state_id != protection_state_id_) { DCHECK(!current_surface_); - InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, NULL); + InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, false, NULL); + return; + } + + if (ShouldFastACK(params_in_pixel.surface_handle)) { + InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, false, NULL); return; } + current_surface_ = params_in_pixel.surface_handle; released_front_lock_ = NULL; DCHECK(current_surface_); @@ -850,9 +894,7 @@ void RenderWidgetHostViewAura::AcceleratedSurfacePostSubBuffer( ui::Compositor* compositor = GetCompositor(); if (!compositor) { - // We have no compositor, so we have no way to display the surface - // Must still send the ACK - InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, NULL); + InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, false, NULL); } else { DCHECK(image_transport_clients_.find(params_in_pixel.surface_handle) != image_transport_clients_.end()); @@ -875,32 +917,15 @@ void RenderWidgetHostViewAura::AcceleratedSurfacePostSubBuffer( window_->SchedulePaintInRect(rect_to_paint); - if (!resize_locks_.empty()) { - // If we are waiting for the resize, fast-track the ACK. - if (compositor->IsThreaded()) { - // We need the compositor thread to pick up the active buffer before - // ACKing. - on_compositing_did_commit_callbacks_.push_back( - base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, - params_in_pixel.route_id, - gpu_host_id)); - if (!compositor->HasObserver(this)) - compositor->AddObserver(this); - } else { - // The compositor will pickup the active buffer during a draw, so we - // can ACK immediately. - InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, - compositor); - } - } else { - // Add sending an ACK to the list of things to do OnCompositingWillStart - on_compositing_will_start_callbacks_.push_back( - base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, - params_in_pixel.route_id, - gpu_host_id)); - if (!compositor->HasObserver(this)) - compositor->AddObserver(this); - } + // Add sending an ACK to the list of things to do OnCompositingDidCommit + can_lock_compositor_ = NO_PENDING_COMMIT; + on_compositing_did_commit_callbacks_.push_back( + base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, + params_in_pixel.route_id, + gpu_host_id, + true)); + if (!compositor->HasObserver(this)) + compositor->AddObserver(this); } } @@ -1653,17 +1678,19 @@ void RenderWidgetHostViewAura::OnLostActive() { void RenderWidgetHostViewAura::OnCompositingDidCommit( ui::Compositor* compositor) { + if (can_lock_compositor_ == NO_PENDING_COMMIT) { + can_lock_compositor_ = YES; + for (ResizeLockList::iterator it = resize_locks_.begin(); + it != resize_locks_.end(); ++it) + if ((*it)->GrabDeferredLock()) + can_lock_compositor_ = YES_DID_LOCK; + } RunCompositingDidCommitCallbacks(compositor); -} - -void RenderWidgetHostViewAura::OnCompositingWillStart( - ui::Compositor* compositor) { - RunCompositingWillStartCallbacks(compositor); + locks_pending_commit_.clear(); } void RenderWidgetHostViewAura::OnCompositingStarted( ui::Compositor* compositor) { - locks_pending_draw_.clear(); } void RenderWidgetHostViewAura::OnCompositingEnded( @@ -1674,6 +1701,15 @@ void RenderWidgetHostViewAura::OnCompositingAborted( ui::Compositor* compositor) { } +void RenderWidgetHostViewAura::OnCompositingLockStateChanged( + ui::Compositor* compositor) { + // A compositor lock that is part of a resize lock timed out. We + // should display a renderer frame. + if (!compositor->IsLocked() && can_lock_compositor_ == YES_DID_LOCK) { + can_lock_compositor_ = NO_PENDING_RENDERER_FRAME; + } +} + //////////////////////////////////////////////////////////////////////////////// // RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation: @@ -1685,7 +1721,7 @@ void RenderWidgetHostViewAura::OnLostResources() { current_surface_in_use_by_compositor_ = true; surface_route_id_ = 0; UpdateExternalTexture(); - locks_pending_draw_.clear(); + locks_pending_commit_.clear(); DCHECK(!shared_surface_handle_.is_null()); ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); @@ -1832,19 +1868,10 @@ void RenderWidgetHostViewAura::RunCompositingDidCommitCallbacks( on_compositing_did_commit_callbacks_.clear(); } -void RenderWidgetHostViewAura::RunCompositingWillStartCallbacks( - ui::Compositor* compositor) { - for (std::vector< base::Callback<void(ui::Compositor*)> >::const_iterator - it = on_compositing_will_start_callbacks_.begin(); - it != on_compositing_will_start_callbacks_.end(); ++it) { - it->Run(compositor); - } - on_compositing_will_start_callbacks_.clear(); -} - // static void RenderWidgetHostViewAura::InsertSyncPointAndACK( - int32 route_id, int gpu_host_id, ui::Compositor* compositor) { + int32 route_id, int gpu_host_id, bool presented, + ui::Compositor* compositor) { uint32 sync_point = 0; // If we have no compositor, so we must still send the ACK. A zero // sync point will not be waited for in the GPU process. @@ -1854,7 +1881,7 @@ void RenderWidgetHostViewAura::InsertSyncPointAndACK( } RenderWidgetHostImpl::AcknowledgeBufferPresent( - route_id, gpu_host_id, sync_point); + route_id, gpu_host_id, presented, sync_point); } void RenderWidgetHostViewAura::RemovingFromRootWindow() { @@ -1866,8 +1893,7 @@ void RenderWidgetHostViewAura::RemovingFromRootWindow() { // composited data. ui::Compositor* compositor = GetCompositor(); RunCompositingDidCommitCallbacks(compositor); - RunCompositingWillStartCallbacks(compositor); - locks_pending_draw_.clear(); + locks_pending_commit_.clear(); if (compositor && compositor->HasObserver(this)) compositor->RemoveObserver(this); DetachFromInputMethod(); diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 70d244f..c6076f3 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h @@ -24,7 +24,6 @@ #include "webkit/glue/webcursor.h" namespace aura { -class CompositorLock; class WindowTracker; } @@ -33,6 +32,7 @@ class Canvas; } namespace ui { +class CompositorLock; class InputMethod; class Texture; } @@ -206,10 +206,11 @@ class RenderWidgetHostViewAura // Overridden from ui::CompositorObserver: virtual void OnCompositingDidCommit(ui::Compositor* compositor) OVERRIDE; - virtual void OnCompositingWillStart(ui::Compositor* compositor) OVERRIDE; virtual void OnCompositingStarted(ui::Compositor* compositor) OVERRIDE; virtual void OnCompositingEnded(ui::Compositor* compositor) OVERRIDE; virtual void OnCompositingAborted(ui::Compositor* compositor) OVERRIDE; + virtual void OnCompositingLockStateChanged( + ui::Compositor* compositor) OVERRIDE; // Overridden from ImageTransportFactoryObserver: virtual void OnLostResources() OVERRIDE; @@ -217,6 +218,7 @@ class RenderWidgetHostViewAura virtual ~RenderWidgetHostViewAura(); void UpdateCursorIfOverSelf(); + bool ShouldFastACK(uint64 surface_id); void UpdateExternalTexture(); ui::InputMethod* GetInputMethod() const; @@ -241,12 +243,12 @@ class RenderWidgetHostViewAura // Run the compositing callbacks. void RunCompositingDidCommitCallbacks(ui::Compositor* compositor); - void RunCompositingWillStartCallbacks(ui::Compositor* compositor); // Insert a sync point into the compositor's command stream and acknowledge // that we have presented the accelerated surface buffer. static void InsertSyncPointAndACK(int32 route_id, int gpu_host_id, + bool presented, ui::Compositor* compositor); // Called when window_ is removed from the window tree. @@ -330,9 +332,6 @@ class RenderWidgetHostViewAura std::vector< base::Callback<void(ui::Compositor*)> > on_compositing_did_commit_callbacks_; - std::vector< base::Callback<void(ui::Compositor*)> > - on_compositing_will_start_callbacks_; - std::map<uint64, scoped_refptr<ui::Texture> > image_transport_clients_; @@ -379,19 +378,32 @@ class RenderWidgetHostViewAura // Used to prevent further resizes while a resize is pending. class ResizeLock; + typedef std::vector<linked_ptr<ResizeLock> > ResizeLockList; + // These locks are the ones waiting for a texture of the right size to come // back from the renderer/GPU process. - std::vector<linked_ptr<ResizeLock> > resize_locks_; - // These locks are the ones waiting for a frame to be drawn. - std::vector<linked_ptr<ResizeLock> > locks_pending_draw_; + ResizeLockList resize_locks_; + // These locks are the ones waiting for a frame to be committed. + ResizeLockList locks_pending_commit_; // This lock is for waiting for a front surface to become available to draw. - scoped_refptr<aura::CompositorLock> released_front_lock_; + scoped_refptr<ui::CompositorLock> released_front_lock_; // Used to track the state of the window we're created from. Only used when // created fullscreen. scoped_ptr<aura::WindowTracker> host_tracker_; + enum CanLockCompositorState { + YES, + // We locked, so at some point we'll need to kick a frame. + YES_DID_LOCK, + // No. A lock timed out, we need to kick a new frame before locking again. + NO_PENDING_RENDERER_FRAME, + // No. We've got a frame, but it hasn't been committed. + NO_PENDING_COMMIT, + }; + CanLockCompositorState can_lock_compositor_; + DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAura); }; diff --git a/content/browser/renderer_host/render_widget_host_view_gtk.cc b/content/browser/renderer_host/render_widget_host_view_gtk.cc index dbe534d4..b429496 100644 --- a/content/browser/renderer_host/render_widget_host_view_gtk.cc +++ b/content/browser/renderer_host/render_widget_host_view_gtk.cc @@ -1072,14 +1072,14 @@ void RenderWidgetHostViewGtk::AcceleratedSurfaceBuffersSwapped( const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, int gpu_host_id) { RenderWidgetHostImpl::AcknowledgeBufferPresent( - params.route_id, gpu_host_id, 0); + params.route_id, gpu_host_id, true, 0); } void RenderWidgetHostViewGtk::AcceleratedSurfacePostSubBuffer( const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params, int gpu_host_id) { RenderWidgetHostImpl::AcknowledgeBufferPresent( - params.route_id, gpu_host_id, 0); + params.route_id, gpu_host_id, true, 0); } void RenderWidgetHostViewGtk::AcceleratedSurfaceSuspend() { diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index f6cdfd4..8b75f45 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm @@ -1037,6 +1037,7 @@ void RenderWidgetHostViewMac::AckPendingSwapBuffers() { RenderWidgetHostImpl::AcknowledgeBufferPresent( pending_swap_buffers_acks_.front().first, pending_swap_buffers_acks_.front().second, + true, 0); if (render_widget_host_) { render_widget_host_->AcknowledgeSwapBuffersToRenderer(); diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h index 4549e30..498f1ba 100644 --- a/content/common/gpu/gpu_messages.h +++ b/content/common/gpu/gpu_messages.h @@ -275,7 +275,8 @@ IPC_MESSAGE_ROUTED2(AcceleratedSurfaceMsg_SetFrontSurfaceIsProtected, // Tells the GPU process that the browser process has handled the swap // buffers or post sub-buffer request. A non-zero sync point means // that we should wait for the sync point. -IPC_MESSAGE_ROUTED1(AcceleratedSurfaceMsg_BufferPresented, +IPC_MESSAGE_ROUTED2(AcceleratedSurfaceMsg_BufferPresented, + bool /* presented */, uint32 /* sync_point */) // Tells the GPU process to remove all contexts. diff --git a/content/common/gpu/image_transport_surface.cc b/content/common/gpu/image_transport_surface.cc index dce01a2..47bb204 100644 --- a/content/common/gpu/image_transport_surface.cc +++ b/content/common/gpu/image_transport_surface.cc @@ -212,8 +212,9 @@ void ImageTransportHelper::OnSetFrontSurfaceIsProtected( surface_->OnSetFrontSurfaceIsProtected(is_protected, protection_state_id); } -void ImageTransportHelper::OnBufferPresented(uint32 sync_point) { - surface_->OnBufferPresented(sync_point); +void ImageTransportHelper::OnBufferPresented(bool presented, + uint32 sync_point) { + surface_->OnBufferPresented(presented, sync_point); } void ImageTransportHelper::OnResizeViewACK() { @@ -311,7 +312,9 @@ bool PassThroughImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) { return true; } -void PassThroughImageTransportSurface::OnBufferPresented(uint32 sync_point) { +void PassThroughImageTransportSurface::OnBufferPresented( + bool /* presented */, + uint32 /* sync_point */) { DCHECK(transport_); helper_->SetScheduled(true); } diff --git a/content/common/gpu/image_transport_surface.h b/content/common/gpu/image_transport_surface.h index 3a9849e..391f72a 100644 --- a/content/common/gpu/image_transport_surface.h +++ b/content/common/gpu/image_transport_surface.h @@ -60,7 +60,7 @@ class ImageTransportSurface { public: ImageTransportSurface(); - virtual void OnBufferPresented(uint32 sync_point) = 0; + virtual void OnBufferPresented(bool presented, uint32 sync_point) = 0; virtual void OnResizeViewACK() = 0; virtual void OnResize(gfx::Size size) = 0; virtual void OnSetFrontSurfaceIsProtected(bool is_protected, @@ -139,7 +139,7 @@ class ImageTransportHelper : public IPC::Listener { gpu::gles2::GLES2Decoder* Decoder(); // IPC::Message handlers. - void OnBufferPresented(uint32 sync_point); + void OnBufferPresented(bool presented, uint32 sync_point); void OnResizeViewACK(); void OnSetFrontSurfaceIsProtected(bool is_protected, uint32 protection_state_id); @@ -177,7 +177,8 @@ class PassThroughImageTransportSurface virtual bool OnMakeCurrent(gfx::GLContext* context) OVERRIDE; // ImageTransportSurface implementation. - virtual void OnBufferPresented(uint32 sync_point) OVERRIDE; + virtual void OnBufferPresented(bool presented, + uint32 sync_point) OVERRIDE; virtual void OnResizeViewACK() OVERRIDE; virtual void OnResize(gfx::Size size) OVERRIDE; virtual gfx::Size GetSize() OVERRIDE; diff --git a/content/common/gpu/image_transport_surface_mac.cc b/content/common/gpu/image_transport_surface_mac.cc index bb9defe..0070c0e 100644 --- a/content/common/gpu/image_transport_surface_mac.cc +++ b/content/common/gpu/image_transport_surface_mac.cc @@ -57,7 +57,8 @@ class IOSurfaceImageTransportSurface : public gfx::NoOpGLSurfaceCGL, protected: // ImageTransportSurface implementation - virtual void OnBufferPresented(uint32 sync_point) OVERRIDE; + virtual void OnBufferPresented(bool presented, + uint32 sync_point) OVERRIDE; virtual void OnResizeViewACK() OVERRIDE; virtual void OnResize(gfx::Size size) OVERRIDE; @@ -273,7 +274,8 @@ gfx::Size IOSurfaceImageTransportSurface::GetSize() { return size_; } -void IOSurfaceImageTransportSurface::OnBufferPresented(uint32 sync_point) { +void IOSurfaceImageTransportSurface::OnBufferPresented(bool presented, + uint32 sync_point) { DCHECK(is_swap_buffers_pending_); is_swap_buffers_pending_ = false; if (did_unschedule_) { diff --git a/content/common/gpu/image_transport_surface_win.cc b/content/common/gpu/image_transport_surface_win.cc index bc4953a..930c888 100644 --- a/content/common/gpu/image_transport_surface_win.cc +++ b/content/common/gpu/image_transport_surface_win.cc @@ -50,7 +50,7 @@ class PbufferImageTransportSurface protected: // ImageTransportSurface implementation - virtual void OnBufferPresented(uint32 sync_point) OVERRIDE; + virtual void OnBufferPresented(bool presented, uint32 sync_point) OVERRIDE; virtual void OnResizeViewACK() OVERRIDE; virtual void OnResize(gfx::Size size) OVERRIDE; virtual gfx::Size GetSize() OVERRIDE; @@ -205,7 +205,8 @@ void PbufferImageTransportSurface::SendBuffersSwapped() { is_swap_buffers_pending_ = true; } -void PbufferImageTransportSurface::OnBufferPresented(uint32 sync_point) { +void PbufferImageTransportSurface::OnBufferPresented(bool presented, + uint32 sync_point) { is_swap_buffers_pending_ = false; if (did_unschedule_) { did_unschedule_ = false; diff --git a/content/common/gpu/texture_image_transport_surface.cc b/content/common/gpu/texture_image_transport_surface.cc index ab0a276..ec9aeb4 100644 --- a/content/common/gpu/texture_image_transport_surface.cc +++ b/content/common/gpu/texture_image_transport_surface.cc @@ -46,7 +46,8 @@ TextureImageTransportSurface::TextureImageTransportSurface( handle_(handle), parent_stub_(NULL), is_swap_buffers_pending_(false), - did_unschedule_(false) { + did_unschedule_(false), + did_flip_(false) { helper_.reset(new ImageTransportHelper(this, manager, stub, @@ -323,7 +324,7 @@ bool TextureImageTransportSurface::PostSubBuffer( region_to_copy.width(), region_to_copy.height()); } } - } else { + } else if (!surfaces_same_size && did_flip_) { DCHECK(new_damage_rect == gfx::Rect(expected_size)); } @@ -391,21 +392,35 @@ void TextureImageTransportSurface::OnSetFrontSurfaceIsProtected( } } -void TextureImageTransportSurface::OnBufferPresented(uint32 sync_point) { +void TextureImageTransportSurface::OnBufferPresented(bool presented, + uint32 sync_point) { if (sync_point == 0) { - BufferPresentedImpl(); + BufferPresentedImpl(presented); } else { helper_->manager()->sync_point_manager()->AddSyncPointCallback( sync_point, base::Bind(&TextureImageTransportSurface::BufferPresentedImpl, - this->AsWeakPtr())); + this->AsWeakPtr(), + presented)); } } -void TextureImageTransportSurface::BufferPresentedImpl() { +void TextureImageTransportSurface::BufferPresentedImpl(bool presented) { DCHECK(is_swap_buffers_pending_); is_swap_buffers_pending_ = false; + if (presented) { + // If we had not flipped, the two frame damage tracking is inconsistent. + // So conservatively take the whole frame. + if (!did_flip_) + previous_damage_rect_ = gfx::Rect(textures_[front()].size); + } else { + front_ = back(); + previous_damage_rect_ = gfx::Rect(0, 0, 0, 0); + } + + did_flip_ = presented; + // We're relying on the fact that the parent context is // finished with it's context when it inserts the sync point that // triggers this callback. diff --git a/content/common/gpu/texture_image_transport_surface.h b/content/common/gpu/texture_image_transport_surface.h index 0d19d0f..150b585 100644 --- a/content/common/gpu/texture_image_transport_surface.h +++ b/content/common/gpu/texture_image_transport_surface.h @@ -48,6 +48,7 @@ class TextureImageTransportSurface : protected: // ImageTransportSurface implementation. virtual void OnBufferPresented( + bool presented, uint32 sync_point) OVERRIDE; virtual void OnResizeViewACK() OVERRIDE; virtual void OnSetFrontSurfaceIsProtected( @@ -83,7 +84,7 @@ class TextureImageTransportSurface : void ReleaseTexture(int id); void ReleaseParentStub(); void AdjustFrontBufferAllocation(); - void BufferPresentedImpl(); + void BufferPresentedImpl(bool presented); int front() const { return front_; } int back() const { return 1 - front_; } @@ -122,6 +123,10 @@ class TextureImageTransportSurface : // Whether we unscheduled command buffer because of pending SwapBuffers. bool did_unschedule_; + // Whether or not the buffer flip went through browser side on the last + // swap or post sub buffer. + bool did_flip_; + DISALLOW_COPY_AND_ASSIGN(TextureImageTransportSurface); }; diff --git a/ui/aura/bench/bench_main.cc b/ui/aura/bench/bench_main.cc index b75a5d4..f105854 100644 --- a/ui/aura/bench/bench_main.cc +++ b/ui/aura/bench/bench_main.cc @@ -95,8 +95,6 @@ class BenchCompositorObserver : public ui::CompositorObserver { virtual void OnCompositingDidCommit(ui::Compositor* compositor) OVERRIDE {} - virtual void OnCompositingWillStart(Compositor* compositor) OVERRIDE {} - virtual void OnCompositingStarted(Compositor* compositor) OVERRIDE {} virtual void OnCompositingEnded(Compositor* compositor) OVERRIDE { @@ -120,6 +118,9 @@ class BenchCompositorObserver : public ui::CompositorObserver { virtual void OnCompositingAborted(Compositor* compositor) OVERRIDE {} + virtual void OnCompositingLockStateChanged( + Compositor* compositor) OVERRIDE {} + virtual void Draw() {} int frames() const { return frames_; } diff --git a/ui/aura/root_window.cc b/ui/aura/root_window.cc index 39b07b7..5634566 100644 --- a/ui/aura/root_window.cc +++ b/ui/aura/root_window.cc @@ -50,8 +50,6 @@ namespace { const char kRootWindowForAcceleratedWidget[] = "__AURA_ROOT_WINDOW_ACCELERATED_WIDGET__"; -const int kCompositorLockTimeoutMs = 67; - // Returns true if |target| has a non-client (frame) component at |location|, // in window coordinates. bool IsNonClientLocation(Window* target, const gfx::Point& location) { @@ -96,25 +94,6 @@ RootWindowHost* CreateHost(RootWindow* root_window, } // namespace -CompositorLock::CompositorLock(RootWindow* root_window) - : root_window_(root_window) { - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&CompositorLock::CancelLock, AsWeakPtr()), - base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs)); -} - -CompositorLock::~CompositorLock() { - CancelLock(); -} - -void CompositorLock::CancelLock() { - if (!root_window_) - return; - root_window_->UnlockCompositor(); - root_window_ = NULL; -} - RootWindow::CreateParams::CreateParams(const gfx::Rect& a_initial_bounds) : initial_bounds(a_initial_bounds), host(NULL) { @@ -143,9 +122,7 @@ RootWindow::RootWindow(const CreateParams& params) draw_on_compositing_end_(false), defer_draw_scheduling_(false), mouse_move_hold_count_(0), - ALLOW_THIS_IN_INITIALIZER_LIST(held_mouse_event_factory_(this)), - compositor_lock_(NULL), - draw_on_compositor_unlock_(false) { + ALLOW_THIS_IN_INITIALIZER_LIST(held_mouse_event_factory_(this)) { SetName("RootWindow"); compositor_.reset(new ui::Compositor(this, host_->GetAcceleratedWidget())); @@ -158,12 +135,6 @@ RootWindow::RootWindow(const CreateParams& params) } RootWindow::~RootWindow() { - if (compositor_lock_) { - // No need to schedule a draw, we're going away. - draw_on_compositor_unlock_ = false; - compositor_lock_->CancelLock(); - DCHECK(!compositor_lock_); - } compositor_->RemoveObserver(this); // Make sure to destroy the compositor before terminating so that state is // cleared and we don't hit asserts. @@ -279,10 +250,6 @@ void RootWindow::Draw() { draw_on_compositing_end_ = true; return; } - if (compositor_lock_) { - draw_on_compositor_unlock_ = true; - return; - } waiting_on_compositing_end_ = true; TRACE_EVENT_ASYNC_BEGIN0("ui", "RootWindow::Draw", @@ -412,6 +379,7 @@ void RootWindow::HoldMouseMoves() { if (!mouse_move_hold_count_) held_mouse_event_factory_.InvalidateWeakPtrs(); ++mouse_move_hold_count_; + TRACE_EVENT_ASYNC_BEGIN0("ui", "RootWindow::HoldMouseMoves", this); } void RootWindow::ReleaseMouseMoves() { @@ -428,12 +396,7 @@ void RootWindow::ReleaseMouseMoves() { base::Bind(&RootWindow::DispatchHeldMouseMove, held_mouse_event_factory_.GetWeakPtr())); } -} - -scoped_refptr<CompositorLock> RootWindow::GetCompositorLock() { - if (!compositor_lock_) - compositor_lock_ = new CompositorLock(this); - return compositor_lock_; + TRACE_EVENT_ASYNC_END0("ui", "RootWindow::HoldMouseMoves", this); } void RootWindow::SetFocusWhenShown(bool focused) { @@ -486,9 +449,7 @@ ui::EventTarget* RootWindow::GetParentTarget() { // RootWindow, ui::CompositorDelegate implementation: void RootWindow::ScheduleDraw() { - if (compositor_lock_) { - draw_on_compositor_unlock_ = true; - } else if (!defer_draw_scheduling_) { + if (!defer_draw_scheduling_) { defer_draw_scheduling_ = true; MessageLoop::current()->PostTask( FROM_HERE, @@ -502,9 +463,6 @@ void RootWindow::ScheduleDraw() { void RootWindow::OnCompositingDidCommit(ui::Compositor*) { } -void RootWindow::OnCompositingWillStart(ui::Compositor*) { -} - void RootWindow::OnCompositingStarted(ui::Compositor*) { } @@ -525,6 +483,9 @@ void RootWindow::OnCompositingEnded(ui::Compositor*) { void RootWindow::OnCompositingAborted(ui::Compositor*) { } +void RootWindow::OnCompositingLockStateChanged(ui::Compositor*) { +} + //////////////////////////////////////////////////////////////////////////////// // RootWindow, ui::LayerDelegate implementation: @@ -1062,13 +1023,4 @@ void RootWindow::SynthesizeMouseMoveEvent() { #endif } -void RootWindow::UnlockCompositor() { - DCHECK(compositor_lock_); - compositor_lock_ = NULL; - if (draw_on_compositor_unlock_) { - draw_on_compositor_unlock_ = false; - ScheduleDraw(); - } -} - } // namespace aura diff --git a/ui/aura/root_window.h b/ui/aura/root_window.h index 7631d96..2d07627 100644 --- a/ui/aura/root_window.h +++ b/ui/aura/root_window.h @@ -50,31 +50,6 @@ class RootWindow; class RootWindowHost; class RootWindowObserver; -// This class represents a lock on the compositor, that can be used to prevent a -// compositing pass from happening while we're waiting for an asynchronous -// event. The typical use case is when waiting for a renderer to produce a frame -// at the right size. The caller keeps a reference on this object, and drops the -// reference once it desires to release the lock. -// Note however that the lock is canceled after a short timeout to ensure -// responsiveness of the UI, so the compositor tree should be kept in a -// "reasonable" state while the lock is held. -// Don't instantiate this class directly, use RootWindow::GetCompositorLock. -class AURA_EXPORT CompositorLock - : public base::RefCounted<CompositorLock>, - public base::SupportsWeakPtr<CompositorLock> { - private: - friend class base::RefCounted<CompositorLock>; - friend class RootWindow; - - explicit CompositorLock(RootWindow* root_window); - ~CompositorLock(); - - void CancelLock(); - - RootWindow* root_window_; - DISALLOW_COPY_AND_ASSIGN(CompositorLock); -}; - // RootWindow is responsible for hosting a set of windows. class AURA_EXPORT RootWindow : public ui::CompositorDelegate, public ui::CompositorObserver, @@ -235,9 +210,6 @@ class AURA_EXPORT RootWindow : public ui::CompositorDelegate, void HoldMouseMoves(); void ReleaseMouseMoves(); - // Creates a compositor lock. - scoped_refptr<CompositorLock> GetCompositorLock(); - // Sets if the window should be focused when shown. void SetFocusWhenShown(bool focus_when_shown); @@ -262,10 +234,10 @@ class AURA_EXPORT RootWindow : public ui::CompositorDelegate, // Overridden from ui::CompositorObserver: virtual void OnCompositingDidCommit(ui::Compositor*) OVERRIDE; - virtual void OnCompositingWillStart(ui::Compositor*) OVERRIDE; virtual void OnCompositingStarted(ui::Compositor*) OVERRIDE; virtual void OnCompositingEnded(ui::Compositor*) OVERRIDE; virtual void OnCompositingAborted(ui::Compositor*) OVERRIDE; + virtual void OnCompositingLockStateChanged(ui::Compositor*) OVERRIDE; // Overridden from ui::LayerDelegate: virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE; @@ -285,7 +257,6 @@ class AURA_EXPORT RootWindow : public ui::CompositorDelegate, private: friend class Window; - friend class CompositorLock; // Called whenever the mouse moves, tracks the current |mouse_moved_handler_|, // sending exited and entered events as its value changes. @@ -361,9 +332,6 @@ class AURA_EXPORT RootWindow : public ui::CompositorDelegate, // current mouse location. void SynthesizeMouseMoveEvent(); - // Called by CompositorLock. - void UnlockCompositor(); - scoped_ptr<ui::Compositor> compositor_; scoped_ptr<RootWindowHost> host_; @@ -410,9 +378,6 @@ class AURA_EXPORT RootWindow : public ui::CompositorDelegate, scoped_ptr<ui::ViewProp> prop_; - CompositorLock* compositor_lock_; - bool draw_on_compositor_unlock_; - DISALLOW_COPY_AND_ASSIGN(RootWindow); }; diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index 31f47c7..f1c1b25 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc @@ -6,7 +6,9 @@ #include <algorithm> +#include "base/bind.h" #include "base/command_line.h" +#include "base/message_loop.h" #include "base/threading/thread_restrictions.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/WebKit/Source/Platform/chromium/public/Platform.h" @@ -40,6 +42,8 @@ bool test_compositor_enabled = false; ui::ContextFactory* g_context_factory = NULL; +const int kCompositorLockTimeoutMs = 67; + } // namespace namespace ui { @@ -132,6 +136,25 @@ Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor) Texture::~Texture() { } +CompositorLock::CompositorLock(Compositor* compositor) + : compositor_(compositor) { + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&CompositorLock::CancelLock, AsWeakPtr()), + base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs)); +} + +CompositorLock::~CompositorLock() { + CancelLock(); +} + +void CompositorLock::CancelLock() { + if (!compositor_) + return; + compositor_->UnlockCompositor(); + compositor_ = NULL; +} + Compositor::Compositor(CompositorDelegate* delegate, gfx::AcceleratedWidget widget) : delegate_(delegate), @@ -141,7 +164,8 @@ Compositor::Compositor(CompositorDelegate* delegate, device_scale_factor_(0.0f), last_started_frame_(0), last_ended_frame_(0), - disable_schedule_composite_(false) { + disable_schedule_composite_(false), + compositor_lock_(NULL) { WebKit::WebCompositorSupport* compositor_support = WebKit::Platform::current()->compositorSupport(); root_web_layer_.reset(compositor_support->createLayer()); @@ -161,6 +185,9 @@ Compositor::Compositor(CompositorDelegate* delegate, } Compositor::~Compositor() { + CancelCompositorLock(); + DCHECK(!compositor_lock_); + // Don't call |CompositorDelegate::ScheduleDraw| from this point. delegate_ = NULL; if (root_layer_) @@ -230,15 +257,12 @@ void Compositor::Draw(bool force_clear) { return; last_started_frame_++; - if (!g_compositor_thread) - FOR_EACH_OBSERVER(CompositorObserver, - observer_list_, - OnCompositingWillStart(this)); - - // TODO(nduca): Temporary while compositor calls - // compositeImmediately() directly. - layout(); - host_->composite(); + if (!g_compositor_thread && !IsLocked()) { + // TODO(nduca): Temporary while compositor calls + // compositeImmediately() directly. + layout(); + host_->composite(); + } if (!g_compositor_thread && !swap_posted_) NotifyEnd(); } @@ -257,6 +281,7 @@ bool Compositor::ReadPixels(SkBitmap* bitmap, bitmap->allocPixels(); SkAutoLockPixels lock_image(*bitmap); unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels()); + CancelCompositorLock(); return host_->compositeAndReadback(pixels, bounds_in_pixel); } @@ -287,10 +312,6 @@ bool Compositor::HasObserver(CompositorObserver* observer) { return observer_list_.HasObserver(observer); } -bool Compositor::IsThreaded() const { - return g_compositor_thread != NULL; -} - void Compositor::OnSwapBuffersPosted() { swap_posted_ = true; } @@ -384,21 +405,14 @@ WebKit::WebCompositorOutputSurface* Compositor::createOutputSurface() { void Compositor::didRecreateOutputSurface(bool success) { } -// Called once per draw in single-threaded compositor mode and potentially -// many times between draws in the multi-threaded compositor mode. void Compositor::didCommit() { + DCHECK(!IsLocked()); FOR_EACH_OBSERVER(CompositorObserver, observer_list_, OnCompositingDidCommit(this)); } void Compositor::didCommitAndDrawFrame() { - // TODO(backer): Plumb through an earlier impl side will start. - if (g_compositor_thread) - FOR_EACH_OBSERVER(CompositorObserver, - observer_list_, - OnCompositingWillStart(this)); - FOR_EACH_OBSERVER(CompositorObserver, observer_list_, OnCompositingStarted(this)); @@ -413,6 +427,33 @@ void Compositor::scheduleComposite() { ScheduleDraw(); } +scoped_refptr<CompositorLock> Compositor::GetCompositorLock() { + if (!compositor_lock_) { + compositor_lock_ = new CompositorLock(this); + if (g_compositor_thread) + host_->setDeferCommits(true); + FOR_EACH_OBSERVER(CompositorObserver, + observer_list_, + OnCompositingLockStateChanged(this)); + } + return compositor_lock_; +} + +void Compositor::UnlockCompositor() { + DCHECK(compositor_lock_); + compositor_lock_ = NULL; + if (g_compositor_thread) + host_->setDeferCommits(false); + FOR_EACH_OBSERVER(CompositorObserver, + observer_list_, + OnCompositingLockStateChanged(this)); +} + +void Compositor::CancelCompositorLock() { + if (compositor_lock_) + compositor_lock_->CancelLock(); +} + void Compositor::NotifyEnd() { last_ended_frame_++; FOR_EACH_OBSERVER(CompositorObserver, diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index c5dc3ba..f3720bc 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h @@ -126,6 +126,32 @@ class COMPOSITOR_EXPORT CompositorDelegate { virtual ~CompositorDelegate() {} }; +// This class represents a lock on the compositor, that can be used to prevent +// commits to the compositor tree while we're waiting for an asynchronous +// event. The typical use case is when waiting for a renderer to produce a frame +// at the right size. The caller keeps a reference on this object, and drops the +// reference once it desires to release the lock. +// Note however that the lock is cancelled after a short timeout to ensure +// responsiveness of the UI, so the compositor tree should be kept in a +// "reasonable" state while the lock is held. +// Don't instantiate this class directly, use Compositor::GetCompositorLock. +class COMPOSITOR_EXPORT CompositorLock + : public base::RefCounted<CompositorLock>, + public base::SupportsWeakPtr<CompositorLock> { + private: + friend class base::RefCounted<CompositorLock>; + friend class Compositor; + + explicit CompositorLock(Compositor* compositor); + ~CompositorLock(); + + void CancelLock(); + + Compositor* compositor_; + DISALLOW_COPY_AND_ASSIGN(CompositorLock); +}; + + // Compositor object to take care of GPU painting. // A Browser compositor object is responsible for generating the final // displayable form of pixels comprising a single widget's contents. It draws an @@ -196,9 +222,9 @@ class COMPOSITOR_EXPORT Compositor // and the OnCompositingEnded. bool DrawPending() const { return swap_posted_; } - // Returns whether the drawing is issued from a separate thread - // (i.e. |Compositor::Initialize(true)| was called). - bool IsThreaded() const; + // Creates a compositor lock. Returns NULL if it is not possible to lock at + // this time (i.e. we're waiting to complete a previous unlock). + scoped_refptr<CompositorLock> GetCompositorLock(); // Internal functions, called back by command-buffer contexts on swap buffer // events. @@ -227,8 +253,17 @@ class COMPOSITOR_EXPORT Compositor int last_started_frame() { return last_started_frame_; } int last_ended_frame() { return last_ended_frame_; } + bool IsLocked() { return compositor_lock_ != NULL; } + private: friend class base::RefCounted<Compositor>; + friend class CompositorLock; + + // Called by CompositorLock. + void UnlockCompositor(); + + // Called to release any pending CompositorLock + void CancelCompositorLock(); // Notifies the compositor that compositing is complete. void NotifyEnd(); @@ -258,6 +293,8 @@ class COMPOSITOR_EXPORT Compositor bool disable_schedule_composite_; + CompositorLock* compositor_lock_; + DISALLOW_COPY_AND_ASSIGN(Compositor); }; diff --git a/ui/compositor/compositor_observer.h b/ui/compositor/compositor_observer.h index 830f170..4157453 100644 --- a/ui/compositor/compositor_observer.h +++ b/ui/compositor/compositor_observer.h @@ -19,12 +19,10 @@ class COMPOSITOR_EXPORT CompositorObserver { // composite. In the multi-threaded case, many commits may happen between // two successive composites. In the single-threaded, a single commit // between two composites (just before the composite as part of the - // composite cycle). + // composite cycle). If the compositor is locked, it will not send this + // this signal. virtual void OnCompositingDidCommit(Compositor* compositor) = 0; - // Called when compositing will start. - virtual void OnCompositingWillStart(Compositor* compositor) = 0; - // Called when compositing started: it has taken all the layer changes into // account and has issued the graphics commands. virtual void OnCompositingStarted(Compositor* compositor) = 0; @@ -35,6 +33,9 @@ class COMPOSITOR_EXPORT CompositorObserver { // Called when compositing is aborted (e.g. lost graphics context). virtual void OnCompositingAborted(Compositor* compositor) = 0; + // Called when the compositor lock state changes. + virtual void OnCompositingLockStateChanged(Compositor* compositor) = 0; + protected: virtual ~CompositorObserver() {} }; diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc index f246997..7d2a1f6 100644 --- a/ui/compositor/layer_unittest.cc +++ b/ui/compositor/layer_unittest.cc @@ -323,13 +323,12 @@ class NullLayerDelegate : public LayerDelegate { class TestCompositorObserver : public CompositorObserver { public: TestCompositorObserver() - : will_start_(false), started_(false), ended_(false), aborted_(false) {} + : started_(false), ended_(false), aborted_(false) {} - bool notified() const { return will_start_ && started_ && ended_; } + bool notified() const { return started_ && ended_; } bool aborted() const { return aborted_; } void Reset() { - will_start_ = false; started_ = false; ended_ = false; aborted_ = false; @@ -339,10 +338,6 @@ class TestCompositorObserver : public CompositorObserver { virtual void OnCompositingDidCommit(Compositor* compositor) OVERRIDE { } - virtual void OnCompositingWillStart(Compositor* compositor) OVERRIDE { - will_start_ = true; - } - virtual void OnCompositingStarted(Compositor* compositor) OVERRIDE { started_ = true; } @@ -355,7 +350,9 @@ class TestCompositorObserver : public CompositorObserver { aborted_ = true; } - bool will_start_; + virtual void OnCompositingLockStateChanged(Compositor* compositor) OVERRIDE { + } + bool started_; bool ended_; bool aborted_; diff --git a/webkit/compositor_bindings/web_layer_tree_view_impl.cc b/webkit/compositor_bindings/web_layer_tree_view_impl.cc index e61a166..d1a453e 100644 --- a/webkit/compositor_bindings/web_layer_tree_view_impl.cc +++ b/webkit/compositor_bindings/web_layer_tree_view_impl.cc @@ -165,6 +165,11 @@ void WebLayerTreeViewImpl::finishAllRendering() m_layerTreeHost->finishAllRendering(); } +void WebLayerTreeViewImpl::setDeferCommits(bool deferCommits) +{ + m_layerTreeHost->setDeferCommits(deferCommits); +} + void WebLayerTreeViewImpl::renderingStats(WebRenderingStats& stats) const { RenderingStats ccStats; diff --git a/webkit/compositor_bindings/web_layer_tree_view_impl.h b/webkit/compositor_bindings/web_layer_tree_view_impl.h index 9b0ecbf..dace36c 100644 --- a/webkit/compositor_bindings/web_layer_tree_view_impl.h +++ b/webkit/compositor_bindings/web_layer_tree_view_impl.h @@ -46,6 +46,7 @@ public: virtual void updateAnimations(double frameBeginTime) OVERRIDE; virtual bool compositeAndReadback(void *pixels, const WebRect&) OVERRIDE; virtual void finishAllRendering() OVERRIDE; + virtual void setDeferCommits(bool deferCommits) OVERRIDE; virtual void renderingStats(WebRenderingStats&) const OVERRIDE; virtual void setFontAtlas(SkBitmap, WebRect asciiToRectTable[128], int fontHeight) OVERRIDE; virtual void loseCompositorContext(int numTimes) OVERRIDE; |