summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cc/layers/layer.cc24
-rw-r--r--cc/layers/layer.h13
-rw-r--r--cc/layers/layer_impl.cc23
-rw-r--r--cc/layers/layer_impl.h2
-rw-r--r--cc/layers/layer_impl_unittest.cc72
-rw-r--r--cc/layers/layer_unittest.cc9
-rw-r--r--cc/layers/texture_layer_unittest.cc3
-rw-r--r--cc/scheduler/scheduler.cc4
-rw-r--r--cc/scheduler/scheduler.h2
-rw-r--r--cc/scheduler/scheduler_state_machine.cc59
-rw-r--r--cc/scheduler/scheduler_state_machine.h10
-rw-r--r--cc/scheduler/scheduler_state_machine_unittest.cc100
-rw-r--r--cc/scheduler/scheduler_unittest.cc11
-rw-r--r--cc/test/fake_content_layer.cc5
-rw-r--r--cc/test/fake_content_layer.h5
-rw-r--r--cc/test/fake_picture_layer.cc5
-rw-r--r--cc/test/fake_picture_layer.h10
-rw-r--r--cc/test/fake_proxy.h1
-rw-r--r--cc/test/layer_test_common.h16
-rw-r--r--cc/test/layer_tree_test.cc6
-rw-r--r--cc/test/layer_tree_test.h3
-rw-r--r--cc/trees/layer_tree_host.cc25
-rw-r--r--cc/trees/layer_tree_host.h2
-rw-r--r--cc/trees/layer_tree_host_impl.cc4
-rw-r--r--cc/trees/layer_tree_host_unittest.cc9
-rw-r--r--cc/trees/layer_tree_host_unittest_context.cc1
-rw-r--r--cc/trees/layer_tree_host_unittest_damage.cc1
-rw-r--r--cc/trees/layer_tree_host_unittest_scroll.cc214
-rw-r--r--cc/trees/layer_tree_impl.cc18
-rw-r--r--cc/trees/layer_tree_impl.h1
-rw-r--r--cc/trees/proxy.h1
-rw-r--r--cc/trees/single_thread_proxy.cc8
-rw-r--r--cc/trees/single_thread_proxy.h1
-rw-r--r--cc/trees/thread_proxy.cc101
-rw-r--r--cc/trees/thread_proxy.h6
35 files changed, 659 insertions, 116 deletions
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 5e7bd77..9d1cde5 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -121,6 +121,11 @@ void Layer::SetLayerTreeHost(LayerTreeHost* host) {
layer_tree_host_->set_needs_filter_context();
}
+void Layer::SetNeedsUpdate() {
+ if (layer_tree_host_ && !ignore_set_needs_commit_)
+ layer_tree_host_->SetNeedsUpdateLayers();
+}
+
void Layer::SetNeedsCommit() {
if (!layer_tree_host_)
return;
@@ -563,14 +568,17 @@ void Layer::SetScrollOffset(gfx::Vector2d scroll_offset) {
void Layer::SetScrollOffsetFromImplSide(gfx::Vector2d scroll_offset) {
DCHECK(IsPropertyChangeAllowed());
+ // This function only gets called during a begin frame, so there
+ // is no need to call SetNeedsUpdate here.
DCHECK(layer_tree_host_ && layer_tree_host_->CommitRequested());
if (scroll_offset_ == scroll_offset)
return;
scroll_offset_ = scroll_offset;
+ SetNeedsPushProperties();
if (!did_scroll_callback_.is_null())
did_scroll_callback_.Run();
- // Note: didScroll() could potentially change the layer structure.
- // "this" may have been destroyed during the process.
+ // The callback could potentially change the layer structure:
+ // "this" may have been destroyed during the process.
}
void Layer::SetMaxScrollOffset(gfx::Vector2d max_scroll_offset) {
@@ -663,14 +671,16 @@ void Layer::SetHideLayerAndSubtree(bool hide) {
}
void Layer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
+ if (!update_rect_.Contains(dirty_rect)) {
+ SetNeedsPushProperties();
+ }
+
update_rect_.Union(dirty_rect);
needs_display_ = true;
- // Simply mark the contents as dirty. For non-root layers, the call to
- // SetNeedsCommit will schedule a fresh compositing pass.
- // For the root layer, SetNeedsCommit has no effect.
- if (DrawsContent() && !update_rect_.IsEmpty())
- SetNeedsCommit();
+ if (DrawsContent() && !update_rect_.IsEmpty()) {
+ SetNeedsUpdate();
+ }
}
bool Layer::DescendantIsFixedToContainerLayer() const {
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index fb63c4c0..09f7f71 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -394,7 +394,18 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
Layer();
+ // These SetNeeds functions are in order of severity of update:
+ //
+ // Called when this layer has been modified in some way, but isn't sure
+ // that it needs a commit yet. It needs CalcDrawProperties and UpdateLayers
+ // before it knows whether or not a commit is required.
+ void SetNeedsUpdate();
+ // Called when a property has been modified in a way that the layer
+ // knows immediately that a commit is required. This implies SetNeedsUpdate
+ // as well as SetNeedsPushProperties to push that property.
void SetNeedsCommit();
+ // Called when there's been a change in layer structure. Implies both
+ // SetNeedsUpdate and SetNeedsCommit, but not SetNeedsPushProperties.
void SetNeedsFullTreeSync();
bool IsPropertyChangeAllowed() const;
@@ -435,7 +446,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
int layer_id_;
// When true, the layer is about to perform an update. Any commit requests
- // will be handled implcitly after the update completes.
+ // will be handled implicitly after the update completes.
bool ignore_set_needs_commit_;
private:
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 4865fe2..008c689 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -265,11 +265,30 @@ gfx::Vector2dF LayerImpl::ScrollBy(gfx::Vector2dF scroll) {
new_delta.SetToMax(min_delta);
new_delta.SetToMin(max_delta);
gfx::Vector2dF unscrolled = ScrollDelta() + scroll - new_delta;
-
SetScrollDelta(new_delta);
return unscrolled;
}
+void LayerImpl::ApplySentScrollDeltas() {
+ // Pending tree never has sent scroll deltas
+ DCHECK(layer_tree_impl()->IsActiveTree());
+
+ // Apply sent scroll deltas to scroll position / scroll delta as if the
+ // main thread had applied them and then committed those values.
+ //
+ // This function should not change the total scroll offset; it just shifts
+ // some of the scroll delta to the scroll offset. Therefore, adjust these
+ // variables directly rather than calling the scroll offset delegate to
+ // avoid sending it multiple spurious calls.
+ //
+ // Because of the way scroll delta is calculated with a delegate, this will
+ // leave the total scroll offset unchanged on this layer regardless of
+ // whether a delegate is being used.
+ scroll_offset_ += sent_scroll_delta_;
+ scroll_delta_ -= sent_scroll_delta_;
+ sent_scroll_delta_ = gfx::Vector2d();
+}
+
InputHandler::ScrollStatus LayerImpl::TryScroll(
gfx::PointF screen_space_point,
InputHandler::ScrollInputType type) const {
@@ -893,8 +912,8 @@ void LayerImpl::SetScrollDelta(gfx::Vector2dF scroll_delta) {
} else {
scroll_delta_ = scroll_delta;
}
- NoteLayerPropertyChangedForSubtree();
+ NoteLayerPropertyChangedForSubtree();
UpdateScrollbarPositions();
}
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index ff7e956..90da41a 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -330,6 +330,8 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver {
void SetScrollable(bool scrollable) { scrollable_ = scrollable; }
bool scrollable() const { return scrollable_; }
+ void ApplySentScrollDeltas();
+
void SetShouldScrollOnMainThread(bool should_scroll_on_main_thread) {
should_scroll_on_main_thread_ = should_scroll_on_main_thread;
}
diff --git a/cc/layers/layer_impl_unittest.cc b/cc/layers/layer_impl_unittest.cc
index 45ba641..a0235ae 100644
--- a/cc/layers/layer_impl_unittest.cc
+++ b/cc/layers/layer_impl_unittest.cc
@@ -482,5 +482,77 @@ TEST_F(LayerImplScrollTest, ScrollByWithAcceptingDelegate) {
EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
}
+TEST_F(LayerImplScrollTest, ApplySentScrollsNoDelegate) {
+ gfx::Vector2d max_scroll_offset(50, 80);
+ gfx::Vector2d scroll_offset(10, 5);
+ gfx::Vector2dF scroll_delta(20.5f, 8.5f);
+ gfx::Vector2d sent_scroll_delta(12, -3);
+
+ layer()->SetMaxScrollOffset(max_scroll_offset);
+ layer()->SetScrollOffset(scroll_offset);
+ layer()->ScrollBy(scroll_delta);
+ layer()->SetSentScrollDelta(sent_scroll_delta);
+
+ EXPECT_VECTOR_EQ(scroll_offset + scroll_delta, layer()->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(scroll_delta, layer()->ScrollDelta());
+ EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
+ EXPECT_VECTOR_EQ(sent_scroll_delta, layer()->sent_scroll_delta());
+
+ layer()->ApplySentScrollDeltas();
+
+ EXPECT_VECTOR_EQ(scroll_offset + scroll_delta, layer()->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(scroll_delta - sent_scroll_delta, layer()->ScrollDelta());
+ EXPECT_VECTOR_EQ(scroll_offset + sent_scroll_delta, layer()->scroll_offset());
+ EXPECT_VECTOR_EQ(gfx::Vector2d(), layer()->sent_scroll_delta());
+}
+
+TEST_F(LayerImplScrollTest, ApplySentScrollsWithIgnoringDelegate) {
+ gfx::Vector2d max_scroll_offset(50, 80);
+ gfx::Vector2d scroll_offset(10, 5);
+ gfx::Vector2d sent_scroll_delta(12, -3);
+ gfx::Vector2dF fixed_offset(32, 12);
+
+ layer()->SetMaxScrollOffset(max_scroll_offset);
+ layer()->SetScrollOffset(scroll_offset);
+ ScrollDelegateIgnore delegate;
+ delegate.set_fixed_offset(fixed_offset);
+ layer()->SetScrollOffsetDelegate(&delegate);
+ layer()->SetSentScrollDelta(sent_scroll_delta);
+
+ EXPECT_VECTOR_EQ(fixed_offset, layer()->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
+ EXPECT_VECTOR_EQ(sent_scroll_delta, layer()->sent_scroll_delta());
+
+ layer()->ApplySentScrollDeltas();
+
+ EXPECT_VECTOR_EQ(fixed_offset, layer()->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(scroll_offset + sent_scroll_delta, layer()->scroll_offset());
+ EXPECT_VECTOR_EQ(gfx::Vector2d(), layer()->sent_scroll_delta());
+}
+
+TEST_F(LayerImplScrollTest, ApplySentScrollsWithAcceptingDelegate) {
+ gfx::Vector2d max_scroll_offset(50, 80);
+ gfx::Vector2d scroll_offset(10, 5);
+ gfx::Vector2d sent_scroll_delta(12, -3);
+ gfx::Vector2dF scroll_delta(20.5f, 8.5f);
+
+ layer()->SetMaxScrollOffset(max_scroll_offset);
+ layer()->SetScrollOffset(scroll_offset);
+ ScrollDelegateAccept delegate;
+ layer()->SetScrollOffsetDelegate(&delegate);
+ layer()->ScrollBy(scroll_delta);
+ layer()->SetSentScrollDelta(sent_scroll_delta);
+
+ EXPECT_VECTOR_EQ(scroll_offset + scroll_delta, layer()->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
+ EXPECT_VECTOR_EQ(sent_scroll_delta, layer()->sent_scroll_delta());
+
+ layer()->ApplySentScrollDeltas();
+
+ EXPECT_VECTOR_EQ(scroll_offset + scroll_delta, layer()->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(scroll_offset + sent_scroll_delta, layer()->scroll_offset());
+ EXPECT_VECTOR_EQ(gfx::Vector2d(), layer()->sent_scroll_delta());
+}
+
} // namespace
} // namespace cc
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index f841e73..0c2fca6 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -44,6 +44,7 @@ class MockLayerTreeHost : public LayerTreeHost {
}
MOCK_METHOD0(SetNeedsCommit, void());
+ MOCK_METHOD0(SetNeedsUpdateLayers, void());
MOCK_METHOD0(SetNeedsFullTreeSync, void());
};
@@ -467,7 +468,7 @@ TEST_F(LayerTest, GetRootLayerAfterTreeManipulations) {
TEST_F(LayerTest, CheckSetNeedsDisplayCausesCorrectBehavior) {
// The semantics for SetNeedsDisplay which are tested here:
// 1. sets NeedsDisplay flag appropriately.
- // 2. indirectly calls SetNeedsCommit, exactly once for each call to
+ // 2. indirectly calls SetNeedsUpdate, exactly once for each call to
// SetNeedsDisplay.
scoped_refptr<Layer> test_layer = Layer::Create();
@@ -497,7 +498,7 @@ TEST_F(LayerTest, CheckSetNeedsDisplayCausesCorrectBehavior) {
// Case 1: Layer should accept dirty rects that go beyond its bounds.
test_layer->ResetNeedsDisplayForTesting();
EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
- EXPECT_SET_NEEDS_COMMIT(
+ EXPECT_SET_NEEDS_UPDATE(
1, test_layer->SetNeedsDisplayRect(out_of_bounds_dirty_rect));
EXPECT_TRUE(test_layer->NeedsDisplayForTesting());
test_layer->ResetNeedsDisplayForTesting();
@@ -505,7 +506,7 @@ TEST_F(LayerTest, CheckSetNeedsDisplayCausesCorrectBehavior) {
// Case 2: SetNeedsDisplay() without the dirty rect arg.
test_layer->ResetNeedsDisplayForTesting();
EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
- EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetNeedsDisplay());
+ EXPECT_SET_NEEDS_UPDATE(1, test_layer->SetNeedsDisplay());
EXPECT_TRUE(test_layer->NeedsDisplayForTesting());
test_layer->ResetNeedsDisplayForTesting();
@@ -513,7 +514,7 @@ TEST_F(LayerTest, CheckSetNeedsDisplayCausesCorrectBehavior) {
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsDrawable(false));
test_layer->ResetNeedsDisplayForTesting();
EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
- EXPECT_SET_NEEDS_COMMIT(0, test_layer->SetNeedsDisplayRect(dirty1));
+ EXPECT_SET_NEEDS_UPDATE(0, test_layer->SetNeedsDisplayRect(dirty1));
EXPECT_TRUE(test_layer->NeedsDisplayForTesting());
}
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index ccbd0a7..cbb66db 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -38,6 +38,7 @@ class MockLayerTreeHost : public LayerTreeHost {
MOCK_METHOD0(AcquireLayerTextures, void());
MOCK_METHOD0(SetNeedsCommit, void());
+ MOCK_METHOD0(SetNeedsUpdateLayers, void());
MOCK_METHOD1(StartRateLimiter, void(WebKit::WebGraphicsContext3D* context));
MOCK_METHOD1(StopRateLimiter, void(WebKit::WebGraphicsContext3D* context));
};
@@ -118,7 +119,7 @@ TEST_F(TextureLayerTest, SyncImplWhenDrawing) {
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
+ EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(1);
test_layer->SetNeedsDisplayRect(dirty_rect);
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 5e397bd..010cc99 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -85,9 +85,9 @@ void Scheduler::FinishCommit() {
ProcessScheduledActions();
}
-void Scheduler::BeginFrameAbortedByMainThread() {
+void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) {
TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread");
- state_machine_.BeginFrameAbortedByMainThread();
+ state_machine_.BeginFrameAbortedByMainThread(did_handle);
ProcessScheduledActions();
}
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index 48a3bb2..230f20d 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -86,7 +86,7 @@ class CC_EXPORT Scheduler {
void DidSwapUseIncompleteTile();
void FinishCommit();
- void BeginFrameAbortedByMainThread();
+ void BeginFrameAbortedByMainThread(bool did_handle);
void DidLoseOutputSurface();
void DidCreateAndInitializeOutputSurface();
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 3747c0b..ed9c15f 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -15,6 +15,7 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
commit_state_(COMMIT_STATE_IDLE),
commit_count_(0),
current_frame_number_(0),
+ last_frame_number_where_begin_frame_sent_to_main_thread_(-1),
last_frame_number_where_draw_was_called_(-1),
last_frame_number_where_tree_activation_attempted_(-1),
last_frame_number_where_update_visible_tiles_was_called_(-1),
@@ -24,6 +25,7 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
swap_used_incomplete_tile_(false),
needs_forced_redraw_(false),
needs_forced_redraw_after_next_commit_(false),
+ needs_redraw_after_next_commit_(false),
needs_commit_(false),
needs_forced_commit_(false),
expect_immediate_begin_frame_for_main_thread_(false),
@@ -116,6 +118,19 @@ bool SchedulerStateMachine::HasUpdatedVisibleTilesThisFrame() const {
last_frame_number_where_update_visible_tiles_was_called_;
}
+void SchedulerStateMachine::SetPostCommitFlags() {
+ // This post-commit work is common to both completed and aborted commits.
+ if (needs_forced_redraw_after_next_commit_) {
+ needs_forced_redraw_after_next_commit_ = false;
+ needs_forced_redraw_ = true;
+ }
+ if (needs_redraw_after_next_commit_) {
+ needs_redraw_after_next_commit_ = false;
+ needs_redraw_ = true;
+ }
+ texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD;
+}
+
bool SchedulerStateMachine::DrawSuspendedUntilCommit() const {
if (!can_draw_)
return true;
@@ -184,7 +199,7 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
return ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD;
switch (commit_state_) {
- case COMMIT_STATE_IDLE:
+ case COMMIT_STATE_IDLE: {
if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE &&
needs_forced_redraw_)
return ACTION_DRAW_FORCED;
@@ -205,14 +220,18 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
return needs_forced_redraw_ ? ACTION_DRAW_FORCED
: ACTION_DRAW_IF_POSSIBLE;
}
- if (needs_commit_ &&
- ((visible_ && output_surface_state_ == OUTPUT_SURFACE_ACTIVE)
- || needs_forced_commit_))
+ bool can_commit_this_frame =
+ visible_ &&
+ current_frame_number_ >
+ last_frame_number_where_begin_frame_sent_to_main_thread_;
+ if (needs_commit_ && ((can_commit_this_frame &&
+ output_surface_state_ == OUTPUT_SURFACE_ACTIVE) ||
+ needs_forced_commit_))
// TODO(enne): Should probably drop the active tree on force commit.
return has_pending_tree_ ? ACTION_NONE
: ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD;
return ACTION_NONE;
-
+ }
case COMMIT_STATE_FRAME_IN_PROGRESS:
if (ShouldUpdateVisibleTiles())
return ACTION_UPDATE_VISIBLE_TILES;
@@ -239,7 +258,11 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
// COMMIT_STATE_WAITING_FOR_FIRST_DRAW wants to enforce a draw. If
// can_draw_ is false or textures are not available, proceed to the next
// step (similar as in COMMIT_STATE_IDLE).
- bool can_commit = visible_ || needs_forced_commit_;
+ bool can_commit =
+ needs_forced_commit_ ||
+ (visible_ &&
+ current_frame_number_ >
+ last_frame_number_where_begin_frame_sent_to_main_thread_);
if (needs_commit_ && can_commit && DrawSuspendedUntilCommit())
return has_pending_tree_ ? ACTION_NONE
: ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD;
@@ -276,10 +299,16 @@ void SchedulerStateMachine::UpdateState(Action action) {
case ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD:
DCHECK(!has_pending_tree_);
- DCHECK(visible_ || needs_forced_commit_);
+ if (!needs_forced_commit_) {
+ DCHECK(visible_);
+ DCHECK_GT(current_frame_number_,
+ last_frame_number_where_begin_frame_sent_to_main_thread_);
+ }
commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
needs_commit_ = false;
needs_forced_commit_ = false;
+ last_frame_number_where_begin_frame_sent_to_main_thread_ =
+ current_frame_number_;
return;
case ACTION_COMMIT:
@@ -293,13 +322,7 @@ void SchedulerStateMachine::UpdateState(Action action) {
needs_redraw_ = true;
if (draw_if_possible_failed_)
last_frame_number_where_draw_was_called_ = -1;
-
- if (needs_forced_redraw_after_next_commit_) {
- needs_forced_redraw_after_next_commit_ = false;
- needs_forced_redraw_ = true;
- }
-
- texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD;
+ SetPostCommitFlags();
return;
case ACTION_DRAW_FORCED:
@@ -367,12 +390,12 @@ bool SchedulerStateMachine::ProactiveBeginFrameWantedByImplThread() const {
}
void SchedulerStateMachine::DidEnterBeginFrame(const BeginFrameArgs& args) {
+ current_frame_number_++;
inside_begin_frame_ = true;
last_begin_frame_args_ = args;
}
void SchedulerStateMachine::DidLeaveBeginFrame() {
- current_frame_number_++;
inside_begin_frame_ = false;
}
@@ -422,10 +445,13 @@ void SchedulerStateMachine::FinishCommit() {
commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
}
-void SchedulerStateMachine::BeginFrameAbortedByMainThread() {
+void SchedulerStateMachine::BeginFrameAbortedByMainThread(bool did_handle) {
DCHECK_EQ(commit_state_, COMMIT_STATE_FRAME_IN_PROGRESS);
if (expect_immediate_begin_frame_for_main_thread_) {
expect_immediate_begin_frame_for_main_thread_ = false;
+ } else if (did_handle) {
+ commit_state_ = COMMIT_STATE_IDLE;
+ SetPostCommitFlags();
} else {
commit_state_ = COMMIT_STATE_IDLE;
SetNeedsCommit();
@@ -458,6 +484,7 @@ void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() {
// sort themselves out with a commit.
needs_redraw_ = false;
}
+ needs_redraw_after_next_commit_ = true;
did_create_and_initialize_first_output_surface_ = true;
}
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index 5a29830d..5c7d5b5 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -79,7 +79,7 @@ class CC_EXPORT SchedulerStateMachine {
// Indicates that the system has entered and left a BeginFrame callback.
// The scheduler will not draw more than once in a given BeginFrame
- // callback.
+ // callback nor send more than one BeginFrame message.
void DidEnterBeginFrame(const BeginFrameArgs& args);
void DidLeaveBeginFrame();
bool inside_begin_frame() const { return inside_begin_frame_; }
@@ -120,8 +120,9 @@ class CC_EXPORT SchedulerStateMachine {
// Call this only in response to receiving an
// ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD from NextAction if the client
- // rejects the begin frame message.
- void BeginFrameAbortedByMainThread();
+ // rejects the begin frame message. If did_handle is false, then
+ // another commit will be retried soon.
+ void BeginFrameAbortedByMainThread(bool did_handle);
// Request exclusive access to the textures that back single buffered
// layers on behalf of the main thread. Upon acquisition,
@@ -168,6 +169,7 @@ class CC_EXPORT SchedulerStateMachine {
bool HasDrawnThisFrame() const;
bool HasAttemptedTreeActivationThisFrame() const;
bool HasUpdatedVisibleTilesThisFrame() const;
+ void SetPostCommitFlags();
const SchedulerSettings settings_;
@@ -175,6 +177,7 @@ class CC_EXPORT SchedulerStateMachine {
int commit_count_;
int current_frame_number_;
+ int last_frame_number_where_begin_frame_sent_to_main_thread_;
int last_frame_number_where_draw_was_called_;
int last_frame_number_where_tree_activation_attempted_;
int last_frame_number_where_update_visible_tiles_was_called_;
@@ -184,6 +187,7 @@ class CC_EXPORT SchedulerStateMachine {
bool swap_used_incomplete_tile_;
bool needs_forced_redraw_;
bool needs_forced_redraw_after_next_commit_;
+ bool needs_redraw_after_next_commit_;
bool needs_commit_;
bool needs_forced_commit_;
bool expect_immediate_begin_frame_for_main_thread_;
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index 7036459..c7210eb 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -718,7 +718,7 @@ TEST(SchedulerStateMachineTest, TestGoesInvisibleBeforeFinishCommit) {
// Become invisible and abort the main thread's begin frame.
state.SetVisible(false);
- state.BeginFrameAbortedByMainThread();
+ state.BeginFrameAbortedByMainThread(false);
// We should now be back in the idle state as if we didn't start a frame at
// all.
@@ -728,8 +728,14 @@ TEST(SchedulerStateMachineTest, TestGoesInvisibleBeforeFinishCommit) {
// Become visible again.
state.SetVisible(true);
- // We should be beginning a frame now.
+ // Although we have aborted on this frame and haven't cancelled the commit
+ // (i.e. need another), don't send another begin frame yet.
EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_TRUE(state.NeedsCommit());
+
+ // Start a new frame.
+ state.DidEnterBeginFrame(BeginFrameArgs::CreateForTesting());
EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD,
state.NextAction());
@@ -741,6 +747,52 @@ TEST(SchedulerStateMachineTest, TestGoesInvisibleBeforeFinishCommit) {
state.CommitState());
}
+TEST(SchedulerStateMachineTest, AbortBeginFrameAndCancelCommit) {
+ SchedulerSettings default_scheduler_settings;
+ StateMachine state(default_scheduler_settings);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.DidCreateAndInitializeOutputSurface();
+ state.SetVisible(true);
+ state.SetCanDraw(true);
+
+ // Get into a begin frame / commit state.
+ state.SetNeedsCommit();
+ EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD,
+ state.NextAction());
+ state.UpdateState(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD);
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
+ state.CommitState());
+ EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+
+ // Abort the commit, cancelling future commits.
+ state.BeginFrameAbortedByMainThread(true);
+
+ // Verify that another commit doesn't start on the same frame.
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_FALSE(state.NeedsCommit());
+
+ // Start a new frame; draw because this is the first frame since output
+ // surface init'd.
+ state.DidEnterBeginFrame(BeginFrameArgs::CreateForTesting());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE, state.NextAction());
+ state.DidLeaveBeginFrame();
+
+ // Verify another commit doesn't start on another frame either.
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_FALSE(state.NeedsCommit());
+
+ // Verify another commit can start if requested, though.
+ state.SetNeedsCommit();
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD,
+ state.NextAction());
+}
+
TEST(SchedulerStateMachineTest, TestFirstContextCreation) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
@@ -816,15 +868,23 @@ TEST(SchedulerStateMachineTest,
// Recreate the context
state.DidCreateAndInitializeOutputSurface();
+ EXPECT_FALSE(state.RedrawPending());
// When the context is recreated, we should begin a commit
EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD,
state.NextAction());
state.UpdateState(state.NextAction());
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
+ state.CommitState());
+ state.FinishCommit();
+ EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ state.UpdateState(state.NextAction());
+ // Finishing the first commit after initializing an output surface should
+ // automatically cause a redraw.
+ EXPECT_TRUE(state.RedrawPending());
// Once the context is recreated, whether we draw should be based on
// SetCanDraw.
- state.SetNeedsRedraw(true);
state.DidEnterBeginFrame(BeginFrameArgs::CreateForTesting());
EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE, state.NextAction());
state.SetCanDraw(false);
@@ -1192,7 +1252,7 @@ TEST(SchedulerStateMachineTest,
// Become invisible and abort the main thread's begin frame.
state.SetVisible(false);
- state.BeginFrameAbortedByMainThread();
+ state.BeginFrameAbortedByMainThread(false);
// Should be back in the idle state, but needing a commit.
EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
@@ -1295,5 +1355,37 @@ TEST(SchedulerStateMachineTest, ReportIfNotDrawingFromAcquiredTextures) {
EXPECT_FALSE(state.DrawSuspendedUntilCommit());
}
+TEST(SchedulerStateMachineTest, AcquireTexturesWithAbort) {
+ SchedulerSettings default_scheduler_settings;
+ SchedulerStateMachine state(default_scheduler_settings);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.DidCreateAndInitializeOutputSurface();
+ state.SetCanDraw(true);
+ state.SetVisible(true);
+
+ state.SetMainThreadNeedsLayerTextures();
+ EXPECT_EQ(
+ SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD,
+ state.NextAction());
+ state.UpdateState(state.NextAction());
+ EXPECT_TRUE(state.DrawSuspendedUntilCommit());
+
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+
+ state.SetNeedsCommit();
+ EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD,
+ state.NextAction());
+ state.UpdateState(state.NextAction());
+ EXPECT_TRUE(state.DrawSuspendedUntilCommit());
+
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+
+ state.BeginFrameAbortedByMainThread(true);
+
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_FALSE(state.DrawSuspendedUntilCommit());
+}
+
} // namespace
} // namespace cc
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 0a3c250..930111c 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -378,12 +378,17 @@ TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) {
client);
client.Reset();
+ // Already sent a begin frame on this current frame, so wait.
+ scheduler->SetVisible(true);
+ EXPECT_EQ(0, client.num_actions_());
+ client.Reset();
+
// Regaining visibility with textures acquired by main thread while
// compositor is waiting for first draw should result in a request
// for a new frame in order to escape a deadlock.
- scheduler->SetVisible(true);
- EXPECT_SINGLE_ACTION("ScheduledActionSendBeginFrameToMainThread", client);
- client.Reset();
+ scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2);
+ EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
}
class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
diff --git a/cc/test/fake_content_layer.cc b/cc/test/fake_content_layer.cc
index 5dcc512..077831fd 100644
--- a/cc/test/fake_content_layer.cc
+++ b/cc/test/fake_content_layer.cc
@@ -12,7 +12,8 @@ namespace cc {
FakeContentLayer::FakeContentLayer(ContentLayerClient* client)
: ContentLayer(client),
update_count_(0),
- push_properties_count_(0) {
+ push_properties_count_(0),
+ always_update_resources_(false) {
SetAnchorPoint(gfx::PointF(0.f, 0.f));
SetBounds(gfx::Size(1, 1));
SetIsDrawable(true);
@@ -29,7 +30,7 @@ bool FakeContentLayer::Update(ResourceUpdateQueue* queue,
const OcclusionTracker* occlusion) {
bool updated = ContentLayer::Update(queue, occlusion);
update_count_++;
- return updated;
+ return updated || always_update_resources_;
}
void FakeContentLayer::PushPropertiesTo(LayerImpl* layer) {
diff --git a/cc/test/fake_content_layer.h b/cc/test/fake_content_layer.h
index 6b7a37d..191a634 100644
--- a/cc/test/fake_content_layer.h
+++ b/cc/test/fake_content_layer.h
@@ -29,6 +29,10 @@ class FakeContentLayer : public ContentLayer {
ResourceUpdateQueue* queue,
const OcclusionTracker* occlusion) OVERRIDE;
+ void set_always_update_resources(bool always_update_resources) {
+ always_update_resources_ = always_update_resources;
+ }
+
virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
bool HaveBackingAt(int i, int j);
@@ -39,6 +43,7 @@ class FakeContentLayer : public ContentLayer {
size_t update_count_;
size_t push_properties_count_;
+ bool always_update_resources_;
};
} // namespace cc
diff --git a/cc/test/fake_picture_layer.cc b/cc/test/fake_picture_layer.cc
index 997197c..69292c3 100644
--- a/cc/test/fake_picture_layer.cc
+++ b/cc/test/fake_picture_layer.cc
@@ -11,7 +11,8 @@ namespace cc {
FakePictureLayer::FakePictureLayer(ContentLayerClient* client)
: PictureLayer(client),
update_count_(0),
- push_properties_count_(0) {
+ push_properties_count_(0),
+ always_update_resources_(false) {
SetAnchorPoint(gfx::PointF(0.f, 0.f));
SetBounds(gfx::Size(1, 1));
SetIsDrawable(true);
@@ -28,7 +29,7 @@ bool FakePictureLayer::Update(ResourceUpdateQueue* queue,
const OcclusionTracker* occlusion) {
bool updated = PictureLayer::Update(queue, occlusion);
update_count_++;
- return updated;
+ return updated || always_update_resources_;
}
void FakePictureLayer::PushPropertiesTo(LayerImpl* layer) {
diff --git a/cc/test/fake_picture_layer.h b/cc/test/fake_picture_layer.h
index b5b81de..824ac6c 100644
--- a/cc/test/fake_picture_layer.h
+++ b/cc/test/fake_picture_layer.h
@@ -26,9 +26,12 @@ class FakePictureLayer : public PictureLayer {
size_t push_properties_count() const { return push_properties_count_; }
void reset_push_properties_count() { push_properties_count_ = 0; }
- virtual bool Update(
- ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE;
+ void set_always_update_resources(bool always_update_resources) {
+ always_update_resources_ = always_update_resources;
+ }
+
+ virtual bool Update(ResourceUpdateQueue* queue,
+ const OcclusionTracker* occlusion) OVERRIDE;
virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
@@ -38,6 +41,7 @@ class FakePictureLayer : public PictureLayer {
size_t update_count_;
size_t push_properties_count_;
+ bool always_update_resources_;
};
} // namespace cc
diff --git a/cc/test/fake_proxy.h b/cc/test/fake_proxy.h
index 76de4b0..8cc3311 100644
--- a/cc/test/fake_proxy.h
+++ b/cc/test/fake_proxy.h
@@ -29,6 +29,7 @@ class FakeProxy : public Proxy {
virtual void CreateAndInitializeOutputSurface() OVERRIDE;
virtual const RendererCapabilities& GetRendererCapabilities() const OVERRIDE;
virtual void SetNeedsAnimate() OVERRIDE {}
+ virtual void SetNeedsUpdateLayers() OVERRIDE {}
virtual void SetNeedsCommit() OVERRIDE {}
virtual void SetNeedsRedraw(gfx::Rect damage_rect) OVERRIDE {}
virtual void SetDeferCommits(bool defer_commits) OVERRIDE {}
diff --git a/cc/test/layer_test_common.h b/cc/test/layer_test_common.h
index 94e2f2a..0021398 100644
--- a/cc/test/layer_test_common.h
+++ b/cc/test/layer_test_common.h
@@ -5,10 +5,18 @@
#ifndef CC_TEST_LAYER_TEST_COMMON_H_
#define CC_TEST_LAYER_TEST_COMMON_H_
-#define EXPECT_SET_NEEDS_COMMIT(expect, code_to_test) do { \
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times((expect)); \
- code_to_test; \
- Mock::VerifyAndClearExpectations(layer_tree_host_.get()); \
+#define EXPECT_SET_NEEDS_COMMIT(expect, code_to_test) \
+ do { \
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times((expect)); \
+ code_to_test; \
+ Mock::VerifyAndClearExpectations(layer_tree_host_.get()); \
+ } while (false)
+
+#define EXPECT_SET_NEEDS_UPDATE(expect, code_to_test) \
+ do { \
+ EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times((expect)); \
+ code_to_test; \
+ Mock::VerifyAndClearExpectations(layer_tree_host_.get()); \
} while (false)
namespace gfx { class Rect; }
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index ed97752..6193d84 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -233,9 +233,9 @@ class LayerTreeHostClientForTesting : public LayerTreeHostClient {
}
virtual ~LayerTreeHostClientForTesting() {}
- virtual void WillBeginFrame() OVERRIDE {}
+ virtual void WillBeginFrame() OVERRIDE { test_hooks_->WillBeginFrame(); }
- virtual void DidBeginFrame() OVERRIDE {}
+ virtual void DidBeginFrame() OVERRIDE { test_hooks_->DidBeginFrame(); }
virtual void Animate(double monotonic_time) OVERRIDE {
test_hooks_->Animate(base::TimeTicks::FromInternalValue(
@@ -263,7 +263,7 @@ class LayerTreeHostClientForTesting : public LayerTreeHostClient {
test_hooks_->DidFailToInitializeOutputSurface();
}
- virtual void WillCommit() OVERRIDE {}
+ virtual void WillCommit() OVERRIDE { test_hooks_->WillCommit(); }
virtual void DidCommit() OVERRIDE {
test_hooks_->DidCommit();
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index b92e3af..61226dd 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -52,10 +52,13 @@ class TestHooks : public AnimationDelegate {
virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
float scale) {}
virtual void Animate(base::TimeTicks monotonic_time) {}
+ virtual void WillBeginFrame() {}
+ virtual void DidBeginFrame() {}
virtual void Layout() {}
virtual void DidInitializeOutputSurface(bool succeeded) {}
virtual void DidFailToInitializeOutputSurface() {}
virtual void DidAddAnimation() {}
+ virtual void WillCommit() {}
virtual void DidCommit() {}
virtual void DidCommitAndDrawFrame() {}
virtual void DidCompleteSwapBuffers() {}
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index cdb5f61..0c82db8 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -469,6 +469,8 @@ void LayerTreeHost::SetNeedsAnimate() {
proxy_->SetNeedsAnimate();
}
+void LayerTreeHost::SetNeedsUpdateLayers() { proxy_->SetNeedsUpdateLayers(); }
+
void LayerTreeHost::SetNeedsCommit() {
if (!prepaint_callback_.IsCancelled()) {
TRACE_EVENT_INSTANT0("cc",
@@ -581,6 +583,11 @@ void LayerTreeHost::SetOverdrawBottomHeight(float overdraw_bottom_height) {
SetNeedsCommit();
}
+void LayerTreeHost::ApplyPageScaleDeltaFromImplSide(float page_scale_delta) {
+ DCHECK(CommitRequested());
+ page_scale_factor_ *= page_scale_delta;
+}
+
void LayerTreeHost::SetPageScaleFactorAndLimits(float page_scale_factor,
float min_page_scale_factor,
float max_page_scale_factor) {
@@ -965,8 +972,8 @@ void LayerTreeHost::ApplyScrollAndScale(const ScrollAndScaleSet& info) {
if (!root_layer_.get())
return;
- Layer* root_scroll_layer = FindFirstScrollableLayer(root_layer_.get());
gfx::Vector2d root_scroll_delta;
+ Layer* root_scroll_layer = FindFirstScrollableLayer(root_layer_.get());
for (size_t i = 0; i < info.scrolls.size(); ++i) {
Layer* layer =
@@ -981,8 +988,22 @@ void LayerTreeHost::ApplyScrollAndScale(const ScrollAndScaleSet& info) {
info.scrolls[i].scroll_delta);
}
}
- if (!root_scroll_delta.IsZero() || info.page_scale_delta != 1.f)
+
+ if (!root_scroll_delta.IsZero() || info.page_scale_delta != 1.f) {
+ // SetScrollOffsetFromImplSide above could have destroyed the tree,
+ // so re-get this layer before doing anything to it.
+ root_scroll_layer = FindFirstScrollableLayer(root_layer_.get());
+
+ // Preemptively apply the scroll offset and scale delta here before sending
+ // it to the client. If the client comes back and sets it to the same
+ // value, then the layer can early out without needing a full commit.
+ if (root_scroll_layer) {
+ root_scroll_layer->SetScrollOffsetFromImplSide(
+ root_scroll_layer->scroll_offset() + root_scroll_delta);
+ }
+ ApplyPageScaleDeltaFromImplSide(info.page_scale_delta);
client_->ApplyScrollAndScale(root_scroll_delta, info.page_scale_delta);
+ }
}
void LayerTreeHost::StartRateLimiter(WebKit::WebGraphicsContext3D* context3d) {
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index f04871a..2ec3eac 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -165,6 +165,7 @@ class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) {
const RendererCapabilities& GetRendererCapabilities() const;
void SetNeedsAnimate();
+ virtual void SetNeedsUpdateLayers();
virtual void SetNeedsCommit();
virtual void SetNeedsFullTreeSync();
void SetNeedsRedraw();
@@ -189,6 +190,7 @@ class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) {
gfx::Size device_viewport_size() const { return device_viewport_size_; }
float overdraw_bottom_height() const { return overdraw_bottom_height_; }
+ void ApplyPageScaleDeltaFromImplSide(float page_scale_delta);
void SetPageScaleFactorAndLimits(float page_scale_factor,
float min_page_scale_factor,
float max_page_scale_factor);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 629877f..f97eea0 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1180,8 +1180,10 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame,
TRACE_EVENT0("cc", "LayerTreeHostImpl::DrawLayers");
DCHECK(CanDraw());
- if (frame->has_no_damage)
+ if (frame->has_no_damage) {
+ TRACE_EVENT0("cc", "EarlyOut_NoDamage");
return;
+ }
DCHECK(!frame->render_passes.empty());
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 4d768205..e9435f7 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -1812,7 +1812,7 @@ class LayerTreeHostTestContinuousCommit : public LayerTreeHostTest {
virtual void DidCommit() OVERRIDE {
if (num_draw_layers_ == 2)
return;
- layer_tree_host()->root_layer()->SetNeedsDisplay();
+ layer_tree_host()->SetNeedsCommit();
}
virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
@@ -3099,6 +3099,9 @@ class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest {
virtual void SetupTree() OVERRIDE {
layer_ = FakePictureLayer::Create(&client_);
+ // Force commits to not be aborted so new frames get drawn, otherwise
+ // the renderer gets deferred initialized but nothing new needs drawing.
+ layer_->set_always_update_resources(true);
layer_tree_host()->SetRootLayer(layer_);
LayerTreeHostTest::SetupTree();
}
@@ -3395,9 +3398,11 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest {
++expected_push_properties_grandchild_;
break;
case 16:
+ // SetNeedsDisplay does not always set needs commit (so call it
+ // explicitly), but is a property change.
child_->SetNeedsDisplay();
- // The modified layer needs commit
++expected_push_properties_child_;
+ layer_tree_host()->SetNeedsCommit();
break;
case 17:
EndTest();
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index ccb7afd..b014941 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -286,6 +286,7 @@ class LayerTreeHostContextTestLostContextSucceeds
virtual void InvalidateAndSetNeedsCommit() {
// Cause damage so we try to draw.
layer_tree_host()->root_layer()->SetNeedsDisplay();
+ layer_tree_host()->SetNeedsCommit();
}
bool NextTestCase() {
diff --git a/cc/trees/layer_tree_host_unittest_damage.cc b/cc/trees/layer_tree_host_unittest_damage.cc
index 523eecd..e8ae7a2 100644
--- a/cc/trees/layer_tree_host_unittest_damage.cc
+++ b/cc/trees/layer_tree_host_unittest_damage.cc
@@ -87,6 +87,7 @@ class LayerTreeHostDamageTestNoDamageDoesNotSwap
case 3:
// Cause non-visible damage.
content_->SetNeedsDisplayRect(gfx::Rect(1990, 1990, 10, 10));
+ layer_tree_host()->SetNeedsCommit();
break;
}
}
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index b07b386..f0e1754 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -70,10 +70,8 @@ class LayerTreeHostScrollTestScrollSimple : public LayerTreeHostScrollTest {
}
}
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta, float scale)
- OVERRIDE {
- gfx::Vector2d offset = layer_tree_host()->root_layer()->scroll_offset();
- layer_tree_host()->root_layer()->SetScrollOffset(offset + scroll_delta);
+ virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
+ float scale) OVERRIDE {
num_scrolls_++;
}
@@ -150,10 +148,8 @@ class LayerTreeHostScrollTestScrollMultipleRedraw
}
}
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta, float scale)
- OVERRIDE {
- gfx::Vector2d offset = layer_tree_host()->root_layer()->scroll_offset();
- layer_tree_host()->root_layer()->SetScrollOffset(offset + scroll_delta);
+ virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
+ float scale) OVERRIDE {
num_scrolls_++;
}
@@ -167,6 +163,182 @@ class LayerTreeHostScrollTestScrollMultipleRedraw
MULTI_THREAD_TEST_F(LayerTreeHostScrollTestScrollMultipleRedraw);
+class LayerTreeHostScrollTestScrollAbortedCommit
+ : public LayerTreeHostScrollTest {
+ public:
+ LayerTreeHostScrollTestScrollAbortedCommit()
+ : initial_scroll_(50, 60),
+ impl_scroll_(-3, 2),
+ second_main_scroll_(14, -3),
+ impl_scale_(2.f),
+ num_will_begin_frames_(0),
+ num_did_begin_frames_(0),
+ num_will_commits_(0),
+ num_did_commits_(0),
+ num_impl_commits_(0),
+ num_impl_scrolls_(0) {}
+
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+ virtual void SetupTree() OVERRIDE {
+ LayerTreeHostScrollTest::SetupTree();
+ scoped_refptr<Layer> root_scroll_layer = Layer::Create();
+ root_scroll_layer->SetScrollable(true);
+ root_scroll_layer->SetScrollOffset(initial_scroll_);
+ root_scroll_layer->SetBounds(gfx::Size(200, 200));
+ root_scroll_layer->SetMaxScrollOffset(gfx::Vector2d(100, 100));
+ root_scroll_layer->SetIsDrawable(true);
+ layer_tree_host()->root_layer()->AddChild(root_scroll_layer);
+
+ layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f);
+ }
+
+ virtual void WillBeginFrame() OVERRIDE {
+ num_will_begin_frames_++;
+ Layer* root_scroll_layer = layer_tree_host()->root_layer()->children()[0];
+ switch (num_will_begin_frames_) {
+ case 1:
+ // This will not be aborted because of the initial prop changes.
+ EXPECT_EQ(0, num_impl_scrolls_);
+ EXPECT_EQ(0, layer_tree_host()->source_frame_number());
+ EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(), initial_scroll_);
+ EXPECT_EQ(1.f, layer_tree_host()->page_scale_factor());
+ break;
+ case 2:
+ // This commit will be aborted, and another commit will be
+ // initiated from the redraw.
+ EXPECT_EQ(1, num_impl_scrolls_);
+ EXPECT_EQ(1, layer_tree_host()->source_frame_number());
+ EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(),
+ initial_scroll_ + impl_scroll_);
+ EXPECT_EQ(impl_scale_, layer_tree_host()->page_scale_factor());
+ PostSetNeedsRedrawToMainThread();
+ break;
+ case 3:
+ // This commit will not be aborted because of the scroll change.
+ EXPECT_EQ(2, num_impl_scrolls_);
+ EXPECT_EQ(1, layer_tree_host()->source_frame_number());
+ EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(),
+ initial_scroll_ + impl_scroll_ + impl_scroll_);
+ EXPECT_EQ(impl_scale_ * impl_scale_,
+ layer_tree_host()->page_scale_factor());
+ root_scroll_layer->SetScrollOffset(root_scroll_layer->scroll_offset() +
+ second_main_scroll_);
+ break;
+ case 4:
+ // This commit will also be aborted.
+ EXPECT_EQ(3, num_impl_scrolls_);
+ EXPECT_EQ(2, layer_tree_host()->source_frame_number());
+ EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(),
+ initial_scroll_ + impl_scroll_ + impl_scroll_ +
+ impl_scroll_ + second_main_scroll_);
+ // End the test by drawing to verify this commit is also aborted.
+ PostSetNeedsRedrawToMainThread();
+ break;
+ }
+ }
+
+ virtual void DidBeginFrame() OVERRIDE { num_did_begin_frames_++; }
+
+ virtual void WillCommit() OVERRIDE { num_will_commits_++; }
+
+ virtual void DidCommit() OVERRIDE { num_did_commits_++; }
+
+ virtual void BeginCommitOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ num_impl_commits_++;
+ }
+
+ virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ LayerImpl* root_scroll_layer =
+ impl->active_tree()->root_layer()->children()[0];
+
+ if (impl->active_tree()->source_frame_number() == 0 &&
+ impl->SourceAnimationFrameNumber() == 1) {
+ // First draw
+ EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), gfx::Vector2d());
+ root_scroll_layer->ScrollBy(impl_scroll_);
+ EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), impl_scroll_);
+ EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(), initial_scroll_);
+
+ EXPECT_EQ(1.f, impl->active_tree()->page_scale_delta());
+ EXPECT_EQ(1.f, impl->active_tree()->total_page_scale_factor());
+ impl->active_tree()->SetPageScaleDelta(impl_scale_);
+ EXPECT_EQ(impl_scale_, impl->active_tree()->page_scale_delta());
+ EXPECT_EQ(impl_scale_, impl->active_tree()->total_page_scale_factor());
+
+ // To simplify the testing flow, don't redraw here, just commit.
+ impl->SetNeedsCommit();
+ } else if (impl->active_tree()->source_frame_number() == 0 &&
+ impl->SourceAnimationFrameNumber() == 2) {
+ // Test a second draw after an aborted commit.
+ // The scroll/scale values should be baked into the offset/scale factor
+ // since the main thread consumed but aborted the begin frame.
+ EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), gfx::Vector2d());
+ root_scroll_layer->ScrollBy(impl_scroll_);
+ EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), impl_scroll_);
+ EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(),
+ initial_scroll_ + impl_scroll_);
+
+ EXPECT_EQ(1.f, impl->active_tree()->page_scale_delta());
+ EXPECT_EQ(impl_scale_, impl->active_tree()->total_page_scale_factor());
+ impl->active_tree()->SetPageScaleDelta(impl_scale_);
+ EXPECT_EQ(impl_scale_, impl->active_tree()->page_scale_delta());
+ EXPECT_EQ(impl_scale_ * impl_scale_,
+ impl->active_tree()->total_page_scale_factor());
+
+ impl->SetNeedsCommit();
+ } else if (impl->active_tree()->source_frame_number() == 1 &&
+ impl->SourceAnimationFrameNumber() == 3) {
+ // Third draw after the second full commit.
+ EXPECT_EQ(root_scroll_layer->ScrollDelta(), gfx::Vector2d());
+ root_scroll_layer->ScrollBy(impl_scroll_);
+ impl->SetNeedsCommit();
+ EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), impl_scroll_);
+ EXPECT_VECTOR_EQ(
+ root_scroll_layer->scroll_offset(),
+ initial_scroll_ + impl_scroll_ + impl_scroll_ + second_main_scroll_);
+ } else if (impl->active_tree()->source_frame_number() == 1 &&
+ impl->SourceAnimationFrameNumber() == 4) {
+ // Final draw after the second aborted commit.
+ EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(),
+ initial_scroll_ + impl_scroll_ + impl_scroll_ +
+ impl_scroll_ + second_main_scroll_);
+ EndTest();
+ }
+ }
+
+ virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
+ float scale) OVERRIDE {
+ num_impl_scrolls_++;
+ }
+
+ virtual void AfterTest() OVERRIDE {
+ EXPECT_EQ(3, num_impl_scrolls_);
+ // Verify that the embedder sees aborted commits as real commits.
+ EXPECT_EQ(4, num_will_begin_frames_);
+ EXPECT_EQ(4, num_did_begin_frames_);
+ EXPECT_EQ(4, num_will_commits_);
+ EXPECT_EQ(4, num_did_commits_);
+ // ...but the compositor thread only sees two real ones.
+ EXPECT_EQ(2, num_impl_commits_);
+ }
+
+ private:
+ gfx::Vector2d initial_scroll_;
+ gfx::Vector2d impl_scroll_;
+ gfx::Vector2d second_main_scroll_;
+ float impl_scale_;
+ int num_will_begin_frames_;
+ int num_did_begin_frames_;
+ int num_will_commits_;
+ int num_did_commits_;
+ int num_impl_commits_;
+ int num_impl_scrolls_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostScrollTestScrollAbortedCommit);
+
class LayerTreeHostScrollTestFractionalScroll : public LayerTreeHostScrollTest {
public:
LayerTreeHostScrollTestFractionalScroll() : scroll_amount_(1.75, 0) {}
@@ -208,12 +380,6 @@ class LayerTreeHostScrollTestFractionalScroll : public LayerTreeHostScrollTest {
root->ScrollBy(scroll_amount_);
}
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta, float scale)
- OVERRIDE {
- gfx::Vector2d offset = layer_tree_host()->root_layer()->scroll_offset();
- layer_tree_host()->root_layer()->SetScrollOffset(offset + scroll_delta);
- }
-
virtual void AfterTest() OVERRIDE {}
private:
@@ -285,14 +451,20 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest {
virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+ virtual void WillCommit() OVERRIDE {
+ // Keep the test committing (otherwise the early out for no update
+ // will stall the test).
+ if (layer_tree_host()->source_frame_number() < 2) {
+ layer_tree_host()->SetNeedsCommit();
+ }
+ }
+
void DidScroll() {
final_scroll_offset_ = expected_scroll_layer_->scroll_offset();
}
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta, float scale)
- OVERRIDE {
- gfx::Vector2d offset = root_scroll_layer_->scroll_offset();
- root_scroll_layer_->SetScrollOffset(offset + scroll_delta);
+ virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
+ float scale) OVERRIDE {
num_scrolls_++;
}
@@ -642,10 +814,8 @@ class ImplSidePaintingScrollTestSimple : public ImplSidePaintingScrollTest {
}
}
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta, float scale)
- OVERRIDE {
- gfx::Vector2d offset = layer_tree_host()->root_layer()->scroll_offset();
- layer_tree_host()->root_layer()->SetScrollOffset(offset + scroll_delta);
+ virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
+ float scale) OVERRIDE {
num_scrolls_++;
}
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 860f067..c160d97 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -231,6 +231,24 @@ void LayerTreeImpl::UpdateMaxScrollOffset() {
root_scroll_layer_->SetMaxScrollOffset(gfx::ToFlooredVector2d(max_scroll));
}
+static void ApplySentScrollDeltasOn(LayerImpl* layer) {
+ layer->ApplySentScrollDeltas();
+}
+
+void LayerTreeImpl::ApplySentScrollAndScaleDeltas() {
+ DCHECK(IsActiveTree());
+
+ page_scale_factor_ *= sent_page_scale_delta_;
+ page_scale_delta_ /= sent_page_scale_delta_;
+ sent_page_scale_delta_ = 1.f;
+
+ if (!root_layer())
+ return;
+
+ LayerTreeHostCommon::CallFunctionForSubtree(
+ root_layer(), base::Bind(&ApplySentScrollDeltasOn));
+}
+
void LayerTreeImpl::UpdateSolidColorScrollbars() {
DCHECK(settings().solid_color_scrollbars);
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index aafaf2a..27aa6fa 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -109,6 +109,7 @@ class CC_EXPORT LayerTreeImpl {
void FindRootScrollLayer();
void UpdateMaxScrollOffset();
+ void ApplySentScrollAndScaleDeltas();
SkColor background_color() const { return background_color_; }
void set_background_color(SkColor color) { background_color_ = color; }
diff --git a/cc/trees/proxy.h b/cc/trees/proxy.h
index e3b5f82..f4a1ef9 100644
--- a/cc/trees/proxy.h
+++ b/cc/trees/proxy.h
@@ -66,6 +66,7 @@ class CC_EXPORT Proxy {
virtual const RendererCapabilities& GetRendererCapabilities() const = 0;
virtual void SetNeedsAnimate() = 0;
+ virtual void SetNeedsUpdateLayers() = 0;
virtual void SetNeedsCommit() = 0;
virtual void SetNeedsRedraw(gfx::Rect damage_rect) = 0;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 426b44f..2c4d3a8 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -171,6 +171,11 @@ void SingleThreadProxy::SetNeedsAnimate() {
NOTREACHED();
}
+void SingleThreadProxy::SetNeedsUpdateLayers() {
+ DCHECK(Proxy::IsMainThread());
+ layer_tree_host_->ScheduleComposite();
+}
+
void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) {
DCHECK(Proxy::IsMainThread());
// Commit immediately.
@@ -203,11 +208,12 @@ void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) {
layer_tree_host_impl_->CommitComplete();
#ifndef NDEBUG
- // In the single-threaded case, the scroll deltas should never be
+ // In the single-threaded case, the scale and scroll deltas should never be
// touched on the impl layer tree.
scoped_ptr<ScrollAndScaleSet> scroll_info =
layer_tree_host_impl_->ProcessScrollDeltas();
DCHECK(!scroll_info->scrolls.size());
+ DCHECK_EQ(1.f, scroll_info->page_scale_delta);
#endif
base::TimeDelta duration = stats_instrumentation->EndRecording(start_time);
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index b344cc3..9f7eed4 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -32,6 +32,7 @@ class SingleThreadProxy : public Proxy, LayerTreeHostImplClient {
virtual void CreateAndInitializeOutputSurface() OVERRIDE;
virtual const RendererCapabilities& GetRendererCapabilities() const OVERRIDE;
virtual void SetNeedsAnimate() OVERRIDE;
+ virtual void SetNeedsUpdateLayers() OVERRIDE;
virtual void SetNeedsCommit() OVERRIDE;
virtual void SetNeedsRedraw(gfx::Rect damage_rect) OVERRIDE;
virtual void SetDeferCommits(bool defer_commits) OVERRIDE;
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index 2bf8247..3d73b21 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -90,6 +90,7 @@ ThreadProxy::ThreadProxy(
using_synchronous_renderer_compositor_(
layer_tree_host->settings().using_synchronous_renderer_compositor),
inside_draw_(false),
+ can_cancel_commit_(true),
defer_commits_(false),
renew_tree_priority_on_impl_thread_pending_(false),
draw_duration_history_(kDurationHistorySize),
@@ -128,10 +129,15 @@ bool ThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) {
&begin_frame_sent_to_main_thread_completion));
begin_frame_sent_to_main_thread_completion.Wait();
}
+
in_composite_and_readback_ = true;
BeginFrameOnMainThread(scoped_ptr<BeginFrameAndCommitState>());
in_composite_and_readback_ = false;
+ // Composite and readback requires a second commit to undo any changes
+ // that it made.
+ can_cancel_commit_ = false;
+
// Perform a synchronous readback.
ReadbackRequest request;
request.rect = rect;
@@ -301,6 +307,17 @@ void ThreadProxy::OnOutputSurfaceInitializeAttempted(
}
}
+void ThreadProxy::SendCommitRequestToImplThreadIfNeeded() {
+ DCHECK(IsMainThread());
+ if (commit_request_sent_to_impl_thread_)
+ return;
+ commit_request_sent_to_impl_thread_ = true;
+ Proxy::ImplThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadProxy::SetNeedsCommitOnImplThread,
+ impl_thread_weak_ptr_));
+}
+
const RendererCapabilities& ThreadProxy::GetRendererCapabilities() const {
DCHECK(IsMainThread());
DCHECK(!layer_tree_host_->output_surface_lost());
@@ -314,30 +331,26 @@ void ThreadProxy::SetNeedsAnimate() {
TRACE_EVENT0("cc", "ThreadProxy::SetNeedsAnimate");
animate_requested_ = true;
+ can_cancel_commit_ = false;
+ SendCommitRequestToImplThreadIfNeeded();
+}
- if (commit_request_sent_to_impl_thread_)
- return;
- commit_request_sent_to_impl_thread_ = true;
- Proxy::ImplThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&ThreadProxy::SetNeedsCommitOnImplThread,
- impl_thread_weak_ptr_));
+void ThreadProxy::SetNeedsUpdateLayers() {
+ DCHECK(IsMainThread());
+ SendCommitRequestToImplThreadIfNeeded();
}
void ThreadProxy::SetNeedsCommit() {
DCHECK(IsMainThread());
+ // Unconditionally set here to handle SetNeedsCommit calls during a commit.
+ can_cancel_commit_ = false;
+
if (commit_requested_)
return;
TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommit");
commit_requested_ = true;
- if (commit_request_sent_to_impl_thread_)
- return;
- commit_request_sent_to_impl_thread_ = true;
- Proxy::ImplThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&ThreadProxy::SetNeedsCommitOnImplThread,
- impl_thread_weak_ptr_));
+ SendCommitRequestToImplThreadIfNeeded();
}
void ThreadProxy::DidLoseOutputSurfaceOnImplThread() {
@@ -680,21 +693,23 @@ void ThreadProxy::BeginFrameOnMainThread(
// callbacks will trigger another frame.
animate_requested_ = false;
- if (begin_frame_state)
- layer_tree_host_->ApplyScrollAndScale(*begin_frame_state->scroll_info);
-
if (!in_composite_and_readback_ && !layer_tree_host_->visible()) {
commit_requested_ = false;
commit_request_sent_to_impl_thread_ = false;
TRACE_EVENT0("cc", "EarlyOut_NotVisible");
+ bool did_handle = false;
Proxy::ImplThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::BeginFrameAbortedByMainThreadOnImplThread,
- impl_thread_weak_ptr_));
+ impl_thread_weak_ptr_,
+ did_handle));
return;
}
+ if (begin_frame_state)
+ layer_tree_host_->ApplyScrollAndScale(*begin_frame_state->scroll_info);
+
layer_tree_host_->WillBeginFrame();
if (begin_frame_state) {
@@ -718,24 +733,44 @@ void ThreadProxy::BeginFrameOnMainThread(
// UpdateLayers.
commit_requested_ = false;
commit_request_sent_to_impl_thread_ = false;
+ bool can_cancel_this_commit =
+ can_cancel_commit_ && !in_composite_and_readback_;
+ can_cancel_commit_ = true;
scoped_ptr<ResourceUpdateQueue> queue =
make_scoped_ptr(new ResourceUpdateQueue);
- layer_tree_host_->UpdateLayers(
+ bool updated = layer_tree_host_->UpdateLayers(
queue.get(),
- begin_frame_state ?
- begin_frame_state->memory_allocation_limit_bytes : 0u);
+ begin_frame_state ? begin_frame_state->memory_allocation_limit_bytes
+ : 0u);
// Once single buffered layers are committed, they cannot be modified until
// they are drawn by the impl thread.
textures_acquired_ = false;
layer_tree_host_->WillCommit();
- // Before applying scrolls and calling animate, we set animate_requested_ to
- // false. If it is true now, it means SetNeedAnimate was called again, but
- // during a state when commit_request_sent_to_impl_thread_ = true. We need to
- // force that call to happen again now so that the commit request is sent to
- // the impl thread.
+
+ if (!updated && can_cancel_this_commit) {
+ TRACE_EVENT0("cc", "EarlyOut_NoUpdates");
+ bool did_handle = true;
+ Proxy::ImplThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadProxy::BeginFrameAbortedByMainThreadOnImplThread,
+ impl_thread_weak_ptr_,
+ did_handle));
+
+ // Although the commit is internally aborted, this is because it has been
+ // detected to be a no-op. From the perspective of an embedder, this commit
+ // went through, and input should no longer be throttled, etc.
+ layer_tree_host_->CommitComplete();
+ layer_tree_host_->DidBeginFrame();
+ return;
+ }
+
+ // Before calling animate, we set animate_requested_ to false. If it is true
+ // now, it means SetNeedAnimate was called again, but during a state when
+ // commit_request_sent_to_impl_thread_ = true. We need to force that call to
+ // happen again now so that the commit request is sent to the impl thread.
if (animate_requested_) {
// Forces SetNeedsAnimate to consider posting a commit task.
animate_requested_ = false;
@@ -831,13 +866,19 @@ void ThreadProxy::StartCommitOnImplThread(
scheduler_on_impl_thread_->AnticipatedDrawTime());
}
-void ThreadProxy::BeginFrameAbortedByMainThreadOnImplThread() {
+void ThreadProxy::BeginFrameAbortedByMainThreadOnImplThread(bool did_handle) {
TRACE_EVENT0("cc", "ThreadProxy::BeginFrameAbortedByMainThreadOnImplThread");
DCHECK(IsImplThread());
DCHECK(scheduler_on_impl_thread_);
DCHECK(scheduler_on_impl_thread_->CommitPending());
+ DCHECK(!layer_tree_host_impl_->pending_tree());
- scheduler_on_impl_thread_->BeginFrameAbortedByMainThread();
+ // If the begin frame data was handled, then scroll and scale set was applied
+ // by the main thread, so the active tree needs to be updated as if these sent
+ // values were applied and committed.
+ if (did_handle)
+ layer_tree_host_impl_->active_tree()->ApplySentScrollAndScaleDeltas();
+ scheduler_on_impl_thread_->BeginFrameAbortedByMainThread(did_handle);
}
void ThreadProxy::ScheduledActionCommit() {
@@ -905,7 +946,8 @@ void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
ScheduledActionDrawAndSwapResult
ThreadProxy::ScheduledActionDrawAndSwapInternal(bool forced_draw) {
- TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwap");
+ TRACE_EVENT1(
+ "cc", "ThreadProxy::ScheduledActionDrawAndSwap", "forced", forced_draw);
ScheduledActionDrawAndSwapResult result;
result.did_draw = false;
@@ -1066,6 +1108,7 @@ void ThreadProxy::AcquireLayerTextures() {
completion.Wait();
textures_acquired_ = true;
+ can_cancel_commit_ = false;
}
void ThreadProxy::AcquireLayerTexturesForMainThreadOnImplThread(
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index eb2ef7e..c9d5b47 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -49,6 +49,7 @@ class ThreadProxy : public Proxy,
virtual void CreateAndInitializeOutputSurface() OVERRIDE;
virtual const RendererCapabilities& GetRendererCapabilities() const OVERRIDE;
virtual void SetNeedsAnimate() OVERRIDE;
+ virtual void SetNeedsUpdateLayers() OVERRIDE;
virtual void SetNeedsCommit() OVERRIDE;
virtual void SetNeedsRedraw(gfx::Rect damage_rect) OVERRIDE;
virtual void SetDeferCommits(bool defer_commits) OVERRIDE;
@@ -135,6 +136,7 @@ class ThreadProxy : public Proxy,
void OnOutputSurfaceInitializeAttempted(
bool success,
const RendererCapabilities& capabilities);
+ void SendCommitRequestToImplThreadIfNeeded();
// Called on impl thread.
struct ReadbackRequest;
@@ -146,7 +148,7 @@ class ThreadProxy : public Proxy,
CompletionEvent* completion,
ResourceUpdateQueue* queue,
scoped_refptr<cc::ContextProvider> offscreen_context_provider);
- void BeginFrameAbortedByMainThreadOnImplThread();
+ void BeginFrameAbortedByMainThreadOnImplThread(bool did_handle);
void RequestReadbackOnImplThread(ReadbackRequest* request);
void FinishAllRenderingOnImplThread(CompletionEvent* completion);
void InitializeImplOnImplThread(CompletionEvent* completion);
@@ -241,6 +243,8 @@ class ThreadProxy : public Proxy,
bool inside_draw_;
+ bool can_cancel_commit_;
+
bool defer_commits_;
scoped_ptr<BeginFrameAndCommitState> pending_deferred_commit_;