summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--android_webview/browser/browser_view_renderer.cc118
-rw-r--r--android_webview/browser/browser_view_renderer.h22
-rw-r--r--android_webview/browser/browser_view_renderer_client.h2
-rw-r--r--android_webview/browser/browser_view_renderer_unittest.cc41
-rw-r--r--cc/output/begin_frame_args.cc2
-rw-r--r--cc/output/begin_frame_args.h1
-rw-r--r--cc/output/output_surface.h6
-rw-r--r--cc/output/output_surface_client.h2
-rw-r--r--cc/scheduler/scheduler.cc164
-rw-r--r--cc/scheduler/scheduler.h12
-rw-r--r--cc/scheduler/scheduler_state_machine.cc251
-rw-r--r--cc/scheduler/scheduler_state_machine.h43
-rw-r--r--cc/scheduler/scheduler_unittest.cc166
-rw-r--r--cc/surfaces/display.cc4
-rw-r--r--cc/surfaces/display.h1
-rw-r--r--cc/test/fake_layer_tree_host_impl_client.h1
-rw-r--r--cc/test/fake_output_surface.h1
-rw-r--r--cc/test/fake_output_surface_client.h1
-rw-r--r--cc/test/layer_tree_test.cc5
-rw-r--r--cc/test/layer_tree_test.h1
-rw-r--r--cc/trees/layer_tree_host_impl.cc4
-rw-r--r--cc/trees/layer_tree_host_impl.h4
-rw-r--r--cc/trees/layer_tree_host_impl_unittest.cc1
-rw-r--r--cc/trees/layer_tree_host_unittest.cc16
-rw-r--r--cc/trees/single_thread_proxy.cc10
-rw-r--r--cc/trees/single_thread_proxy.h3
-rw-r--r--cc/trees/thread_proxy.cc11
-rw-r--r--cc/trees/thread_proxy.h2
-rw-r--r--content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.cc10
-rw-r--r--content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h3
-rw-r--r--content/browser/android/in_process/synchronous_compositor_impl.cc69
-rw-r--r--content/browser/android/in_process/synchronous_compositor_impl.h15
-rw-r--r--content/browser/android/in_process/synchronous_compositor_output_surface.cc28
-rw-r--r--content/browser/android/in_process/synchronous_compositor_output_surface.h14
-rw-r--r--content/browser/renderer_host/render_widget_host_view_android.cc51
-rw-r--r--content/public/browser/android/synchronous_compositor.h5
-rw-r--r--content/public/browser/android/synchronous_compositor_client.h5
-rw-r--r--content/public/test/test_synchronous_compositor_android.h1
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(&current_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_;