diff options
38 files changed, 648 insertions, 448 deletions
diff --git a/android_webview/browser/browser_view_renderer.cc b/android_webview/browser/browser_view_renderer.cc index 6b4ee92..928a62b7 100644 --- a/android_webview/browser/browser_view_renderer.cc +++ b/android_webview/browser/browser_view_renderer.cc @@ -98,8 +98,6 @@ BrowserViewRenderer::BrowserViewRenderer( on_new_picture_enable_(false), clear_view_(false), offscreen_pre_raster_(false), - compositor_needs_continuous_invalidate_(false), - block_invalidates_(false), fallback_tick_pending_(false) { } @@ -198,6 +196,7 @@ bool BrowserViewRenderer::CanOnDraw() { bool BrowserViewRenderer::OnDrawHardware() { TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware"); + shared_renderer_state_.InitializeHardwareDrawIfNeededOnUI(); if (!CanOnDraw()) { @@ -220,6 +219,8 @@ bool BrowserViewRenderer::OnDrawHardware() { } bool BrowserViewRenderer::CompositeHw() { + CancelFallbackTick(); + ReturnResourceFromParent(); compositor_->SetMemoryPolicy(CalculateDesiredMemoryPolicy()); @@ -263,7 +264,6 @@ bool BrowserViewRenderer::CompositeHw() { transform_for_tile_priority, offscreen_pre_raster_, parent_draw_constraints.is_layer)); - DidComposite(); // Uncommitted frame can happen with consecutive fallback ticks. ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI()); shared_renderer_state_.SetCompositorFrameOnUI(child_frame.Pass()); @@ -271,7 +271,7 @@ bool BrowserViewRenderer::CompositeHw() { } void BrowserViewRenderer::UpdateParentDrawConstraints() { - EnsureContinuousInvalidation(true); + PostInvalidateWithFallback(); ParentCompositorDrawConstraints parent_draw_constraints = shared_renderer_state_.GetParentDrawConstraintsOnUI(); client_->ParentDrawConstraintsUpdated(parent_draw_constraints); @@ -342,7 +342,7 @@ void BrowserViewRenderer::ClearView() { clear_view_ = true; // Always invalidate ignoring the compositor to actually clear the webview. - EnsureContinuousInvalidation(true); + PostInvalidateWithFallback(); } void BrowserViewRenderer::SetOffscreenPreRaster(bool enable) { @@ -357,7 +357,7 @@ void BrowserViewRenderer::SetIsPaused(bool paused) { "paused", paused); is_paused_ = paused; - EnsureContinuousInvalidation(false); + UpdateCompositorIsActive(); } void BrowserViewRenderer::SetViewVisibility(bool view_visible) { @@ -376,7 +376,7 @@ void BrowserViewRenderer::SetWindowVisibility(bool window_visible) { "window_visible", window_visible); window_visible_ = window_visible; - EnsureContinuousInvalidation(false); + UpdateCompositorIsActive(); } void BrowserViewRenderer::OnSizeChanged(int width, int height) { @@ -399,6 +399,7 @@ void BrowserViewRenderer::OnAttachedToWindow(int width, int height) { height); attached_to_window_ = true; size_.SetSize(width, height); + UpdateCompositorIsActive(); } void BrowserViewRenderer::OnDetachedFromWindow() { @@ -406,6 +407,7 @@ void BrowserViewRenderer::OnDetachedFromWindow() { shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI(); attached_to_window_ = false; DCHECK(!hardware_enabled_); + UpdateCompositorIsActive(); } void BrowserViewRenderer::ReleaseHardware() { @@ -437,6 +439,7 @@ void BrowserViewRenderer::DidInitializeCompositor( DCHECK(compositor); DCHECK(!compositor_); compositor_ = compositor; + UpdateCompositorIsActive(); } void BrowserViewRenderer::DidDestroyCompositor( @@ -446,20 +449,6 @@ void BrowserViewRenderer::DidDestroyCompositor( compositor_ = NULL; } -void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) { - if (compositor_needs_continuous_invalidate_ == invalidate) - return; - - TRACE_EVENT_INSTANT1("android_webview", - "BrowserViewRenderer::SetContinuousInvalidate", - TRACE_EVENT_SCOPE_THREAD, - "invalidate", - invalidate); - compositor_needs_continuous_invalidate_ = invalidate; - - EnsureContinuousInvalidation(false); -} - void BrowserViewRenderer::SetDipScale(float dip_scale) { dip_scale_ = dip_scale; CHECK_GT(dip_scale_, 0.f); @@ -627,13 +616,13 @@ void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll, client_->DidOverscroll(rounded_overscroll_delta); } -void BrowserViewRenderer::EnsureContinuousInvalidation(bool force_invalidate) { - // This method should be called again when any of these conditions change. - bool need_invalidate = - compositor_needs_continuous_invalidate_ || force_invalidate; - if (!need_invalidate || block_invalidates_) - return; +void BrowserViewRenderer::PostInvalidate() { + TRACE_EVENT_INSTANT0("android_webview", "BrowserViewRenderer::PostInvalidate", + TRACE_EVENT_SCOPE_THREAD); + PostInvalidateWithFallback(); +} +void BrowserViewRenderer::PostInvalidateWithFallback() { // Always call view invalidate. We rely the Android framework to ignore the // invalidate when it's not needed such as when view is not visible. client_->PostInvalidate(); @@ -646,63 +635,49 @@ void BrowserViewRenderer::EnsureContinuousInvalidation(bool force_invalidate) { // "on-screen" but that updates are not needed when in the background. bool throttle_fallback_tick = (is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_); - if (throttle_fallback_tick) - return; - block_invalidates_ = compositor_needs_continuous_invalidate_; - if (fallback_tick_pending_) + if (throttle_fallback_tick || fallback_tick_pending_) return; - // Unretained here is safe because the callbacks are cancelled when - // they are destroyed. + DCHECK(post_fallback_tick_.IsCancelled()); + DCHECK(fallback_tick_fired_.IsCancelled()); + post_fallback_tick_.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick, base::Unretained(this))); + ui_task_runner_->PostTask(FROM_HERE, post_fallback_tick_.callback()); + fallback_tick_pending_ = true; +} + +void BrowserViewRenderer::CancelFallbackTick() { + post_fallback_tick_.Cancel(); fallback_tick_fired_.Cancel(); fallback_tick_pending_ = false; - - // No need to reschedule fallback tick if compositor does not need to be - // ticked. This can happen if this is reached because force_invalidate is - // true. - if (compositor_needs_continuous_invalidate_) { - fallback_tick_pending_ = true; - ui_task_runner_->PostTask(FROM_HERE, post_fallback_tick_.callback()); - } } void BrowserViewRenderer::PostFallbackTick() { DCHECK(fallback_tick_fired_.IsCancelled()); + TRACE_EVENT0("android_webview", "BrowserViewRenderer::PostFallbackTick"); + post_fallback_tick_.Cancel(); fallback_tick_fired_.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired, base::Unretained(this))); - if (compositor_needs_continuous_invalidate_) { - ui_task_runner_->PostDelayedTask( - FROM_HERE, - fallback_tick_fired_.callback(), - base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds)); - } else { - // Pretend we just composited to unblock further invalidates. - DidComposite(); - } + ui_task_runner_->PostDelayedTask( + FROM_HERE, fallback_tick_fired_.callback(), + base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds)); } void BrowserViewRenderer::FallbackTickFired() { - TRACE_EVENT1("android_webview", - "BrowserViewRenderer::FallbackTickFired", - "compositor_needs_continuous_invalidate_", - compositor_needs_continuous_invalidate_); - + TRACE_EVENT0("android_webview", "BrowserViewRenderer::FallbackTickFired"); // This should only be called if OnDraw or DrawGL did not come in time, which - // means block_invalidates_ must still be true. - DCHECK(block_invalidates_); + // means fallback_tick_pending_ must still be true. + DCHECK(fallback_tick_pending_); + fallback_tick_fired_.Cancel(); fallback_tick_pending_ = false; - if (compositor_needs_continuous_invalidate_ && compositor_) { + if (compositor_) { if (hardware_enabled_) { CompositeHw(); } else { ForceFakeCompositeSW(); } - } else { - // Pretend we just composited to unblock further invalidates. - DidComposite(); } } @@ -717,18 +692,15 @@ void BrowserViewRenderer::ForceFakeCompositeSW() { bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) { DCHECK(compositor_); + CancelFallbackTick(); ReturnResourceFromParent(); - bool result = compositor_->DemandDrawSw(canvas); - DidComposite(); - return result; + return compositor_->DemandDrawSw(canvas); } -void BrowserViewRenderer::DidComposite() { - block_invalidates_ = false; - post_fallback_tick_.Cancel(); - fallback_tick_fired_.Cancel(); - fallback_tick_pending_ = false; - EnsureContinuousInvalidation(false); +void BrowserViewRenderer::UpdateCompositorIsActive() { + if (compositor_) + compositor_->SetIsActive(!is_paused_ && + (!attached_to_window_ || window_visible_)); } std::string BrowserViewRenderer::ToString() const { @@ -738,10 +710,8 @@ std::string BrowserViewRenderer::ToString() const { base::StringAppendF(&str, "window_visible: %d ", window_visible_); base::StringAppendF(&str, "dip_scale: %f ", dip_scale_); base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_); - base::StringAppendF(&str, - "compositor_needs_continuous_invalidate: %d ", - compositor_needs_continuous_invalidate_); - base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_); + base::StringAppendF(&str, "fallback_tick_pending: %d ", + fallback_tick_pending_); base::StringAppendF(&str, "view size: %s ", size_.ToString().c_str()); base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_); base::StringAppendF(&str, diff --git a/android_webview/browser/browser_view_renderer.h b/android_webview/browser/browser_view_renderer.h index 843529b..308abd4 100644 --- a/android_webview/browser/browser_view_renderer.h +++ b/android_webview/browser/browser_view_renderer.h @@ -96,7 +96,7 @@ class BrowserViewRenderer : public content::SynchronousCompositorClient { content::SynchronousCompositor* compositor) override; void DidDestroyCompositor( content::SynchronousCompositor* compositor) override; - void SetContinuousInvalidate(bool invalidate) override; + void PostInvalidate() override; void DidUpdateContent() override; gfx::Vector2dF GetTotalRootLayerScrollOffset() override; void UpdateRootLayerState(const gfx::Vector2dF& total_scroll_offset_dip, @@ -116,12 +116,13 @@ class BrowserViewRenderer : public content::SynchronousCompositorClient { private: void SetTotalRootLayerScrollOffset(gfx::Vector2dF new_value_dip); bool CanOnDraw(); - // Checks the continuous invalidate and block invalidate state, and schedule - // invalidates appropriately. If |force_invalidate| is true, then send a view - // invalidate regardless of compositor expectation. - void EnsureContinuousInvalidation(bool force_invalidate); + // Posts an invalidate with fallback tick. All invalidates posted while an + // invalidate is pending will be posted as a single invalidate after the + // pending invalidate is done. + void PostInvalidateWithFallback(); + void CancelFallbackTick(); + void UpdateCompositorIsActive(); bool CompositeSW(SkCanvas* canvas); - void DidComposite(); scoped_refptr<base::trace_event::ConvertableToTraceFormat> RootLayerStateAsValue(const gfx::Vector2dF& total_scroll_offset_dip, const gfx::SizeF& scrollable_size_dip); @@ -145,6 +146,7 @@ class BrowserViewRenderer : public content::SynchronousCompositorClient { gfx::Vector2d max_scroll_offset() const; size_t CalculateDesiredMemoryPolicy(); + // For debug tracing or logging. Return the string representation of this // view renderer's state. std::string ToString() const; @@ -170,14 +172,6 @@ class BrowserViewRenderer : public content::SynchronousCompositorClient { gfx::Vector2d last_on_draw_scroll_offset_; gfx::Rect last_on_draw_global_visible_rect_; - // When true, we should continuously invalidate and keep drawing, for example - // to drive animation. This value is set by the compositor and should always - // reflect the expectation of the compositor and not be reused for other - // states. - bool compositor_needs_continuous_invalidate_; - - // Used to block additional invalidates while one is already pending. - bool block_invalidates_; base::CancelableClosure post_fallback_tick_; base::CancelableClosure fallback_tick_fired_; diff --git a/android_webview/browser/browser_view_renderer_client.h b/android_webview/browser/browser_view_renderer_client.h index 4c2f36f..c4bf8f2 100644 --- a/android_webview/browser/browser_view_renderer_client.h +++ b/android_webview/browser/browser_view_renderer_client.h @@ -26,6 +26,8 @@ class BrowserViewRendererClient { virtual void OnNewPicture() = 0; // Called to trigger view invalidations. + // This calls postInvalidateOnAnimation if outside of a vsync, otherwise it + // calls invalidate. virtual void PostInvalidate() = 0; // Call postInvalidateOnAnimation for invalidations. This is only used to diff --git a/android_webview/browser/browser_view_renderer_unittest.cc b/android_webview/browser/browser_view_renderer_unittest.cc index e4c6eac..634e1f3 100644 --- a/android_webview/browser/browser_view_renderer_unittest.cc +++ b/android_webview/browser/browser_view_renderer_unittest.cc @@ -9,13 +9,7 @@ namespace android_webview { class SmokeTest : public RenderingTest { - void StartTest() override { - browser_view_renderer_->SetContinuousInvalidate(true); - } - - void WillOnDraw() override { - browser_view_renderer_->SetContinuousInvalidate(false); - } + void StartTest() override { browser_view_renderer_->PostInvalidate(); } void DidDrawOnRT(SharedRendererState* functor) override { EndTest(); @@ -26,25 +20,20 @@ RENDERING_TEST_F(SmokeTest); class ClearViewTest : public RenderingTest { public: - ClearViewTest() : on_draw_count_(0u) {} + ClearViewTest() : on_draw_count_(0) {} void StartTest() override { - browser_view_renderer_->SetContinuousInvalidate(true); + browser_view_renderer_->PostInvalidate(); browser_view_renderer_->ClearView(); } - void WillOnDraw() override { - on_draw_count_++; - if (on_draw_count_ == 2u) { - browser_view_renderer_->SetContinuousInvalidate(false); - } - } - void DidOnDraw(bool success) override { - if (on_draw_count_ == 1u) { + on_draw_count_++; + if (on_draw_count_ == 1) { // First OnDraw should be skipped due to ClearView. EXPECT_FALSE(success); browser_view_renderer_->DidUpdateContent(); // Unset ClearView. + browser_view_renderer_->PostInvalidate(); } else { // Following OnDraws should succeed. EXPECT_TRUE(success); @@ -55,25 +44,23 @@ class ClearViewTest : public RenderingTest { EndTest(); } private: - size_t on_draw_count_; + int on_draw_count_; }; RENDERING_TEST_F(ClearViewTest); class TestAnimateInAndOutOfScreen : public RenderingTest { public: - TestAnimateInAndOutOfScreen() - : on_draw_count_(0u), draw_gl_count_on_rt_(0u) {} + TestAnimateInAndOutOfScreen() : on_draw_count_(0), draw_gl_count_on_rt_(0) {} void StartTest() override { new_constraints_ = ParentCompositorDrawConstraints( false, gfx::Transform(), gfx::Rect(window_->surface_size())); new_constraints_.transform.Scale(2.0, 2.0); - browser_view_renderer_->SetContinuousInvalidate(true); + browser_view_renderer_->PostInvalidate(); } void WillOnDraw() override { - browser_view_renderer_->SetContinuousInvalidate(false); // Step 0: A single onDraw on screen. The parent draw constraints // of the BVR will updated to be the initial constraints. // Step 1: A single onDrraw off screen. The parent draw constraints of the @@ -81,7 +68,7 @@ class TestAnimateInAndOutOfScreen : public RenderingTest { // Step 2: This onDraw is to introduce the DrawGL that animates the // webview onto the screen on render thread. End the test when the parent // draw constraints of BVR is updated to initial constraints. - if (on_draw_count_ == 1u || on_draw_count_ == 2u) + if (on_draw_count_ == 1 || on_draw_count_ == 2) browser_view_renderer_->PrepareToDraw(gfx::Vector2d(), gfx::Rect()); } @@ -92,7 +79,7 @@ class TestAnimateInAndOutOfScreen : public RenderingTest { bool WillDrawOnRT(SharedRendererState* functor, AwDrawGLInfo* draw_info) override { - if (draw_gl_count_on_rt_ == 1u) { + if (draw_gl_count_on_rt_ == 1) { draw_gl_count_on_rt_++; ui_proxy_->PostTask(FROM_HERE, base::Bind(&RenderingTest::PostInvalidate, base::Unretained(this))); @@ -104,7 +91,7 @@ class TestAnimateInAndOutOfScreen : public RenderingTest { draw_info->is_layer = false; gfx::Transform transform; - if (draw_gl_count_on_rt_ == 0u) + if (draw_gl_count_on_rt_ == 0) transform = new_constraints_.transform; transform.matrix().asColMajorf(draw_info->transform); @@ -145,8 +132,8 @@ class TestAnimateInAndOutOfScreen : public RenderingTest { } private: - size_t on_draw_count_; - size_t draw_gl_count_on_rt_; + int on_draw_count_; + int draw_gl_count_on_rt_; ParentCompositorDrawConstraints initial_constraints_; ParentCompositorDrawConstraints new_constraints_; }; diff --git a/cc/output/begin_frame_args.cc b/cc/output/begin_frame_args.cc index 3663125..7a77be2 100644 --- a/cc/output/begin_frame_args.cc +++ b/cc/output/begin_frame_args.cc @@ -15,8 +15,6 @@ const char* BeginFrameArgs::TypeToString(BeginFrameArgsType type) { return "INVALID"; case BeginFrameArgs::NORMAL: return "NORMAL"; - case BeginFrameArgs::SYNCHRONOUS: - return "SYNCHRONOUS"; case BeginFrameArgs::MISSED: return "MISSED"; case BeginFrameArgs::BEGIN_FRAME_ARGS_TYPE_MAX: diff --git a/cc/output/begin_frame_args.h b/cc/output/begin_frame_args.h index 10f7f28..c22f7fd 100644 --- a/cc/output/begin_frame_args.h +++ b/cc/output/begin_frame_args.h @@ -40,7 +40,6 @@ struct CC_EXPORT BeginFrameArgs { enum BeginFrameArgsType { INVALID, NORMAL, - SYNCHRONOUS, MISSED, // Not a real type, but used by the IPC system. Should always remain the // *last* value in this enum. diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h index 3e3b085..b72f7fd 100644 --- a/cc/output/output_surface.h +++ b/cc/output/output_surface.h @@ -151,6 +151,12 @@ class CC_EXPORT OutputSurface { void DidLoseOutputSurface(); void SetMemoryPolicy(const ManagedMemoryPolicy& policy); + // Support for a pull-model where draws are requested by the output surface. + // + // OutputSurface::Invalidate is called by the compositor to notify that + // there's new content. + virtual void Invalidate() {} + protected: OutputSurfaceClient* client_; diff --git a/cc/output/output_surface_client.h b/cc/output/output_surface_client.h index 60750b4..03eba10 100644 --- a/cc/output/output_surface_client.h +++ b/cc/output/output_surface_client.h @@ -49,6 +49,8 @@ class CC_EXPORT OutputSurfaceClient { // valid for the lifetime of the OutputSurfaceClient or until unregisted -- // use SetTreeActivationCallback(base::Closure()) to unregister it. virtual void SetTreeActivationCallback(const base::Closure& callback) = 0; + // This allows the output surface to ask it's client for a draw. + virtual void OnDraw() = 0; protected: virtual ~OutputSurfaceClient() {} diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index 37e7c53..8a66e8e 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc @@ -109,8 +109,6 @@ Scheduler::Scheduler( base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr()); begin_impl_frame_deadline_closure_ = base::Bind( &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); - poll_for_draw_triggers_closure_ = base::Bind( - &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); advance_commit_state_closure_ = base::Bind( &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); @@ -331,37 +329,15 @@ void Scheduler::SetupNextBeginFrameIfNeeded() { // We may need to poll when we can't rely on BeginFrame to advance certain // state or to avoid deadlock. void Scheduler::SetupPollingMechanisms() { - bool needs_advance_commit_state_timer = false; - // Setup PollForAnticipatedDrawTriggers if we need to monitor state but - // aren't expecting any more BeginFrames. This should only be needed by - // the synchronous compositor when BeginFrameNeeded is false. - if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { - DCHECK(!state_machine_.SupportsProactiveBeginFrame()); - if (poll_for_draw_triggers_task_.IsCancelled()) { - poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_); - base::TimeDelta delay = begin_impl_frame_args_.IsValid() - ? begin_impl_frame_args_.interval - : BeginFrameArgs::DefaultInterval(); - task_runner_->PostDelayedTask( - FROM_HERE, poll_for_draw_triggers_task_.callback(), delay); - } - } else { - poll_for_draw_triggers_task_.Cancel(); - - // At this point we'd prefer to advance through the commit flow by - // drawing a frame, however it's possible that the frame rate controller - // will not give us a BeginFrame until the commit completes. See - // crbug.com/317430 for an example of a swap ack being held on commit. Thus - // we set a repeating timer to poll on ProcessScheduledActions until we - // successfully reach BeginFrame. Synchronous compositor does not use - // frame rate controller or have the circular wait in the bug. - if (IsBeginMainFrameSentOrStarted() && - !settings_.using_synchronous_renderer_compositor) { - needs_advance_commit_state_timer = true; - } - } - - if (needs_advance_commit_state_timer) { + // At this point we'd prefer to advance through the commit flow by + // drawing a frame, however it's possible that the frame rate controller + // will not give us a BeginFrame until the commit completes. See + // crbug.com/317430 for an example of a swap ack being held on commit. Thus + // we set a repeating timer to poll on ProcessScheduledActions until we + // successfully reach BeginFrame. Synchronous compositor does not use + // frame rate controller or have the circular wait in the bug. + if (IsBeginMainFrameSentOrStarted() && + !settings_.using_synchronous_renderer_compositor) { if (advance_commit_state_task_.IsCancelled() && begin_impl_frame_args_.IsValid()) { // Since we'd rather get a BeginImplFrame by the normal mechanism, we @@ -400,6 +376,11 @@ bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) { BeginFrameArgs adjusted_args(args); adjusted_args.deadline -= EstimatedParentDrawTime(); + if (settings_.using_synchronous_renderer_compositor) { + BeginImplFrameSynchronous(adjusted_args); + return true; + } + // We have just called SetNeedsBeginFrame(true) and the BeginFrameSource has // sent us the last BeginFrame we have missed. As we might not be able to // actually make rendering for this call, handle it like a "retro frame". @@ -410,17 +391,12 @@ bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) { return true; } - bool should_defer_begin_frame; - if (settings_.using_synchronous_renderer_compositor) { - should_defer_begin_frame = false; - } else { - should_defer_begin_frame = - !begin_retro_frame_args_.empty() || - !begin_retro_frame_task_.IsCancelled() || - !frame_source_->NeedsBeginFrames() || - (state_machine_.begin_impl_frame_state() != - SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); - } + bool should_defer_begin_frame = + !begin_retro_frame_args_.empty() || + !begin_retro_frame_task_.IsCancelled() || + !frame_source_->NeedsBeginFrames() || + (state_machine_.begin_impl_frame_state() != + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); if (should_defer_begin_frame) { begin_retro_frame_args_.push_back(adjusted_args); @@ -428,7 +404,7 @@ bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) { "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD); // Queuing the frame counts as "using it", so we need to return true. } else { - BeginImplFrame(adjusted_args); + BeginImplFrameWithDeadline(adjusted_args); } return true; } @@ -444,6 +420,19 @@ void Scheduler::SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) { vsync_observer_->OnUpdateVSyncParameters(last_vsync_timebase_, interval); } +void Scheduler::OnDrawForOutputSurface() { + DCHECK(settings_.using_synchronous_renderer_compositor); + DCHECK_EQ(state_machine_.begin_impl_frame_state(), + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); + DCHECK(!BeginImplFrameDeadlinePending()); + + state_machine_.OnBeginImplFrameDeadline(); + ProcessScheduledActions(); + + state_machine_.OnBeginImplFrameIdle(); + ProcessScheduledActions(); +} + // BeginRetroFrame is called for BeginFrames that we've deferred because // the scheduler was in the middle of processing a previous BeginFrame. void Scheduler::BeginRetroFrame() { @@ -485,7 +474,7 @@ void Scheduler::BeginRetroFrame() { } else { BeginFrameArgs front = begin_retro_frame_args_.front(); begin_retro_frame_args_.pop_front(); - BeginImplFrame(front); + BeginImplFrameWithDeadline(front); } } @@ -517,6 +506,27 @@ void Scheduler::PostBeginRetroFrameIfNeeded() { task_runner_->PostTask(FROM_HERE, begin_retro_frame_task_.callback()); } +void Scheduler::BeginImplFrameWithDeadline(const BeginFrameArgs& args) { + BeginImplFrame(args); + + // The deadline will be scheduled in ProcessScheduledActions. + state_machine_.OnBeginImplFrameDeadlinePending(); + ProcessScheduledActions(); +} + +void Scheduler::BeginImplFrameSynchronous(const BeginFrameArgs& args) { + BeginImplFrame(args); + FinishImplFrame(); +} + +void Scheduler::FinishImplFrame() { + state_machine_.OnBeginImplFrameIdle(); + ProcessScheduledActions(); + + client_->DidBeginImplFrameDeadline(); + frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); +} + // BeginImplFrame starts a compositor frame that will wait up until a deadline // for a BeginMainFrame+activation to complete before it times out and draws // any asynchronous animation and scroll/pinch updates. @@ -534,6 +544,7 @@ void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { main_thread_is_in_high_latency_mode); DCHECK_EQ(state_machine_.begin_impl_frame_state(), SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); + DCHECK(!BeginImplFrameDeadlinePending()); DCHECK(state_machine_.HasInitializedOutputSurface()); advance_commit_state_task_.Cancel(); @@ -552,19 +563,6 @@ void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { client_->WillBeginImplFrame(begin_impl_frame_args_); ProcessScheduledActions(); - - state_machine_.OnBeginImplFrameDeadlinePending(); - - if (settings_.using_synchronous_renderer_compositor) { - // The synchronous renderer compositor has to make its GL calls - // within this call. - // TODO(brianderson): Have the OutputSurface initiate the deadline tasks - // so the synchronous renderer compositor can take advantage of splitting - // up the BeginImplFrame and deadline as well. - OnBeginImplFrameDeadline(); - } else { - ScheduleBeginImplFrameDeadline(); - } } void Scheduler::ScheduleBeginImplFrameDeadline() { @@ -579,6 +577,9 @@ void Scheduler::ScheduleBeginImplFrameDeadline() { base::TimeTicks deadline; switch (begin_impl_frame_deadline_mode_) { + case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE: + // No deadline. + return; case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE: // We are ready to draw a new active tree immediately. // We don't use Now() here because it's somewhat expensive to call. @@ -597,27 +598,27 @@ void Scheduler::ScheduleBeginImplFrameDeadline() { break; } - TRACE_EVENT1( - "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline); + TRACE_EVENT2("cc", "Scheduler::ScheduleBeginImplFrameDeadline", "mode", + SchedulerStateMachine::BeginImplFrameDeadlineModeToString( + begin_impl_frame_deadline_mode_), + "deadline", deadline); - base::TimeDelta delta = deadline - Now(); - if (delta <= base::TimeDelta()) - delta = base::TimeDelta(); + base::TimeDelta delta = std::max(deadline - Now(), base::TimeDelta()); task_runner_->PostDelayedTask( FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); } -void Scheduler::RescheduleBeginImplFrameDeadlineIfNeeded() { - if (settings_.using_synchronous_renderer_compositor) - return; - +void Scheduler::ScheduleBeginImplFrameDeadlineIfNeeded() { if (state_machine_.begin_impl_frame_state() != SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME) return; - if (begin_impl_frame_deadline_mode_ != - state_machine_.CurrentBeginImplFrameDeadlineMode()) - ScheduleBeginImplFrameDeadline(); + if (begin_impl_frame_deadline_mode_ == + state_machine_.CurrentBeginImplFrameDeadlineMode() && + BeginImplFrameDeadlinePending()) + return; + + ScheduleBeginImplFrameDeadline(); } void Scheduler::OnBeginImplFrameDeadline() { @@ -637,20 +638,9 @@ void Scheduler::OnBeginImplFrameDeadline() { "461509 Scheduler::OnBeginImplFrameDeadline1")); state_machine_.OnBeginImplFrameDeadline(); ProcessScheduledActions(); - state_machine_.OnBeginImplFrameIdle(); - ProcessScheduledActions(); - - client_->DidBeginImplFrameDeadline(); - frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); + FinishImplFrame(); } -void Scheduler::PollForAnticipatedDrawTriggers() { - TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); - poll_for_draw_triggers_task_.Cancel(); - state_machine_.DidEnterPollForAnticipatedDrawTriggers(); - ProcessScheduledActions(); - state_machine_.DidLeavePollForAnticipatedDrawTriggers(); -} void Scheduler::PollToAdvanceCommitState() { TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState"); @@ -735,6 +725,10 @@ void Scheduler::ProcessScheduledActions() { case SchedulerStateMachine::ACTION_PREPARE_TILES: client_->ScheduledActionPrepareTiles(); break; + case SchedulerStateMachine::ACTION_INVALIDATE_OUTPUT_SURFACE: { + client_->ScheduledActionInvalidateOutputSurface(); + break; + } } } while (action != SchedulerStateMachine::ACTION_NONE); @@ -742,7 +736,7 @@ void Scheduler::ProcessScheduledActions() { client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); - RescheduleBeginImplFrameDeadlineIfNeeded(); + ScheduleBeginImplFrameDeadlineIfNeeded(); SetupNextBeginFrameIfNeeded(); } @@ -783,8 +777,6 @@ void Scheduler::AsValueInto(base::trace_event::TracedValue* state) const { !begin_retro_frame_task_.IsCancelled()); state->SetBoolean("begin_impl_frame_deadline_task_", !begin_impl_frame_deadline_task_.IsCancelled()); - state->SetBoolean("poll_for_draw_triggers_task_", - !poll_for_draw_triggers_task_.IsCancelled()); state->SetBoolean("advance_commit_state_task_", !advance_commit_state_task_.IsCancelled()); state->BeginDictionary("begin_impl_frame_args"); diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h index 3a4af5a..4b039de 100644 --- a/cc/scheduler/scheduler.h +++ b/cc/scheduler/scheduler.h @@ -41,10 +41,12 @@ class SchedulerClient { virtual void ScheduledActionActivateSyncTree() = 0; virtual void ScheduledActionBeginOutputSurfaceCreation() = 0; virtual void ScheduledActionPrepareTiles() = 0; + virtual void ScheduledActionInvalidateOutputSurface() = 0; virtual void DidAnticipatedDrawTimeChange(base::TimeTicks time) = 0; virtual base::TimeDelta DrawDurationEstimate() = 0; virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() = 0; virtual base::TimeDelta CommitToActivateDurationEstimate() = 0; + // TODO(sunnyps): Rename DidBeginImplFrameDeadline to DidFinishImplFrame. virtual void DidBeginImplFrameDeadline() = 0; virtual void SendBeginFramesToChildren(const BeginFrameArgs& args) = 0; virtual void SendBeginMainFrameNotExpectedSoon() = 0; @@ -95,6 +97,8 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn { // BeginFrameObserverMixin bool OnBeginFrameMixInDelegate(const BeginFrameArgs& args) override; + void OnDrawForOutputSurface(); + const SchedulerSettings& settings() const { return settings_; } void CommitVSyncParameters(base::TimeTicks timebase, @@ -210,11 +214,9 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn { base::Closure begin_retro_frame_closure_; base::Closure begin_impl_frame_deadline_closure_; - base::Closure poll_for_draw_triggers_closure_; base::Closure advance_commit_state_closure_; base::CancelableClosure begin_retro_frame_task_; base::CancelableClosure begin_impl_frame_deadline_task_; - base::CancelableClosure poll_for_draw_triggers_task_; base::CancelableClosure advance_commit_state_task_; SchedulerStateMachine state_machine_; @@ -223,7 +225,7 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn { private: void ScheduleBeginImplFrameDeadline(); - void RescheduleBeginImplFrameDeadlineIfNeeded(); + void ScheduleBeginImplFrameDeadlineIfNeeded(); void SetupNextBeginFrameIfNeeded(); void PostBeginRetroFrameIfNeeded(); void SetupPollingMechanisms(); @@ -233,9 +235,11 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn { void AdvanceCommitStateIfPossible(); bool IsBeginMainFrameSentOrStarted() const; void BeginRetroFrame(); + void BeginImplFrameWithDeadline(const BeginFrameArgs& args); + void BeginImplFrameSynchronous(const BeginFrameArgs& args); void BeginImplFrame(const BeginFrameArgs& args); + void FinishImplFrame(); void OnBeginImplFrameDeadline(); - void PollForAnticipatedDrawTriggers(); void PollToAdvanceCommitState(); void UpdateActiveFrameSource(); diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc index 0007690..179be59 100644 --- a/cc/scheduler/scheduler_state_machine.cc +++ b/cc/scheduler/scheduler_state_machine.cc @@ -26,10 +26,11 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) last_frame_number_swap_performed_(-1), last_frame_number_swap_requested_(-1), last_frame_number_begin_main_frame_sent_(-1), + last_frame_number_invalidate_output_surface_performed_(-1), animate_funnel_(false), - perform_swap_funnel_(false), request_swap_funnel_(false), send_begin_main_frame_funnel_(false), + invalidate_output_surface_funnel_(false), prepare_tiles_funnel_(0), consecutive_checkerboard_animations_(0), max_pending_swaps_(1), @@ -38,7 +39,6 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) needs_animate_(false), needs_prepare_tiles_(false), needs_commit_(false), - inside_poll_for_anticipated_draw_triggers_(false), visible_(false), can_start_(false), can_draw_(false), @@ -52,7 +52,9 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) continuous_painting_(false), children_need_begin_frames_(false), defer_commits_(false), - last_commit_had_no_updates_(false) { + last_commit_had_no_updates_(false), + did_request_swap_in_last_frame_(false), + did_perform_swap_in_last_draw_(false) { } const char* SchedulerStateMachine::OutputSurfaceStateToString( @@ -89,6 +91,22 @@ const char* SchedulerStateMachine::BeginImplFrameStateToString( return "???"; } +const char* SchedulerStateMachine::BeginImplFrameDeadlineModeToString( + BeginImplFrameDeadlineMode mode) { + switch (mode) { + case BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE: + return "BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE"; + case BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE: + return "BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE"; + case BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR: + return "BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR"; + case BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE: + return "BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE"; + } + NOTREACHED(); + return "???"; +} + const char* SchedulerStateMachine::CommitStateToString(CommitState state) { switch (state) { case COMMIT_STATE_IDLE: @@ -146,6 +164,8 @@ const char* SchedulerStateMachine::ActionToString(Action action) { return "ACTION_BEGIN_OUTPUT_SURFACE_CREATION"; case ACTION_PREPARE_TILES: return "ACTION_PREPARE_TILES"; + case ACTION_INVALIDATE_OUTPUT_SURFACE: + return "ACTION_INVALIDATE_OUTPUT_SURFACE"; } NOTREACHED(); return "???"; @@ -184,11 +204,12 @@ void SchedulerStateMachine::AsValueInto( state->SetInteger("last_frame_number_begin_main_frame_sent", last_frame_number_begin_main_frame_sent_); state->SetBoolean("funnel: animate_funnel", animate_funnel_); - state->SetBoolean("funnel: perform_swap_funnel", perform_swap_funnel_); state->SetBoolean("funnel: request_swap_funnel", request_swap_funnel_); state->SetBoolean("funnel: send_begin_main_frame_funnel", send_begin_main_frame_funnel_); state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_); + state->SetBoolean("funnel: invalidate_output_surface_funnel", + invalidate_output_surface_funnel_); state->SetInteger("consecutive_checkerboard_animations", consecutive_checkerboard_animations_); state->SetInteger("max_pending_swaps_", max_pending_swaps_); @@ -218,26 +239,14 @@ void SchedulerStateMachine::AsValueInto( state->SetBoolean("continuous_painting", continuous_painting_); state->SetBoolean("children_need_begin_frames", children_need_begin_frames_); state->SetBoolean("defer_commits", defer_commits_); + state->SetBoolean("last_commit_had_no_updates", last_commit_had_no_updates_); + state->SetBoolean("did_request_swap_in_last_frame", + did_request_swap_in_last_frame_); + state->SetBoolean("did_perform_swap_in_last_draw", + did_perform_swap_in_last_draw_); state->EndDictionary(); } -void SchedulerStateMachine::AdvanceCurrentFrameNumber() { - current_frame_number_++; - - animate_funnel_ = false; - perform_swap_funnel_ = false; - request_swap_funnel_ = false; - send_begin_main_frame_funnel_ = false; - - // "Drain" the PrepareTiles funnel. - if (prepare_tiles_funnel_ > 0) - prepare_tiles_funnel_--; - - skip_begin_main_frame_to_reduce_latency_ = - skip_next_begin_main_frame_to_reduce_latency_; - skip_next_begin_main_frame_to_reduce_latency_ = false; -} - bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const { // These are all the cases where we normally cannot or do not want to draw // but, if needs_redraw_ is true and we do not draw to make forward progress, @@ -427,7 +436,7 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const { // TODO(brianderson): Remove this restriction to improve throughput. bool just_swapped_in_deadline = begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE && - perform_swap_funnel_; + did_perform_swap_in_last_draw_; if (pending_swaps_ >= max_pending_swaps_ && !just_swapped_in_deadline) return false; @@ -462,14 +471,32 @@ bool SchedulerStateMachine::ShouldPrepareTiles() const { return false; // Limiting to once per-frame is not enough, since we only want to - // prepare tiles _after_ draws. Polling for draw triggers and - // begin-frame are mutually exclusive, so we limit to these two cases. - if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE && - !inside_poll_for_anticipated_draw_triggers_) + // prepare tiles _after_ draws. + if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) return false; + return needs_prepare_tiles_; } +bool SchedulerStateMachine::ShouldInvalidateOutputSurface() const { + // Do not invalidate too many times in a frame. + if (invalidate_output_surface_funnel_) + return false; + + // Only the synchronous compositor requires invalidations. + if (!settings_.using_synchronous_renderer_compositor) + return false; + + // Invalidations are only performed inside a BeginFrame. + if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING) + return false; + + // TODO(sunnyps): needs_prepare_tiles_ is needed here because PrepareTiles is + // called only inside the deadline / draw phase. We could remove this if we + // allowed PrepareTiles to happen in OnBeginImplFrame. + return needs_redraw_ || needs_prepare_tiles_; +} + SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { if (ShouldActivatePendingTree()) return ACTION_ACTIVATE_SYNC_TREE; @@ -489,6 +516,8 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { return ACTION_PREPARE_TILES; if (ShouldSendBeginMainFrame()) return ACTION_SEND_BEGIN_MAIN_FRAME; + if (ShouldInvalidateOutputSurface()) + return ACTION_INVALIDATE_OUTPUT_SURFACE; if (ShouldBeginOutputSurfaceCreation()) return ACTION_BEGIN_OUTPUT_SURFACE_CREATION; return ACTION_NONE; @@ -504,25 +533,11 @@ void SchedulerStateMachine::UpdateState(Action action) { return; case ACTION_ANIMATE: - DCHECK(!animate_funnel_); - last_frame_number_animate_performed_ = current_frame_number_; - animate_funnel_ = true; - needs_animate_ = false; - // TODO(skyostil): Instead of assuming this, require the client to tell - // us. - SetNeedsRedraw(); + UpdateStateOnAnimate(); return; case ACTION_SEND_BEGIN_MAIN_FRAME: - DCHECK(!has_pending_tree_ || - settings_.main_frame_before_activation_enabled); - DCHECK(visible_); - DCHECK(!send_begin_main_frame_funnel_); - commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT; - needs_commit_ = false; - send_begin_main_frame_funnel_ = true; - last_frame_number_begin_main_frame_sent_ = - current_frame_number_; + UpdateStateOnSendBeginMainFrame(); return; case ACTION_COMMIT: { @@ -545,26 +560,42 @@ void SchedulerStateMachine::UpdateState(Action action) { } case ACTION_BEGIN_OUTPUT_SURFACE_CREATION: - DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST); - output_surface_state_ = OUTPUT_SURFACE_CREATING; - - // The following DCHECKs make sure we are in the proper quiescent state. - // The pipeline should be flushed entirely before we start output - // surface creation to avoid complicated corner cases. - DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE); - DCHECK(!has_pending_tree_); - DCHECK(!active_tree_needs_first_draw_); + UpdateStateOnBeginOutputSurfaceCreation(); return; case ACTION_PREPARE_TILES: UpdateStateOnPrepareTiles(); return; + + case ACTION_INVALIDATE_OUTPUT_SURFACE: + UpdateStateOnInvalidateOutputSurface(); + return; } } +void SchedulerStateMachine::UpdateStateOnAnimate() { + DCHECK(!animate_funnel_); + last_frame_number_animate_performed_ = current_frame_number_; + animate_funnel_ = true; + needs_animate_ = false; + // TODO(skyostil): Instead of assuming this, require the client to tell us. + SetNeedsRedraw(); +} + +void SchedulerStateMachine::UpdateStateOnSendBeginMainFrame() { + DCHECK(!has_pending_tree_ || settings_.main_frame_before_activation_enabled); + DCHECK(visible_); + DCHECK(!send_begin_main_frame_funnel_); + commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT; + needs_commit_ = false; + send_begin_main_frame_funnel_ = true; + last_frame_number_begin_main_frame_sent_ = current_frame_number_; +} + void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) { commit_count_++; + // Animate after commit even if we've already animated. if (!commit_has_no_updates) animate_funnel_ = false; @@ -649,6 +680,7 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) { if (did_request_swap) { DCHECK(!request_swap_funnel_); request_swap_funnel_ = true; + did_request_swap_in_last_frame_ = true; last_frame_number_swap_requested_ = current_frame_number_; } } @@ -657,6 +689,25 @@ void SchedulerStateMachine::UpdateStateOnPrepareTiles() { needs_prepare_tiles_ = false; } +void SchedulerStateMachine::UpdateStateOnBeginOutputSurfaceCreation() { + DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST); + output_surface_state_ = OUTPUT_SURFACE_CREATING; + + // The following DCHECKs make sure we are in the proper quiescent state. + // The pipeline should be flushed entirely before we start output + // surface creation to avoid complicated corner cases. + DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE); + DCHECK(!has_pending_tree_); + DCHECK(!active_tree_needs_first_draw_); +} + +void SchedulerStateMachine::UpdateStateOnInvalidateOutputSurface() { + DCHECK(!invalidate_output_surface_funnel_); + invalidate_output_surface_funnel_ = true; + last_frame_number_invalidate_output_surface_performed_ = + current_frame_number_; +} + void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency() { TRACE_EVENT_INSTANT0("cc", "Scheduler: SkipNextBeginMainFrameToReduceLatency", @@ -665,10 +716,7 @@ void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency() { } bool SchedulerStateMachine::BeginFrameNeededForChildren() const { - if (HasInitializedOutputSurface()) - return children_need_begin_frames_; - - return false; + return children_need_begin_frames_; } bool SchedulerStateMachine::BeginFrameNeeded() const { @@ -676,44 +724,8 @@ bool SchedulerStateMachine::BeginFrameNeeded() const { // TODO(brianderson): Support output surface creation inside a BeginFrame. if (!HasInitializedOutputSurface()) return false; - - if (SupportsProactiveBeginFrame()) { - return (BeginFrameNeededToAnimateOrDraw() || - BeginFrameNeededForChildren() || - ProactiveBeginFrameWanted()); - } - - // Proactive BeginFrames are bad for the synchronous compositor because we - // have to draw when we get the BeginFrame and could end up drawing many - // duplicate frames if our new frame isn't ready in time. - // To poll for state with the synchronous compositor without having to draw, - // we rely on ShouldPollForAnticipatedDrawTriggers instead. - // Synchronous compositor doesn't have a browser. - DCHECK(!children_need_begin_frames_); - return BeginFrameNeededToAnimateOrDraw(); -} - -bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const { - // ShouldPollForAnticipatedDrawTriggers is what we use in place of - // ProactiveBeginFrameWanted when we are using the synchronous - // compositor. - if (!SupportsProactiveBeginFrame()) { - return !BeginFrameNeededToAnimateOrDraw() && ProactiveBeginFrameWanted(); - } - - // Non synchronous compositors should rely on - // ProactiveBeginFrameWanted to poll for state instead. - return false; -} - -// Note: If SupportsProactiveBeginFrame is false, the scheduler should poll -// for changes in it's draw state so it can request a BeginFrame when it's -// actually ready. -bool SchedulerStateMachine::SupportsProactiveBeginFrame() const { - // It is undesirable to proactively request BeginFrames if we are - // using a synchronous compositor because we *must* draw for every - // BeginFrame, which could cause duplicate draws. - return !settings_.using_synchronous_renderer_compositor; + return (BeginFrameNeededToAnimateOrDraw() || BeginFrameNeededForChildren() || + ProactiveBeginFrameWanted()); } void SchedulerStateMachine::SetChildrenNeedBeginFrames( @@ -776,7 +788,7 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const { // SetNeedsBeginFrame requests, which may propagate to the BeginImplFrame // provider and get sampled at an inopportune time, delaying the next // BeginImplFrame. - if (request_swap_funnel_) + if (did_request_swap_in_last_frame_) return true; // If the last commit was aborted because of early out (no updates), we should @@ -788,35 +800,49 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const { } void SchedulerStateMachine::OnBeginImplFrame() { - AdvanceCurrentFrameNumber(); - DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE) - << AsValue()->ToString(); begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING; + current_frame_number_++; + last_commit_had_no_updates_ = false; + did_request_swap_in_last_frame_ = false; + + // Clear funnels for any actions we perform during the frame. + animate_funnel_ = false; + send_begin_main_frame_funnel_ = false; + invalidate_output_surface_funnel_ = false; + + // "Drain" the PrepareTiles funnel. + if (prepare_tiles_funnel_ > 0) + prepare_tiles_funnel_--; + + skip_begin_main_frame_to_reduce_latency_ = + skip_next_begin_main_frame_to_reduce_latency_; + skip_next_begin_main_frame_to_reduce_latency_ = false; } void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() { - DCHECK_EQ(begin_impl_frame_state_, - BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING) - << AsValue()->ToString(); begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME; } void SchedulerStateMachine::OnBeginImplFrameDeadline() { - DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME) - << AsValue()->ToString(); begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; + + did_perform_swap_in_last_draw_ = false; + + // Clear funnels for any actions we perform during the deadline. + request_swap_funnel_ = false; } void SchedulerStateMachine::OnBeginImplFrameIdle() { - DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) - << AsValue()->ToString(); begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE; } SchedulerStateMachine::BeginImplFrameDeadlineMode SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const { - if (ShouldTriggerBeginImplFrameDeadlineImmediately()) { + if (settings_.using_synchronous_renderer_compositor) { + // No deadline for synchronous compositor. + return BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE; + } else if (ShouldTriggerBeginImplFrameDeadlineImmediately()) { return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE; } else if (needs_redraw_ && pending_swaps_ < max_pending_swaps_) { // We have an animation or fast input path on the impl thread that wants @@ -834,7 +860,6 @@ SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const { bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately() const { // TODO(brianderson): This should take into account multiple commit sources. - if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME) return false; @@ -900,7 +925,7 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const { // Even if there's a new active tree to draw at the deadline or we've just // swapped it, it may have been triggered by a previous BeginImplFrame, in // which case the main thread is in a high latency mode. - return (active_tree_needs_first_draw_ || perform_swap_funnel_) && + return (active_tree_needs_first_draw_ || did_perform_swap_in_last_draw_) && !send_begin_main_frame_funnel_; } @@ -909,15 +934,6 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const { return active_tree_needs_first_draw_; } -void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() { - AdvanceCurrentFrameNumber(); - inside_poll_for_anticipated_draw_triggers_ = true; -} - -void SchedulerStateMachine::DidLeavePollForAnticipatedDrawTriggers() { - inside_poll_for_anticipated_draw_triggers_ = false; -} - void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; } void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; } @@ -942,9 +958,8 @@ void SchedulerStateMachine::SetMaxSwapsPending(int max) { void SchedulerStateMachine::DidSwapBuffers() { pending_swaps_++; DCHECK_LE(pending_swaps_, max_pending_swaps_); - DCHECK(!perform_swap_funnel_); - perform_swap_funnel_ = true; + did_perform_swap_in_last_draw_ = true; last_frame_number_swap_performed_ = current_frame_number_; } diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h index 3914039..0901ca8 100644 --- a/cc/scheduler/scheduler_state_machine.h +++ b/cc/scheduler/scheduler_state_machine.h @@ -50,10 +50,10 @@ class CC_EXPORT SchedulerStateMachine { }; static const char* OutputSurfaceStateToString(OutputSurfaceState state); - // Note: BeginImplFrameState will always cycle through all the states in - // order. Whether or not it actually waits or draws, it will at least try to - // wait in BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME and try to draw in - // BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE + // Note: BeginImplFrameState does not cycle through these states in a fixed + // order on all platforms. It's up to the scheduler to set these correctly. + // TODO(sunnyps): Rename the states to IDLE, ANIMATE, WAITING_FOR_DEADLINE and + // DRAW. enum BeginImplFrameState { BEGIN_IMPL_FRAME_STATE_IDLE, BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING, @@ -63,6 +63,7 @@ class CC_EXPORT SchedulerStateMachine { static const char* BeginImplFrameStateToString(BeginImplFrameState state); enum BeginImplFrameDeadlineMode { + BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE, BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE, BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR, BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE, @@ -110,6 +111,7 @@ class CC_EXPORT SchedulerStateMachine { ACTION_DRAW_AND_SWAP_ABORT, ACTION_BEGIN_OUTPUT_SURFACE_CREATION, ACTION_PREPARE_TILES, + ACTION_INVALIDATE_OUTPUT_SURFACE, }; static const char* ActionToString(Action action); @@ -123,17 +125,14 @@ class CC_EXPORT SchedulerStateMachine { // to make progress. bool BeginFrameNeeded() const; - // Indicates that we need to independently poll for new state and actions - // because we can't expect a BeginImplFrame. This is mostly used to avoid - // drawing repeat frames with the synchronous compositor without dropping - // necessary actions on the floor. - bool ShouldPollForAnticipatedDrawTriggers() const; - // Indicates that the system has entered and left a BeginImplFrame callback. // The scheduler will not draw more than once in a given BeginImplFrame // callback nor send more than one BeginMainFrame message. void OnBeginImplFrame(); void OnBeginImplFrameDeadlinePending(); + // Indicates that the scheduler has entered the draw phase. The scheduler + // will not draw more than once in a single draw phase. + // TODO(sunnyps): Rename OnBeginImplFrameDeadline to OnDraw or similar. void OnBeginImplFrameDeadline(); void OnBeginImplFrameIdle(); BeginImplFrameState begin_impl_frame_state() const { @@ -145,15 +144,6 @@ class CC_EXPORT SchedulerStateMachine { // impl thread to draw, it is in a high latency mode. bool MainThreadIsInHighLatencyMode() const; - // PollForAnticipatedDrawTriggers is used by the synchronous compositor to - // avoid requesting BeginImplFrames when we won't actually draw but still - // need to advance our state at vsync intervals. - void DidEnterPollForAnticipatedDrawTriggers(); - void DidLeavePollForAnticipatedDrawTriggers(); - bool inside_poll_for_anticipated_draw_triggers() const { - return inside_poll_for_anticipated_draw_triggers_; - } - // Indicates whether the LayerTreeHostImpl is visible. void SetVisible(bool visible); bool visible() const { return visible_; } @@ -240,8 +230,6 @@ class CC_EXPORT SchedulerStateMachine { // True if we need to abort draws to make forward progress. bool PendingDrawsShouldBeAborted() const; - bool SupportsProactiveBeginFrame() const; - void SetContinuousPainting(bool continuous_painting) { continuous_painting_ = continuous_painting; } @@ -276,13 +264,16 @@ class CC_EXPORT SchedulerStateMachine { bool ShouldSendBeginMainFrame() const; bool ShouldCommit() const; bool ShouldPrepareTiles() const; + bool ShouldInvalidateOutputSurface() const; - void AdvanceCurrentFrameNumber(); - + void UpdateStateOnAnimate(); + void UpdateStateOnSendBeginMainFrame(); void UpdateStateOnCommit(bool commit_had_no_updates); void UpdateStateOnActivation(); void UpdateStateOnDraw(bool did_request_swap); + void UpdateStateOnBeginOutputSurfaceCreation(); void UpdateStateOnPrepareTiles(); + void UpdateStateOnInvalidateOutputSurface(); const SchedulerSettings settings_; @@ -298,13 +289,14 @@ class CC_EXPORT SchedulerStateMachine { int last_frame_number_swap_performed_; int last_frame_number_swap_requested_; int last_frame_number_begin_main_frame_sent_; + int last_frame_number_invalidate_output_surface_performed_; // These are used to ensure that an action only happens once per frame, // deadline, etc. bool animate_funnel_; - bool perform_swap_funnel_; bool request_swap_funnel_; bool send_begin_main_frame_funnel_; + bool invalidate_output_surface_funnel_; // prepare_tiles_funnel_ is "filled" each time PrepareTiles is called // and "drained" on each BeginImplFrame. If the funnel gets too full, // we start throttling ACTION_PREPARE_TILES such that we average one @@ -318,7 +310,6 @@ class CC_EXPORT SchedulerStateMachine { bool needs_animate_; bool needs_prepare_tiles_; bool needs_commit_; - bool inside_poll_for_anticipated_draw_triggers_; bool visible_; bool can_start_; bool can_draw_; @@ -333,6 +324,8 @@ class CC_EXPORT SchedulerStateMachine { bool children_need_begin_frames_; bool defer_commits_; bool last_commit_had_no_updates_; + bool did_request_swap_in_last_frame_; + bool did_perform_swap_in_last_draw_; private: DISALLOW_COPY_AND_ASSIGN(SchedulerStateMachine); diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index 935a80a..3daf16a 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc @@ -141,6 +141,10 @@ class FakeSchedulerClient : public SchedulerClient { void ScheduledActionPrepareTiles() override { PushAction("ScheduledActionPrepareTiles"); } + void ScheduledActionInvalidateOutputSurface() override { + actions_.push_back("ScheduledActionInvalidateOutputSurface"); + states_.push_back(scheduler_->AsValue()); + } void DidAnticipatedDrawTimeChange(base::TimeTicks) override { if (log_anticipated_draw_time_change_) PushAction("DidAnticipatedDrawTimeChange"); @@ -306,12 +310,18 @@ class SchedulerTest : public testing::Test { scheduler_->NotifyBeginMainFrameStarted(); scheduler_->NotifyReadyToCommitThenActivateIfNeeded(); - // Run the posted deadline task. - EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); - task_runner_->RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); - EXPECT_FALSE(scheduler_->CommitPending()); + + if (scheduler_settings_.using_synchronous_renderer_compositor) { + scheduler_->SetNeedsRedraw(); + scheduler_->OnDrawForOutputSurface(); + } else { + // Run the posted deadline task. + EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); + task_runner_->RunTasksWhile(client_->ImplFrameDeadlinePending(true)); + } + + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); } client_->Reset(); @@ -321,9 +331,12 @@ class SchedulerTest : public testing::Test { "Run second frame so Scheduler calls SetNeedsBeginFrame(false)."); AdvanceFrame(); - // Run the posted deadline task. - EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); - task_runner_->RunTasksWhile(client_->ImplFrameDeadlinePending(true)); + if (!scheduler_settings_.using_synchronous_renderer_compositor) { + // Run the posted deadline task. + EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); + task_runner_->RunTasksWhile(client_->ImplFrameDeadlinePending(true)); + } + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); } @@ -348,13 +361,14 @@ class SchedulerTest : public testing::Test { if (scheduler_->settings().use_external_begin_frame_source && scheduler_->FrameProductionThrottled()) { SendNextBeginFrame(); - EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); } - // Then run tasks until new deadline is scheduled. - EXPECT_TRUE( - task_runner_->RunTasksWhile(client_->ImplFrameDeadlinePending(false))); - EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); + if (!scheduler_->settings().using_synchronous_renderer_compositor) { + // Then run tasks until new deadline is scheduled. + EXPECT_TRUE(task_runner_->RunTasksWhile( + client_->ImplFrameDeadlinePending(false))); + EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); + } } void SendNextBeginFrame() { @@ -2269,6 +2283,132 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon) { client_->Reset(); } +TEST_F(SchedulerTest, UsingSynchronousCompositor) { + scheduler_settings_.using_synchronous_renderer_compositor = true; + scheduler_settings_.use_external_begin_frame_source = true; + scheduler_settings_.impl_side_painting = true; + SetUpScheduler(true); + + // Compositor thread initiated input/animation. + // -------------------------------------------- + scheduler_->SetNeedsAnimate(); + EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); + client_->Reset(); + + // Next vsync. + AdvanceFrame(); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); + EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + // Continue with animation. + scheduler_->SetNeedsAnimate(); + EXPECT_NO_ACTION(client_); + + // Android onDraw. + scheduler_->SetNeedsRedraw(); + scheduler_->OnDrawForOutputSurface(); + EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + // Next vsync. + AdvanceFrame(); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); + EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + // Android onDraw. + scheduler_->SetNeedsRedraw(); + scheduler_->OnDrawForOutputSurface(); + EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + // Idle on next vsync. + AdvanceFrame(); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3); + EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + // Android onDraw after idle. + // -------------------------- + scheduler_->SetNeedsRedraw(); + scheduler_->OnDrawForOutputSurface(); + EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 3); + EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 2, 3); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + // Idle on next vsync. + AdvanceFrame(); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3); + EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + // Main thread initiated activity. + // ------------------------------- + scheduler_->SetNeedsCommit(); + EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); + client_->Reset(); + + // Next vsync. + AdvanceFrame(); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + scheduler_->NotifyBeginMainFrameStarted(); + EXPECT_NO_ACTION(client_); + + // Next vsync. + AdvanceFrame(); + EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + scheduler_->NotifyReadyToCommit(); + EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_); + client_->Reset(); + + scheduler_->NotifyReadyToActivate(); + EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_); + client_->Reset(); + + // Next vsync. + AdvanceFrame(); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); + EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + // Android onDraw. + scheduler_->SetNeedsRedraw(); + scheduler_->OnDrawForOutputSurface(); + EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + // Idle on next vsync. + AdvanceFrame(); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3); + EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); +} + TEST_F(SchedulerTest, AuthoritativeVSyncInterval) { SetUpScheduler(true); diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc index 7ec4672..6de3c30 100644 --- a/cc/surfaces/display.cc +++ b/cc/surfaces/display.cc @@ -196,6 +196,10 @@ void Display::SetMemoryPolicy(const ManagedMemoryPolicy& policy) { client_->SetMemoryPolicy(policy); } +void Display::OnDraw() { + NOTREACHED(); +} + void Display::OnSurfaceDamaged(SurfaceId surface_id, bool* changed) { if (aggregator_ && aggregator_->previous_contained_surfaces().count(surface_id)) { diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h index 30db259..9c5a349 100644 --- a/cc/surfaces/display.h +++ b/cc/surfaces/display.h @@ -84,6 +84,7 @@ class CC_SURFACES_EXPORT Display : public OutputSurfaceClient, bool resourceless_software_draw) override {} void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override; void SetTreeActivationCallback(const base::Closure& callback) override {} + void OnDraw() override; // RendererClient implementation. void SetFullRootLayerDamage() override {} diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h index 63d7f43..9d946aa 100644 --- a/cc/test/fake_layer_tree_host_impl_client.h +++ b/cc/test/fake_layer_tree_host_impl_client.h @@ -40,6 +40,7 @@ class FakeLayerTreeHostImplClient : public LayerTreeHostImplClient { void DidActivateSyncTree() override {} void DidPrepareTiles() override {} void DidCompletePageScaleAnimationOnImplThread() override {} + void OnDrawForOutputSurface() override {} }; } // namespace cc diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h index 39a78ea..2248b84 100644 --- a/cc/test/fake_output_surface.h +++ b/cc/test/fake_output_surface.h @@ -101,6 +101,7 @@ class FakeOutputSurface : public OutputSurface { void SwapBuffers(CompositorFrame* frame) override; + OutputSurfaceClient* client() { return client_; } bool BindToClient(OutputSurfaceClient* client) override; void set_framebuffer(unsigned framebuffer) { framebuffer_ = framebuffer; } diff --git a/cc/test/fake_output_surface_client.h b/cc/test/fake_output_surface_client.h index 310842d..ddfbd11 100644 --- a/cc/test/fake_output_surface_client.h +++ b/cc/test/fake_output_surface_client.h @@ -46,6 +46,7 @@ class FakeOutputSurfaceClient : public OutputSurfaceClient { bool resourceless_software_draw) override {} void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override; void SetTreeActivationCallback(const base::Closure&) override {} + void OnDraw() override {} int swap_count() { return swap_count_; } diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index 2fff95f..87c4035 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc @@ -120,6 +120,11 @@ class ThreadProxyForTest : public ThreadProxy { test_hooks_->ScheduledActionPrepareTiles(); } + void ScheduledActionInvalidateOutputSurface() override { + ThreadProxy::ScheduledActionInvalidateOutputSurface(); + test_hooks_->ScheduledActionInvalidateOutputSurface(); + } + ThreadProxyForTest( TestHooks* test_hooks, LayerTreeHost* host, diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h index 35a3546..df5f500 100644 --- a/cc/test/layer_tree_test.h +++ b/cc/test/layer_tree_test.h @@ -99,6 +99,7 @@ class TestHooks : public AnimationDelegate { virtual void ScheduledActionCommit() {} virtual void ScheduledActionBeginOutputSurfaceCreation() {} virtual void ScheduledActionPrepareTiles() {} + virtual void ScheduledActionInvalidateOutputSurface() {} // Implementation of AnimationDelegate: void NotifyAnimationStarted(base::TimeTicks monotonic_time, diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 00ae766..c9bba83 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc @@ -1435,6 +1435,10 @@ void LayerTreeHostImpl::ReclaimResources(const CompositorFrameAck* ack) { } } +void LayerTreeHostImpl::OnDraw() { + client_->OnDrawForOutputSurface(); +} + void LayerTreeHostImpl::OnCanDrawStateChangedForTree() { client_->OnCanDrawStateChanged(CanDraw()); } diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index 388de5e..6bbc488 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h @@ -121,6 +121,9 @@ class LayerTreeHostImplClient { // Called when page scale animation has completed on the impl thread. virtual void DidCompletePageScaleAnimationOnImplThread() = 0; + // Called when output surface asks for a draw. + virtual void OnDrawForOutputSurface() = 0; + protected: virtual ~LayerTreeHostImplClient() {} }; @@ -295,6 +298,7 @@ class CC_EXPORT LayerTreeHostImpl void ReclaimResources(const CompositorFrameAck* ack) override; void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override; void SetTreeActivationCallback(const base::Closure& callback) override; + void OnDraw() override; // Called from LayerTreeImpl. void OnCanDrawStateChangedForTree(); diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 818c97e..0092148 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc @@ -162,6 +162,7 @@ class LayerTreeHostImplTest : public testing::Test, void DidCompletePageScaleAnimationOnImplThread() override { did_complete_page_scale_animation_ = true; } + void OnDrawForOutputSurface() override {} void set_reduce_memory_result(bool reduce_memory_result) { reduce_memory_result_ = reduce_memory_result; diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index c2f3417..00f4f9a 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc @@ -2707,10 +2707,26 @@ class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest { class LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor : public LayerTreeHostTestAbortedCommitDoesntStall { + protected: void InitializeSettings(LayerTreeSettings* settings) override { LayerTreeHostTestAbortedCommitDoesntStall::InitializeSettings(settings); settings->using_synchronous_renderer_compositor = true; } + + void ScheduledActionInvalidateOutputSurface() override { + ImplThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind( + &LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor:: + CallOnDraw, + base::Unretained(this))); + } + + void CallOnDraw() { + // Synchronous compositor does not draw unless told to do so by the output + // surface. + output_surface()->client()->OnDraw(); + } }; MULTI_THREAD_TEST_F( diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index 3633585..f16803d 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc @@ -560,6 +560,10 @@ void SingleThreadProxy::DidSwapBuffersCompleteOnImplThread() { layer_tree_host_->DidCompleteSwapBuffers(); } +void SingleThreadProxy::OnDrawForOutputSurface() { + NOTREACHED() << "Implemented by ThreadProxy for synchronous compositor."; +} + void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) { TRACE_EVENT0("cc,benchmark", "SingleThreadProxy::CompositeImmediately"); DCHECK(Proxy::IsMainThread()); @@ -576,7 +580,7 @@ void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) { { BeginFrameArgs begin_frame_args(BeginFrameArgs::Create( BEGINFRAME_FROM_HERE, frame_begin_time, base::TimeTicks(), - BeginFrameArgs::DefaultInterval(), BeginFrameArgs::SYNCHRONOUS)); + BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL)); DoBeginMainFrame(begin_frame_args); DoCommit(); @@ -910,6 +914,10 @@ void SingleThreadProxy::ScheduledActionPrepareTiles() { layer_tree_host_impl_->PrepareTiles(); } +void SingleThreadProxy::ScheduledActionInvalidateOutputSurface() { + NOTREACHED(); +} + void SingleThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) { } diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h index 0ccd28c..47c556d 100644 --- a/cc/trees/single_thread_proxy.h +++ b/cc/trees/single_thread_proxy.h @@ -74,6 +74,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy, void ScheduledActionActivateSyncTree() override; void ScheduledActionBeginOutputSurfaceCreation() override; void ScheduledActionPrepareTiles() override; + void ScheduledActionInvalidateOutputSurface() override; void DidAnticipatedDrawTimeChange(base::TimeTicks time) override; base::TimeDelta DrawDurationEstimate() override; base::TimeDelta BeginMainFrameToCommitDurationEstimate() override; @@ -110,6 +111,8 @@ class CC_EXPORT SingleThreadProxy : public Proxy, void DidActivateSyncTree() override; void DidPrepareTiles() override; void DidCompletePageScaleAnimationOnImplThread() override; + void OnDrawForOutputSurface() override; + void SetDebugState(const LayerTreeDebugState& debug_state) override {} void RequestNewOutputSurface(); diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc index 9a095ef..2253a4f 100644 --- a/cc/trees/thread_proxy.cc +++ b/cc/trees/thread_proxy.cc @@ -1114,6 +1114,12 @@ DrawResult ThreadProxy::ScheduledActionDrawAndSwapForced() { return DrawSwapInternal(forced_draw); } +void ThreadProxy::ScheduledActionInvalidateOutputSurface() { + TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionInvalidateOutputSurface"); + DCHECK(impl().layer_tree_host_impl->output_surface()); + impl().layer_tree_host_impl->output_surface()->Invalidate(); +} + void ThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) { if (impl().current_resource_update_controller) impl().current_resource_update_controller->PerformMoreUpdates(time); @@ -1375,4 +1381,9 @@ void ThreadProxy::DidCompletePageScaleAnimationOnImplThread() { main_thread_weak_ptr_)); } +void ThreadProxy::OnDrawForOutputSurface() { + DCHECK(IsImplThread()); + impl().scheduler->OnDrawForOutputSurface(); +} + } // namespace cc diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h index 07f4c6c..1f06611 100644 --- a/cc/trees/thread_proxy.h +++ b/cc/trees/thread_proxy.h @@ -211,6 +211,7 @@ class CC_EXPORT ThreadProxy : public Proxy, void DidActivateSyncTree() override; void DidPrepareTiles() override; void DidCompletePageScaleAnimationOnImplThread() override; + void OnDrawForOutputSurface() override; // SchedulerClient implementation void WillBeginImplFrame(const BeginFrameArgs& args) override; @@ -222,6 +223,7 @@ class CC_EXPORT ThreadProxy : public Proxy, void ScheduledActionActivateSyncTree() override; void ScheduledActionBeginOutputSurfaceCreation() override; void ScheduledActionPrepareTiles() override; + void ScheduledActionInvalidateOutputSurface() override; void DidAnticipatedDrawTimeChange(base::TimeTicks time) override; base::TimeDelta DrawDurationEstimate() override; base::TimeDelta BeginMainFrameToCommitDurationEstimate() override; diff --git a/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.cc b/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.cc index 0c272fd..f1105f7 100644 --- a/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.cc +++ b/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.cc @@ -30,11 +30,10 @@ SynchronousCompositorExternalBeginFrameSource:: DCHECK(!compositor_); } -void SynchronousCompositorExternalBeginFrameSource::BeginFrame() { +void SynchronousCompositorExternalBeginFrameSource::BeginFrame( + const cc::BeginFrameArgs& args) { DCHECK(CalledOnValidThread()); - CallOnBeginFrame(cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, gfx::FrameTime::Now(), base::TimeTicks(), - cc::BeginFrameArgs::DefaultInterval(), cc::BeginFrameArgs::SYNCHRONOUS)); + CallOnBeginFrame(args); } void SynchronousCompositorExternalBeginFrameSource::SetCompositor( @@ -46,9 +45,8 @@ void SynchronousCompositorExternalBeginFrameSource::SetCompositor( void SynchronousCompositorExternalBeginFrameSource::OnNeedsBeginFramesChange( bool needs_begin_frames) { DCHECK(CalledOnValidThread()); - if (compositor_) - compositor_->NeedsBeginFramesChanged(); + compositor_->OnNeedsBeginFramesChange(needs_begin_frames); } void SynchronousCompositorExternalBeginFrameSource::SetClientReady() { diff --git a/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h b/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h index c235c77..ee82f70 100644 --- a/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h +++ b/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h @@ -20,8 +20,7 @@ class SynchronousCompositorExternalBeginFrameSource explicit SynchronousCompositorExternalBeginFrameSource(int routing_id); ~SynchronousCompositorExternalBeginFrameSource() override; - void BeginFrame(); - + void BeginFrame(const cc::BeginFrameArgs& args); void SetCompositor(SynchronousCompositorImpl* compositor); // cc::BeginFrameSourceMixIn implementation. diff --git a/content/browser/android/in_process/synchronous_compositor_impl.cc b/content/browser/android/in_process/synchronous_compositor_impl.cc index 44d686c..67a04ed 100644 --- a/content/browser/android/in_process/synchronous_compositor_impl.cc +++ b/content/browser/android/in_process/synchronous_compositor_impl.cc @@ -73,7 +73,8 @@ SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents* contents) contents_(contents), routing_id_(contents->GetRoutingID()), input_handler_(NULL), - invoking_composite_(false), + is_active_(false), + renderer_needs_begin_frames_(false), weak_ptr_factory_(this) { DCHECK(contents); DCHECK_NE(routing_id_, MSG_ROUTING_NONE); @@ -120,11 +121,14 @@ void SynchronousCompositorImpl::DidInitializeRendererObjects( begin_frame_source_ = begin_frame_source; begin_frame_source_->SetCompositor(this); - output_surface_->SetBeginFrameSource(begin_frame_source_); + output_surface_->SetCompositor(this); + output_surface_->SetTreeActivationCallback( base::Bind(&SynchronousCompositorImpl::DidActivatePendingTree, weak_ptr_factory_.GetWeakPtr())); - NeedsBeginFramesChanged(); + + OnNeedsBeginFramesChange(begin_frame_source_->NeedsBeginFrames()); + compositor_client_->DidInitializeCompositor(this); } @@ -133,7 +137,7 @@ void SynchronousCompositorImpl::DidDestroyRendererObjects() { DCHECK(begin_frame_source_); begin_frame_source_->SetCompositor(nullptr); - output_surface_->SetBeginFrameSource(nullptr); + output_surface_->SetCompositor(nullptr); if (compositor_client_) compositor_client_->DidDestroyCompositor(this); compositor_client_ = nullptr; @@ -181,12 +185,9 @@ scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw( const gfx::Transform& transform_for_tile_priority) { DCHECK(CalledOnValidThread()); DCHECK(output_surface_); - DCHECK(!invoking_composite_); DCHECK(compositor_client_); DCHECK(begin_frame_source_); - base::AutoReset<bool> invoking_composite_resetter(&invoking_composite_, - true); scoped_ptr<cc::CompositorFrame> frame = output_surface_->DemandDrawHw(surface_size, transform, @@ -194,12 +195,10 @@ scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw( clip, viewport_rect_for_tile_priority, transform_for_tile_priority); + if (frame.get()) UpdateFrameMetaData(frame->metadata); - compositor_client_->SetContinuousInvalidate( - begin_frame_source_->NeedsBeginFrames()); - return frame.Pass(); } @@ -212,20 +211,15 @@ void SynchronousCompositorImpl::ReturnResources( bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) { DCHECK(CalledOnValidThread()); DCHECK(output_surface_); - DCHECK(!invoking_composite_); DCHECK(compositor_client_); DCHECK(begin_frame_source_); - base::AutoReset<bool> invoking_composite_resetter(&invoking_composite_, - true); scoped_ptr<cc::CompositorFrame> frame = output_surface_->DemandDrawSw(canvas); + if (frame.get()) UpdateFrameMetaData(frame->metadata); - compositor_client_->SetContinuousInvalidate( - begin_frame_source_->NeedsBeginFrames()); - return !!frame.get(); } @@ -245,11 +239,42 @@ void SynchronousCompositorImpl::SetMemoryPolicy(size_t bytes_limit) { output_surface_->SetMemoryPolicy(bytes_limit); } +void SynchronousCompositorImpl::PostInvalidate() { + DCHECK(CalledOnValidThread()); + DCHECK(compositor_client_); + compositor_client_->PostInvalidate(); +} + void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() { if (input_handler_) input_handler_->OnRootLayerDelegatedScrollOffsetChanged(); } +void SynchronousCompositorImpl::SetIsActive(bool is_active) { + TRACE_EVENT1("cc", "SynchronousCompositorImpl::SetIsActive", "is_active", + is_active); + is_active_ = is_active; + UpdateNeedsBeginFrames(); +} + +void SynchronousCompositorImpl::OnNeedsBeginFramesChange( + bool needs_begin_frames) { + renderer_needs_begin_frames_ = needs_begin_frames; + UpdateNeedsBeginFrames(); +} + +void SynchronousCompositorImpl::BeginFrame(const cc::BeginFrameArgs& args) { + if (begin_frame_source_) + begin_frame_source_->BeginFrame(args); +} + +void SynchronousCompositorImpl::UpdateNeedsBeginFrames() { + RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>( + contents_->GetRenderWidgetHostView()); + if (rwhv) + rwhv->OnSetNeedsBeginFrames(is_active_ && renderer_needs_begin_frames_); +} + void SynchronousCompositorImpl::SetInputHandler( cc::InputHandler* input_handler) { DCHECK(CalledOnValidThread()); @@ -279,18 +304,6 @@ void SynchronousCompositorImpl::DidStopFlinging() { rwhv->DidStopFlinging(); } -void SynchronousCompositorImpl::NeedsBeginFramesChanged() const { - DCHECK(CalledOnValidThread()); - DCHECK(begin_frame_source_); - if (invoking_composite_) - return; - - if (compositor_client_) { - compositor_client_->SetContinuousInvalidate( - begin_frame_source_->NeedsBeginFrames()); - } -} - InputEventAckState SynchronousCompositorImpl::HandleInputEvent( const blink::WebInputEvent& input_event) { DCHECK(CalledOnValidThread()); diff --git a/content/browser/android/in_process/synchronous_compositor_impl.h b/content/browser/android/in_process/synchronous_compositor_impl.h index d6cacf0..ee5acc1 100644 --- a/content/browser/android/in_process/synchronous_compositor_impl.h +++ b/content/browser/android/in_process/synchronous_compositor_impl.h @@ -18,7 +18,7 @@ #include "ipc/ipc_message.h" namespace cc { -class BeginFrameSource; +struct BeginFrameArgs; class InputHandler; } @@ -56,7 +56,13 @@ class SynchronousCompositorImpl void DidDestroyRendererObjects(); // Called by SynchronousCompositorExternalBeginFrameSource. - void NeedsBeginFramesChanged() const; + void OnNeedsBeginFramesChange(bool needs_begin_frames); + + // Called by SynchronousCompositorOutputSurface. + void PostInvalidate(); + + // Called by RenderWidgetHostViewAndroid. + void BeginFrame(const cc::BeginFrameArgs& args); // SynchronousCompositor bool InitializeHwDraw() override; @@ -72,6 +78,7 @@ class SynchronousCompositorImpl void ReturnResources(const cc::CompositorFrameAck& frame_ack) override; void SetMemoryPolicy(size_t bytes_limit) override; void DidChangeRootLayerScrollOffset() override; + void SetIsActive(bool is_active) override; // LayerScrollOffsetDelegate gfx::ScrollOffset GetTotalScrollOffset() override; @@ -99,6 +106,7 @@ class SynchronousCompositorImpl void DidActivatePendingTree(); void DeliverMessages(); bool CalledOnValidThread() const; + void UpdateNeedsBeginFrames(); SynchronousCompositorClient* compositor_client_; SynchronousCompositorOutputSurface* output_surface_; @@ -106,7 +114,8 @@ class SynchronousCompositorImpl WebContents* contents_; const int routing_id_; cc::InputHandler* input_handler_; - bool invoking_composite_; + bool is_active_; + bool renderer_needs_begin_frames_; base::WeakPtrFactory<SynchronousCompositorImpl> weak_ptr_factory_; diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.cc b/content/browser/android/in_process/synchronous_compositor_output_surface.cc index 48c2bf1..172f639 100644 --- a/content/browser/android/in_process/synchronous_compositor_output_surface.cc +++ b/content/browser/android/in_process/synchronous_compositor_output_surface.cc @@ -71,9 +71,7 @@ SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface( registered_(false), current_sw_canvas_(nullptr), memory_policy_(0), - output_surface_client_(nullptr), - frame_swap_message_queue_(frame_swap_message_queue), - begin_frame_source_(nullptr) { + frame_swap_message_queue_(frame_swap_message_queue) { capabilities_.deferred_gl_initialization = true; capabilities_.draw_and_swap_full_viewport_every_frame = true; capabilities_.adjust_deadline_for_parent = false; @@ -89,7 +87,6 @@ SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() { SynchronousCompositorRegistry::GetInstance()->UnregisterOutputSurface( routing_id_, this); } - DCHECK(!begin_frame_source_); } bool SynchronousCompositorOutputSurface::BindToClient( @@ -98,8 +95,7 @@ bool SynchronousCompositorOutputSurface::BindToClient( if (!cc::OutputSurface::BindToClient(surface_client)) return false; - output_surface_client_ = surface_client; - output_surface_client_->SetMemoryPolicy(memory_policy_); + client_->SetMemoryPolicy(memory_policy_); SynchronousCompositorRegistry::GetInstance()->RegisterOutputSurface( routing_id_, this); @@ -108,6 +104,12 @@ bool SynchronousCompositorOutputSurface::BindToClient( return true; } +void SynchronousCompositorOutputSurface::SetCompositor( + SynchronousCompositorImpl* compositor) { + DCHECK(CalledOnValidThread()); + compositor_ = compositor; +} + void SynchronousCompositorOutputSurface::Reshape( const gfx::Size& size, float scale_factor) { // Intentional no-op: surface size is controlled by the embedder. @@ -123,9 +125,9 @@ void SynchronousCompositorOutputSurface::SwapBuffers( client_->DidSwapBuffers(); } -void SynchronousCompositorOutputSurface::SetBeginFrameSource( - SynchronousCompositorExternalBeginFrameSource* begin_frame_source) { - begin_frame_source_ = begin_frame_source; +void SynchronousCompositorOutputSurface::Invalidate() { + DCHECK(CalledOnValidThread()); + compositor_->PostInvalidate(); } namespace { @@ -179,6 +181,7 @@ SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas* canvas) { DCHECK(CalledOnValidThread()); DCHECK(canvas); DCHECK(!current_sw_canvas_); + base::AutoReset<SkCanvas*> canvas_resetter(¤t_sw_canvas_, canvas); SkIRect canvas_clip; @@ -212,7 +215,6 @@ void SynchronousCompositorOutputSurface::InvokeComposite( gfx::Transform transform_for_tile_priority, bool hardware_draw) { DCHECK(!frame_holder_.get()); - DCHECK(begin_frame_source_); gfx::Transform adjusted_transform = transform; AdjustTransform(&adjusted_transform, viewport); @@ -224,7 +226,7 @@ void SynchronousCompositorOutputSurface::InvokeComposite( !hardware_draw); SetNeedsRedrawRect(gfx::Rect(viewport.size())); - begin_frame_source_->BeginFrame(); + client_->OnDraw(); // After software draws (which might move the viewport arbitrarily), restore // the previous hardware viewport to allow CC's tile manager to prioritize @@ -260,8 +262,8 @@ void SynchronousCompositorOutputSurface::SetMemoryPolicy(size_t bytes_limit) { memory_policy_.bytes_limit_when_visible = bytes_limit; memory_policy_.num_resources_limit = kNumResourcesLimit; - if (output_surface_client_) - output_surface_client_->SetMemoryPolicy(memory_policy_); + if (client_) + client_->SetMemoryPolicy(memory_policy_); } void SynchronousCompositorOutputSurface::SetTreeActivationCallback( diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.h b/content/browser/android/in_process/synchronous_compositor_output_surface.h index 584bedc..adc65b4 100644 --- a/content/browser/android/in_process/synchronous_compositor_output_surface.h +++ b/content/browser/android/in_process/synchronous_compositor_output_surface.h @@ -32,7 +32,7 @@ namespace content { class FrameSwapMessageQueue; class SynchronousCompositorClient; -class SynchronousCompositorExternalBeginFrameSource; +class SynchronousCompositorImpl; class SynchronousCompositorOutputSurface; class WebGraphicsContext3DCommandBufferImpl; @@ -52,13 +52,13 @@ class SynchronousCompositorOutputSurface scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue); ~SynchronousCompositorOutputSurface() override; + void SetCompositor(SynchronousCompositorImpl* compositor); + // OutputSurface. bool BindToClient(cc::OutputSurfaceClient* surface_client) override; void Reshape(const gfx::Size& size, float scale_factor) override; void SwapBuffers(cc::CompositorFrame* frame) override; - - void SetBeginFrameSource( - SynchronousCompositorExternalBeginFrameSource* begin_frame_source); + void Invalidate() override; // Partial SynchronousCompositor API implementation. bool InitializeHwDraw( @@ -93,6 +93,9 @@ class SynchronousCompositorOutputSurface const int routing_id_; bool registered_; + // Not owned. + SynchronousCompositorImpl* compositor_; + gfx::Transform cached_hw_transform_; gfx::Rect cached_hw_viewport_; gfx::Rect cached_hw_clip_; @@ -104,13 +107,10 @@ class SynchronousCompositorOutputSurface cc::ManagedMemoryPolicy memory_policy_; - cc::OutputSurfaceClient* output_surface_client_; scoped_ptr<cc::CompositorFrame> frame_holder_; scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue_; - SynchronousCompositorExternalBeginFrameSource* begin_frame_source_; - DISALLOW_COPY_AND_ASSIGN(SynchronousCompositorOutputSurface); }; 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 76affb9..318584e 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc @@ -778,7 +778,6 @@ void RenderWidgetHostViewAndroid::OnDidChangeBodyBackgroundColor( } void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrames(bool enabled) { - DCHECK(using_browser_compositor_); TRACE_EVENT1("cc", "RenderWidgetHostViewAndroid::OnSetNeedsBeginFrames", "enabled", enabled); if (enabled) @@ -1531,10 +1530,6 @@ void RenderWidgetHostViewAndroid::RemoveLayers() { } void RenderWidgetHostViewAndroid::RequestVSyncUpdate(uint32 requests) { - // The synchronous compositor does not requre BeginFrame messages. - if (!using_browser_compositor_) - requests &= FLUSH_INPUT; - bool should_request_vsync = !outstanding_vsync_requests_ && requests; outstanding_vsync_requests_ |= requests; @@ -1582,15 +1577,28 @@ void RenderWidgetHostViewAndroid::SendBeginFrame(base::TimeTicks frame_time, base::TimeDelta vsync_period) { TRACE_EVENT1("cc", "RenderWidgetHostViewAndroid::SendBeginFrame", "frame_time_us", frame_time.ToInternalValue()); - base::TimeTicks display_time = frame_time + vsync_period; - base::TimeTicks deadline = - display_time - host_->GetEstimatedBrowserCompositeTime(); + if (using_browser_compositor_) { + base::TimeTicks display_time = frame_time + vsync_period; + + base::TimeTicks deadline = + display_time - host_->GetEstimatedBrowserCompositeTime(); - host_->Send(new ViewMsg_BeginFrame( - host_->GetRoutingID(), - cc::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline, - vsync_period, cc::BeginFrameArgs::NORMAL))); + host_->Send(new ViewMsg_BeginFrame( + host_->GetRoutingID(), + cc::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline, + vsync_period, cc::BeginFrameArgs::NORMAL))); + } else { + SynchronousCompositorImpl* compositor = SynchronousCompositorImpl::FromID( + host_->GetProcess()->GetID(), host_->GetRoutingID()); + if (compositor) { + // The synchronous compositor synchronously does it's work in this call. + // It does not use a deadline. + compositor->BeginFrame(cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, frame_time, base::TimeTicks(), vsync_period, + cc::BeginFrameArgs::NORMAL)); + } + } } bool RenderWidgetHostViewAndroid::Animate(base::TimeTicks frame_time) { @@ -1925,19 +1933,22 @@ void RenderWidgetHostViewAndroid::OnVSync(base::TimeTicks frame_time, if (!host_ || host_->is_hidden()) return; - const uint32 current_vsync_requests = outstanding_vsync_requests_; - outstanding_vsync_requests_ = 0; - - if (current_vsync_requests & FLUSH_INPUT) + if (outstanding_vsync_requests_ & FLUSH_INPUT) { + outstanding_vsync_requests_ &= ~FLUSH_INPUT; host_->FlushInput(); + } - if (current_vsync_requests & BEGIN_FRAME || - current_vsync_requests & PERSISTENT_BEGIN_FRAME) { + if (outstanding_vsync_requests_ & BEGIN_FRAME || + outstanding_vsync_requests_ & PERSISTENT_BEGIN_FRAME) { + outstanding_vsync_requests_ &= ~BEGIN_FRAME; SendBeginFrame(frame_time, vsync_period); } - if (current_vsync_requests & PERSISTENT_BEGIN_FRAME) - RequestVSyncUpdate(PERSISTENT_BEGIN_FRAME); + // This allows for SendBeginFrame and FlushInput to modify + // outstanding_vsync_requests. + uint32 outstanding_vsync_requests = outstanding_vsync_requests_; + outstanding_vsync_requests_ = 0; + RequestVSyncUpdate(outstanding_vsync_requests); } void RenderWidgetHostViewAndroid::OnAnimate(base::TimeTicks begin_frame_time) { diff --git a/content/public/browser/android/synchronous_compositor.h b/content/public/browser/android/synchronous_compositor.h index 476b86d..be79209 100644 --- a/content/public/browser/android/synchronous_compositor.h +++ b/content/public/browser/android/synchronous_compositor.h @@ -87,6 +87,11 @@ class CONTENT_EXPORT SynchronousCompositor { // SynchronousCompositorClient::GetTotalRootLayerScrollOffset). virtual void DidChangeRootLayerScrollOffset() = 0; + // Called by the embedder to notify that the compositor is active. The + // compositor won't ask for vsyncs when it's inactive. NOTE: The compositor + // starts off as inactive and needs a SetActive(true) call to begin. + virtual void SetIsActive(bool is_active) = 0; + protected: virtual ~SynchronousCompositor() {} }; diff --git a/content/public/browser/android/synchronous_compositor_client.h b/content/public/browser/android/synchronous_compositor_client.h index c3b91dd..e42e09a 100644 --- a/content/public/browser/android/synchronous_compositor_client.h +++ b/content/public/browser/android/synchronous_compositor_client.h @@ -39,10 +39,7 @@ class SynchronousCompositorClient { gfx::Vector2dF latest_overscroll_delta, gfx::Vector2dF current_fling_velocity) = 0; - // When true, should periodically call - // SynchronousCompositorOutputSurface::DemandDrawHw. Note that this value - // can change inside DemandDrawHw call. - virtual void SetContinuousInvalidate(bool invalidate) = 0; + virtual void PostInvalidate() = 0; virtual void DidUpdateContent() = 0; diff --git a/content/public/test/test_synchronous_compositor_android.h b/content/public/test/test_synchronous_compositor_android.h index a3d3177..ea8982a 100644 --- a/content/public/test/test_synchronous_compositor_android.h +++ b/content/public/test/test_synchronous_compositor_android.h @@ -31,6 +31,7 @@ class CONTENT_EXPORT TestSynchronousCompositor : public SynchronousCompositor { bool DemandDrawSw(SkCanvas* canvas) override; void SetMemoryPolicy(size_t bytes_limit) override; void DidChangeRootLayerScrollOffset() override {} + void SetIsActive(bool is_active) override {} private: SynchronousCompositorClient* client_; |