cc: Limit ManageTiles calls to once per-frame on average

This makes sure LTHI notifies the Scheduler of all ManageTiles calls
and then avoids a scheduled ManageTiles if we are already averaging
one or more ManageTiles per BeginImplFrame.

Limiting the scheduled ManageTiles to occur only if a ManageTiles
hasn't happened in the current frame can still result in two
ManageTiles per frame since we might schedule a ManageTiles at the
begining of a frame and then call explicitly when the commit finishes
if the main thread is in a high latency mode.

BUG=334749

Review URL: https://codereview.chromium.org/130483010

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@245388 0039d316-1c4b-4281-b951-d872f2087c98
parent 440e3573
...@@ -26,7 +26,7 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) ...@@ -26,7 +26,7 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
last_frame_number_swap_performed_(-1), last_frame_number_swap_performed_(-1),
last_frame_number_begin_main_frame_sent_(-1), last_frame_number_begin_main_frame_sent_(-1),
last_frame_number_update_visible_tiles_was_called_(-1), last_frame_number_update_visible_tiles_was_called_(-1),
last_frame_number_manage_tiles_called_(-1), manage_tiles_funnel_(0),
consecutive_failed_draws_(0), consecutive_failed_draws_(0),
needs_redraw_(false), needs_redraw_(false),
needs_manage_tiles_(false), needs_manage_tiles_(false),
...@@ -239,6 +239,7 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const { ...@@ -239,6 +239,7 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
"last_frame_number_update_visible_tiles_was_called", "last_frame_number_update_visible_tiles_was_called",
last_frame_number_update_visible_tiles_was_called_); last_frame_number_update_visible_tiles_was_called_);
minor_state->SetInteger("manage_tiles_funnel", manage_tiles_funnel_);
minor_state->SetInteger("consecutive_failed_draws", minor_state->SetInteger("consecutive_failed_draws",
consecutive_failed_draws_); consecutive_failed_draws_);
minor_state->SetBoolean("needs_redraw", needs_redraw_); minor_state->SetBoolean("needs_redraw", needs_redraw_);
...@@ -270,6 +271,14 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const { ...@@ -270,6 +271,14 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
return state.PassAs<base::Value>(); return state.PassAs<base::Value>();
} }
void SchedulerStateMachine::AdvanceCurrentFrameNumber() {
current_frame_number_++;
// "Drain" the ManageTiles funnel.
if (manage_tiles_funnel_ > 0)
manage_tiles_funnel_--;
}
bool SchedulerStateMachine::HasSentBeginMainFrameThisFrame() const { bool SchedulerStateMachine::HasSentBeginMainFrameThisFrame() const {
return current_frame_number_ == return current_frame_number_ ==
last_frame_number_begin_main_frame_sent_; last_frame_number_begin_main_frame_sent_;
...@@ -507,9 +516,9 @@ bool SchedulerStateMachine::IsCommitStateWaiting() const { ...@@ -507,9 +516,9 @@ bool SchedulerStateMachine::IsCommitStateWaiting() const {
bool SchedulerStateMachine::ShouldManageTiles() const { bool SchedulerStateMachine::ShouldManageTiles() const {
// ManageTiles only really needs to be called immediately after commit // ManageTiles only really needs to be called immediately after commit
// and then periodically after that. Limiting to once per frame prevents // and then periodically after that. Use a funnel to make sure we average
// post-commit and post-draw ManageTiles on the same frame. // one ManageTiles per BeginImplFrame in the long run.
if (last_frame_number_manage_tiles_called_ == current_frame_number_) if (manage_tiles_funnel_ > 0)
return false; return false;
// Limiting to once per-frame is not enough, since we only want to // Limiting to once per-frame is not enough, since we only want to
...@@ -885,7 +894,7 @@ bool SchedulerStateMachine::ProactiveBeginImplFrameWanted() const { ...@@ -885,7 +894,7 @@ bool SchedulerStateMachine::ProactiveBeginImplFrameWanted() const {
} }
void SchedulerStateMachine::OnBeginImplFrame(const BeginFrameArgs& args) { void SchedulerStateMachine::OnBeginImplFrame(const BeginFrameArgs& args) {
current_frame_number_++; AdvanceCurrentFrameNumber();
last_begin_impl_frame_args_ = args; last_begin_impl_frame_args_ = args;
DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE) << *AsValue(); DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE) << *AsValue();
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING; begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING;
...@@ -981,7 +990,7 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const { ...@@ -981,7 +990,7 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
} }
void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() { void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() {
current_frame_number_++; AdvanceCurrentFrameNumber();
inside_poll_for_anticipated_draw_triggers_ = true; inside_poll_for_anticipated_draw_triggers_ = true;
} }
...@@ -1081,7 +1090,8 @@ void SchedulerStateMachine::BeginMainFrameAborted(bool did_handle) { ...@@ -1081,7 +1090,8 @@ void SchedulerStateMachine::BeginMainFrameAborted(bool did_handle) {
void SchedulerStateMachine::DidManageTiles() { void SchedulerStateMachine::DidManageTiles() {
needs_manage_tiles_ = false; needs_manage_tiles_ = false;
last_frame_number_manage_tiles_called_ = current_frame_number_; // "Fill" the ManageTiles funnel.
manage_tiles_funnel_++;
} }
void SchedulerStateMachine::DidLoseOutputSurface() { void SchedulerStateMachine::DidLoseOutputSurface() {
......
...@@ -254,6 +254,7 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -254,6 +254,7 @@ class CC_EXPORT SchedulerStateMachine {
bool ShouldCommit() const; bool ShouldCommit() const;
bool ShouldManageTiles() const; bool ShouldManageTiles() const;
void AdvanceCurrentFrameNumber();
bool HasSentBeginMainFrameThisFrame() const; bool HasSentBeginMainFrameThisFrame() const;
bool HasScheduledManageTilesThisFrame() const; bool HasScheduledManageTilesThisFrame() const;
bool HasUpdatedVisibleTilesThisFrame() const; bool HasUpdatedVisibleTilesThisFrame() const;
...@@ -280,8 +281,12 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -280,8 +281,12 @@ class CC_EXPORT SchedulerStateMachine {
int last_frame_number_swap_performed_; int last_frame_number_swap_performed_;
int last_frame_number_begin_main_frame_sent_; int last_frame_number_begin_main_frame_sent_;
int last_frame_number_update_visible_tiles_was_called_; int last_frame_number_update_visible_tiles_was_called_;
int last_frame_number_manage_tiles_called_;
// manage_tiles_funnel_ is "filled" each time ManageTiles is called
// and "drained" on each BeginImplFrame. If the funnel gets too full,
// we start throttling ACTION_MANAGE_TILES such that we average one
// ManageTile per BeginImplFrame.
int manage_tiles_funnel_;
int consecutive_failed_draws_; int consecutive_failed_draws_;
bool needs_redraw_; bool needs_redraw_;
bool needs_manage_tiles_; bool needs_manage_tiles_;
......
...@@ -1094,7 +1094,7 @@ TEST(SchedulerTest, ManageTiles) { ...@@ -1094,7 +1094,7 @@ TEST(SchedulerTest, ManageTiles) {
} }
// Test that ManageTiles only happens once per frame. If an external caller // Test that ManageTiles only happens once per frame. If an external caller
// initiates it, then the state machine should not on that frame. // initiates it, then the state machine should not ManageTiles on that frame.
TEST(SchedulerTest, ManageTilesOncePerFrame) { TEST(SchedulerTest, ManageTilesOncePerFrame) {
FakeSchedulerClient client; FakeSchedulerClient client;
SchedulerSettings default_scheduler_settings; SchedulerSettings default_scheduler_settings;
...@@ -1112,7 +1112,7 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) { ...@@ -1112,7 +1112,7 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) {
EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client); EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
EXPECT_TRUE(scheduler->ManageTilesPending()); EXPECT_TRUE(scheduler->ManageTilesPending());
scheduler->DidManageTiles(); scheduler->DidManageTiles(); // An explicit ManageTiles.
EXPECT_FALSE(scheduler->ManageTilesPending()); EXPECT_FALSE(scheduler->ManageTilesPending());
client.Reset(); client.Reset();
...@@ -1139,6 +1139,63 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) { ...@@ -1139,6 +1139,63 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) {
client.ActionIndex("ScheduledActionManageTiles")); client.ActionIndex("ScheduledActionManageTiles"));
EXPECT_FALSE(scheduler->RedrawPending()); EXPECT_FALSE(scheduler->RedrawPending());
EXPECT_FALSE(scheduler->ManageTilesPending()); EXPECT_FALSE(scheduler->ManageTilesPending());
scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
// If we get another DidManageTiles within the same frame, we should
// not ManageTiles on the next frame.
scheduler->DidManageTiles(); // An explicit ManageTiles.
scheduler->SetNeedsManageTiles();
scheduler->SetNeedsRedraw();
client.Reset();
scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
EXPECT_TRUE(scheduler->ManageTilesPending());
client.Reset();
scheduler->OnBeginImplFrameDeadline();
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
EXPECT_FALSE(scheduler->RedrawPending());
// If we get another DidManageTiles, we should not ManageTiles on the next
// frame. This verifies we don't alternate calling ManageTiles once and twice.
EXPECT_TRUE(scheduler->ManageTilesPending());
scheduler->DidManageTiles(); // An explicit ManageTiles.
EXPECT_FALSE(scheduler->ManageTilesPending());
scheduler->SetNeedsManageTiles();
scheduler->SetNeedsRedraw();
client.Reset();
scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
EXPECT_TRUE(scheduler->ManageTilesPending());
client.Reset();
scheduler->OnBeginImplFrameDeadline();
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
EXPECT_FALSE(scheduler->RedrawPending());
// Next frame without DidManageTiles should ManageTiles with draw.
scheduler->SetNeedsManageTiles();
scheduler->SetNeedsRedraw();
client.Reset();
scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
client.Reset();
scheduler->OnBeginImplFrameDeadline();
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
client.ActionIndex("ScheduledActionManageTiles"));
EXPECT_FALSE(scheduler->RedrawPending());
EXPECT_FALSE(scheduler->ManageTilesPending());
scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
} }
class SchedulerClientWithFixedEstimates : public FakeSchedulerClient { class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
......
...@@ -424,6 +424,8 @@ void LayerTreeHostImpl::ManageTiles() { ...@@ -424,6 +424,8 @@ void LayerTreeHostImpl::ManageTiles() {
SendManagedMemoryStats(memory_required_bytes, SendManagedMemoryStats(memory_required_bytes,
memory_nice_to_have_bytes, memory_nice_to_have_bytes,
memory_used_bytes); memory_used_bytes);
client_->DidManageTiles();
} }
void LayerTreeHostImpl::StartPageScaleAnimation(gfx::Vector2d target_offset, void LayerTreeHostImpl::StartPageScaleAnimation(gfx::Vector2d target_offset,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment