#include <string>
#include <vector>
+#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
-#include "base/test/test_simple_task_runner.h"
#include "base/time/time.h"
+#include "cc/test/begin_frame_args_test.h"
+#include "cc/test/ordered_simple_task_runner.h"
#include "cc/test/scheduler_test_common.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
- EXPECT_EQ(expected_num_actions, client.num_actions_()); \
- ASSERT_LT(action_index, client.num_actions_()); \
do { \
- EXPECT_STREQ(action, client.Action(action_index)); \
+ EXPECT_EQ(expected_num_actions, client.num_actions_()); \
+ if (action_index >= 0) { \
+ ASSERT_LT(action_index, client.num_actions_()) << scheduler; \
+ EXPECT_STREQ(action, client.Action(action_index)); \
+ } \
for (int i = expected_num_actions; i < client.num_actions_(); ++i) \
- ADD_FAILURE() << "Unexpected action: " << client.Action(i) << \
- " with state:\n" << client.StateForAction(action_index); \
+ ADD_FAILURE() << "Unexpected action: " << client.Action(i) \
+ << " with state:\n" << client.StateForAction(i); \
} while (false)
+#define EXPECT_NO_ACTION(client) EXPECT_ACTION("", client, -1, 0)
+
#define EXPECT_SINGLE_ACTION(action, client) \
EXPECT_ACTION(action, client, 0, 1)
class FakeSchedulerClient : public SchedulerClient {
public:
- FakeSchedulerClient() : needs_begin_frame_(false), automatic_swap_ack_(true) {
+ FakeSchedulerClient()
+ : needs_begin_frame_(false),
+ automatic_swap_ack_(true),
+ swap_contains_incomplete_tile_(false),
+ redraw_will_happen_if_update_visible_tiles_happens_(false),
+ now_src_(TestNowSource::Create()) {
Reset();
}
log_anticipated_draw_time_change_ = false;
}
- Scheduler* CreateScheduler(const SchedulerSettings& settings) {
- task_runner_ = new base::TestSimpleTaskRunner;
- scheduler_ = Scheduler::Create(this, settings, 0, task_runner_);
+ TestScheduler* CreateScheduler(const SchedulerSettings& settings) {
+ scheduler_ = TestScheduler::Create(now_src_, this, settings, 0);
+ // Fail if we need to run 100 tasks in a row.
+ task_runner().SetRunTaskLimit(100);
return scheduler_.get();
}
int num_draws() const { return num_draws_; }
int num_actions_() const { return static_cast<int>(actions_.size()); }
const char* Action(int i) const { return actions_[i]; }
- base::Value& StateForAction(int i) const { return *states_[i]; }
+ std::string StateForAction(int i) const { return states_[i]->ToString(); }
base::TimeTicks posted_begin_impl_frame_deadline() const {
return posted_begin_impl_frame_deadline_;
}
- base::TestSimpleTaskRunner& task_runner() { return *task_runner_; }
+ void AdvanceFrame() {
+ bool external_begin_frame =
+ scheduler_->settings().begin_frame_scheduling_enabled &&
+ scheduler_->settings().throttle_frame_production;
+
+ if (external_begin_frame) {
+ scheduler_->BeginFrame(CreateBeginFrameArgsForTesting(now_src_));
+ }
+
+ EXPECT_TRUE(task_runner().RunTasksWhile(ImplFrameDeadlinePending(false)));
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ }
+
+ OrderedSimpleTaskRunner& task_runner() { return scheduler_->task_runner(); }
+ TestNowSource* now_src() { return now_src_.get(); }
int ActionIndex(const char* action) const {
for (size_t i = 0; i < actions_.size(); i++)
return -1;
}
+ void SetSwapContainsIncompleteTile(bool contain) {
+ swap_contains_incomplete_tile_ = contain;
+ }
+
bool HasAction(const char* action) const {
return ActionIndex(action) >= 0;
}
void SetAutomaticSwapAck(bool automatic_swap_ack) {
automatic_swap_ack_ = automatic_swap_ack;
}
-
+ void SetRedrawWillHappenIfUpdateVisibleTilesHappens(bool redraw) {
+ redraw_will_happen_if_update_visible_tiles_happens_ = redraw;
+ }
// SchedulerClient implementation.
virtual void SetNeedsBeginFrame(bool enable) OVERRIDE {
actions_.push_back("SetNeedsBeginFrame");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue());
needs_begin_frame_ = enable;
}
virtual void WillBeginImplFrame(const BeginFrameArgs& args) OVERRIDE {
actions_.push_back("WillBeginImplFrame");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue());
}
virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {
actions_.push_back("ScheduledActionSendBeginMainFrame");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue());
}
virtual void ScheduledActionAnimate() OVERRIDE {
actions_.push_back("ScheduledActionAnimate");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue());
}
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
- OVERRIDE {
+ virtual DrawResult ScheduledActionDrawAndSwapIfPossible() OVERRIDE {
actions_.push_back("ScheduledActionDrawAndSwapIfPossible");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue());
num_draws_++;
- bool did_readback = false;
- DrawSwapReadbackResult::DrawResult result =
- draw_will_happen_
- ? DrawSwapReadbackResult::DRAW_SUCCESS
- : DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
+ DrawResult result =
+ draw_will_happen_ ? DRAW_SUCCESS : DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
bool swap_will_happen =
draw_will_happen_ && swap_will_happen_if_draw_happens_;
if (swap_will_happen) {
scheduler_->DidSwapBuffers();
+ if (swap_contains_incomplete_tile_) {
+ scheduler_->SetSwapUsedIncompleteTile(true);
+ swap_contains_incomplete_tile_ = false;
+ } else {
+ scheduler_->SetSwapUsedIncompleteTile(false);
+ }
+
if (automatic_swap_ack_)
scheduler_->DidSwapBuffersComplete();
}
- return DrawSwapReadbackResult(
- result,
- draw_will_happen_ && swap_will_happen_if_draw_happens_,
- did_readback);
+ return result;
}
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
+ virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE {
actions_.push_back("ScheduledActionDrawAndSwapForced");
- states_.push_back(scheduler_->StateAsValue().release());
- bool did_request_swap = swap_will_happen_if_draw_happens_;
- bool did_readback = false;
- return DrawSwapReadbackResult(
- DrawSwapReadbackResult::DRAW_SUCCESS, did_request_swap, did_readback);
- }
- virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() OVERRIDE {
- actions_.push_back("ScheduledActionDrawAndReadback");
- states_.push_back(scheduler_->StateAsValue().release());
- bool did_request_swap = false;
- bool did_readback = true;
- return DrawSwapReadbackResult(
- DrawSwapReadbackResult::DRAW_SUCCESS, did_request_swap, did_readback);
+ states_.push_back(scheduler_->AsValue());
+ return DRAW_SUCCESS;
}
virtual void ScheduledActionCommit() OVERRIDE {
actions_.push_back("ScheduledActionCommit");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue());
}
virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE {
actions_.push_back("ScheduledActionUpdateVisibleTiles");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue());
+ if (redraw_will_happen_if_update_visible_tiles_happens_)
+ scheduler_->SetNeedsRedraw();
}
- virtual void ScheduledActionActivatePendingTree() OVERRIDE {
- actions_.push_back("ScheduledActionActivatePendingTree");
- states_.push_back(scheduler_->StateAsValue().release());
+ virtual void ScheduledActionActivateSyncTree() OVERRIDE {
+ actions_.push_back("ScheduledActionActivateSyncTree");
+ states_.push_back(scheduler_->AsValue());
}
virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {
actions_.push_back("ScheduledActionBeginOutputSurfaceCreation");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue());
}
virtual void ScheduledActionManageTiles() OVERRIDE {
actions_.push_back("ScheduledActionManageTiles");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue());
}
virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {
if (log_anticipated_draw_time_change_)
virtual void DidBeginImplFrameDeadline() OVERRIDE {}
+ base::Callback<bool(void)> ImplFrameDeadlinePending(bool state) {
+ return base::Bind(&FakeSchedulerClient::ImplFrameDeadlinePendingCallback,
+ base::Unretained(this),
+ state);
+ }
+
protected:
+ bool ImplFrameDeadlinePendingCallback(bool state) {
+ return scheduler_->BeginImplFrameDeadlinePending() == state;
+ }
+
bool needs_begin_frame_;
bool draw_will_happen_;
bool swap_will_happen_if_draw_happens_;
bool automatic_swap_ack_;
int num_draws_;
bool log_anticipated_draw_time_change_;
+ bool swap_contains_incomplete_tile_;
+ bool redraw_will_happen_if_update_visible_tiles_happens_;
base::TimeTicks posted_begin_impl_frame_deadline_;
std::vector<const char*> actions_;
- ScopedVector<base::Value> states_;
- scoped_ptr<Scheduler> scheduler_;
- scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ std::vector<scoped_refptr<base::debug::ConvertableToTraceFormat> > states_;
+ scoped_ptr<TestScheduler> scheduler_;
+ scoped_refptr<TestNowSource> now_src_;
};
void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler,
FakeSchedulerClient* client) {
- bool client_initiates_begin_frame =
- scheduler->settings().begin_frame_scheduling_enabled &&
- scheduler->settings().throttle_frame_production;
+ TRACE_EVENT0("cc",
+ "SchedulerUnitTest::InitializeOutputSurfaceAndFirstCommit");
scheduler->DidCreateAndInitializeOutputSurface();
scheduler->SetNeedsCommit();
scheduler->NotifyBeginMainFrameStarted();
scheduler->NotifyReadyToCommit();
+ if (scheduler->settings().impl_side_painting)
+ scheduler->NotifyReadyToActivate();
+
// Go through the motions to draw the commit.
- if (client_initiates_begin_frame)
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
- else
- client->task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ client->AdvanceFrame();
// Run the posted deadline task.
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client->task_runner().RunPendingTasks();
+ client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true));
EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
// We need another BeginImplFrame so Scheduler calls
// SetNeedsBeginFrame(false).
- if (client_initiates_begin_frame)
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
- else
- client->task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ client->AdvanceFrame();
// Run the posted deadline task.
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client->task_runner().RunPendingTasks();
+ client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true));
EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
}
TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
FakeSchedulerClient client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
client.Reset();
scheduler->DidCreateAndInitializeOutputSurface();
- EXPECT_EQ(0, client.num_actions_());
+ EXPECT_NO_ACTION(client);
}
TEST(SchedulerTest, RequestCommit) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
client.Reset();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
// If we don't swap on the deadline, we wait for the next BeginFrame.
client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(0, client.num_actions_());
+ EXPECT_NO_ACTION(client);
EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
EXPECT_TRUE(client.needs_begin_frame());
client.Reset();
client.Reset();
// BeginImplFrame should prepare the draw.
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
// The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
// to avoid excessive toggles.
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client.Reset();
TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
client.Reset();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client.Reset();
// Since another commit is needed, the next BeginImplFrame should initiate
// the second commit.
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
// On the next BeginImplFrame, verify we go back to a quiescent state and
// no longer request BeginImplFrames.
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_FALSE(client.needs_begin_frame());
client.Reset();
class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
public:
virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
+ virtual DrawResult ScheduledActionDrawAndSwapIfPossible()
OVERRIDE {
// Only SetNeedsRedraw the first time this is called
if (!num_draws_)
return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
}
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
+ virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE {
NOTREACHED();
- bool did_request_swap = true;
- bool did_readback = false;
- return DrawSwapReadbackResult(
- DrawSwapReadbackResult::DRAW_SUCCESS, did_request_swap, did_readback);
+ return DRAW_SUCCESS;
}
virtual void ScheduledActionCommit() OVERRIDE {}
TEST(SchedulerTest, RequestRedrawInsideDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
EXPECT_TRUE(client.needs_begin_frame());
EXPECT_EQ(0, client.num_draws());
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(scheduler->RedrawPending());
EXPECT_TRUE(client.needs_begin_frame());
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
EXPECT_FALSE(scheduler->RedrawPending());
// We stop requesting BeginImplFrames after a BeginImplFrame where we don't
// swap.
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
EXPECT_FALSE(scheduler->RedrawPending());
TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
EXPECT_EQ(0, client.num_draws());
// Fail the draw.
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(client.needs_begin_frame());
// Fail the draw again.
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
EXPECT_TRUE(scheduler->CommitPending());
// Draw successfully.
client.SetDrawWillHappen(true);
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(3, client.num_draws());
EXPECT_TRUE(scheduler->CommitPending());
: set_needs_commit_on_next_draw_(false) {}
virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
+ virtual DrawResult ScheduledActionDrawAndSwapIfPossible()
OVERRIDE {
// Only SetNeedsCommit the first time this is called
if (set_needs_commit_on_next_draw_) {
return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
}
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
+ virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE {
NOTREACHED();
- bool did_request_swap = false;
- bool did_readback = false;
- return DrawSwapReadbackResult(
- DrawSwapReadbackResult::DRAW_SUCCESS, did_request_swap, did_readback);
+ return DRAW_SUCCESS;
}
virtual void ScheduledActionCommit() OVERRIDE {}
TEST(SchedulerTest, RequestCommitInsideDraw) {
SchedulerClientThatSetNeedsCommitInsideDraw client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
EXPECT_TRUE(client.needs_begin_frame());
client.SetNeedsCommitOnNextDraw();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.SetNeedsCommitOnNextDraw();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
scheduler->NotifyBeginMainFrameStarted();
scheduler->NotifyReadyToCommit();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
// We stop requesting BeginImplFrames after a BeginImplFrame where we don't
// swap.
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
EXPECT_FALSE(scheduler->RedrawPending());
TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
EXPECT_EQ(0, client.num_draws());
// Fail the draw.
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(client.needs_begin_frame());
// Fail the draw again.
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
// Draw successfully.
client.SetDrawWillHappen(true);
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(3, client.num_draws());
EXPECT_TRUE(scheduler->CommitPending());
TEST(SchedulerTest, NoSwapWhenDrawFails) {
SchedulerClientThatSetNeedsCommitInsideDraw client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
// Draw successfully, this starts a new frame.
client.SetNeedsCommitOnNextDraw();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
// Fail to draw, this should not start a frame.
client.SetDrawWillHappen(false);
client.SetNeedsCommitOnNextDraw();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
}
-TEST(SchedulerTest, NoSwapWhenSwapFailsDuringForcedCommit) {
- FakeSchedulerClient client;
- SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
-
- // Tell the client that it will fail to swap.
- client.SetDrawWillHappen(true);
- client.SetSwapWillHappenIfDrawHappens(false);
-
- // Get the compositor to do a ScheduledActionDrawAndReadback.
- scheduler->SetCanDraw(true);
- scheduler->SetNeedsRedraw();
- scheduler->SetNeedsForcedCommitForReadback();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
-}
-
-TEST(SchedulerTest, BackToBackReadbackAllowed) {
- // Some clients call readbacks twice in a row before the replacement
- // commit comes in. Make sure it is allowed.
- FakeSchedulerClient client;
- SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
-
- // Get the compositor to do 2 ScheduledActionDrawAndReadbacks before
- // the replacement commit comes in.
- scheduler->SetCanDraw(true);
- scheduler->SetNeedsRedraw();
- scheduler->SetNeedsForcedCommitForReadback();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
-
- client.Reset();
- scheduler->SetNeedsForcedCommitForReadback();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
-
- // The replacement commit comes in after 2 readbacks.
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
-}
-
-
class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient {
public:
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
+ virtual DrawResult ScheduledActionDrawAndSwapIfPossible()
OVERRIDE {
scheduler_->SetNeedsManageTiles();
return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
TEST(SchedulerTest, ManageTiles) {
SchedulerClientNeedsManageTilesInDraw client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
// We have no immediate actions to perform, so the BeginImplFrame should post
// the deadline task.
client.Reset();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
// We have no immediate actions to perform, so the BeginImplFrame should post
// the deadline task.
client.Reset();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
// We need a BeginImplFrame where we don't swap to go idle.
client.Reset();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client.Reset();
// BeginImplFrame. There will be no draw, only ManageTiles.
client.Reset();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client.Reset();
TEST(SchedulerTest, ManageTilesOncePerFrame) {
FakeSchedulerClient client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
scheduler->SetNeedsManageTiles();
scheduler->SetNeedsRedraw();
client.Reset();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
scheduler->SetNeedsManageTiles();
scheduler->SetNeedsRedraw();
client.Reset();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
scheduler->SetNeedsManageTiles();
scheduler->SetNeedsRedraw();
client.Reset();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
scheduler->SetNeedsManageTiles();
scheduler->SetNeedsRedraw();
client.Reset();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
scheduler->SetNeedsManageTiles();
scheduler->SetNeedsRedraw();
client.Reset();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
}
+TEST(SchedulerTest, ShouldUpdateVisibleTiles) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.impl_side_painting = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ client.SetRedrawWillHappenIfUpdateVisibleTilesHappens(true);
+
+ // SetNeedsCommit should begin the frame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+ client.Reset();
+ client.AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+
+ client.Reset();
+ scheduler->NotifyReadyToActivate();
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client);
+
+ client.Reset();
+ client.SetSwapContainsIncompleteTile(true);
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+ EXPECT_FALSE(scheduler->RedrawPending());
+
+ client.Reset();
+ client.AdvanceFrame();
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionUpdateVisibleTiles", client, 0, 3);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 3);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 2, 3);
+
+ client.Reset();
+ client.AdvanceFrame();
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ // No more UpdateVisibleTiles().
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+ EXPECT_FALSE(client.needs_begin_frame());
+}
+
TEST(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
SchedulerClientNeedsManageTilesInDraw client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
client.Reset();
scheduler->SetNeedsRedraw();
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
// The deadline should be zero since there is no work other than drawing
// pending.
void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms,
int64 commit_to_activate_estimate_in_ms,
- bool smoothness_takes_priority,
+ bool impl_latency_takes_priority,
bool should_send_begin_main_frame) {
// Set up client with specified estimates (draw duration is set to 1).
SchedulerClientWithFixedEstimates client(
begin_main_frame_to_commit_estimate_in_ms),
base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
- scheduler->SetSmoothnessTakesPriority(smoothness_takes_priority);
+ scheduler->SetImplLatencyTakesPriority(impl_latency_takes_priority);
InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
// Impl thread hits deadline before commit finishes.
client.Reset();
scheduler->SetNeedsCommit();
EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
client.Reset();
scheduler->SetNeedsCommit();
EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
- scheduler->BeginFrame(BeginFrameArgs::CreateForTesting());
+ client.AdvanceFrame();
EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(scheduler->MainThreadIsInHighLatencyMode(),
MainFrameInHighLatencyMode(1, 10, false, true);
}
-TEST(SchedulerTest, NotSkipMainFrameInPreferSmoothnessMode) {
+TEST(SchedulerTest, NotSkipMainFrameInPreferImplLatencyMode) {
// Set up client so that estimates indicate that we can commit and activate
- // before the deadline (~8ms by default), but also enable smoothness takes
+ // before the deadline (~8ms by default), but also enable impl latency takes
// priority mode.
MainFrameInHighLatencyMode(1, 1, true, true);
}
base::TimeDelta::FromMilliseconds(32));
client.set_log_anticipated_draw_time_change(true);
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanDraw(true);
scheduler->SetCanStart();
scheduler->NotifyReadyToCommit();
scheduler->SetNeedsRedraw();
- BeginFrameArgs frame_args = BeginFrameArgs::CreateForTesting();
+ BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting(client.now_src());
frame_args.interval = base::TimeDelta::FromMilliseconds(1000);
scheduler->BeginFrame(frame_args);
// Does three iterations to make sure that the timer is properly repeating.
for (int i = 0; i < 3; ++i) {
EXPECT_EQ((frame_args.interval * 2).InMicroseconds(),
- client.task_runner().NextPendingTaskDelay().InMicroseconds())
- << *scheduler->StateAsValue();
+ client.task_runner().DelayToNextTaskTime().InMicroseconds())
+ << scheduler->AsValue()->ToString();
client.task_runner().RunPendingTasks();
EXPECT_GT(client.num_actions_(), actions_so_far);
EXPECT_STREQ(client.Action(client.num_actions_() - 1),
scheduler->NotifyBeginMainFrameStarted();
for (int i = 0; i < 3; ++i) {
EXPECT_EQ((frame_args.interval * 2).InMicroseconds(),
- client.task_runner().NextPendingTaskDelay().InMicroseconds())
- << *scheduler->StateAsValue();
+ client.task_runner().DelayToNextTaskTime().InMicroseconds())
+ << scheduler->AsValue()->ToString();
client.task_runner().RunPendingTasks();
EXPECT_GT(client.num_actions_(), actions_so_far);
EXPECT_STREQ(client.Action(client.num_actions_() - 1),
TEST(SchedulerTest, BeginRetroFrame) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
// Create a BeginFrame with a long deadline to avoid race conditions.
// This is the first BeginFrame, which will be handled immediately.
- BeginFrameArgs args = BeginFrameArgs::CreateForTesting();
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
args.deadline += base::TimeDelta::FromHours(1);
scheduler->BeginFrame(args);
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
// If we don't swap on the deadline, we wait for the next BeginImplFrame.
client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(0, client.num_actions_());
+ EXPECT_NO_ACTION(client);
EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
EXPECT_TRUE(client.needs_begin_frame());
client.Reset();
TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
// Create a BeginFrame with a long deadline to avoid race conditions.
// This is the first BeginFrame, which will be handled immediately.
- BeginFrameArgs args = BeginFrameArgs::CreateForTesting();
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
args.deadline += base::TimeDelta::FromHours(1);
scheduler->BeginFrame(args);
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
args.frame_time += base::TimeDelta::FromSeconds(1);
scheduler->BeginFrame(args);
- EXPECT_EQ(0, client.num_actions_());
+ EXPECT_NO_ACTION(client);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client.Reset();
// Queue BeginFrame while we are still handling the previous BeginFrame.
args.frame_time += base::TimeDelta::FromSeconds(1);
scheduler->BeginFrame(args);
- EXPECT_EQ(0, client.num_actions_());
+ EXPECT_NO_ACTION(client);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
EXPECT_TRUE(client.needs_begin_frame());
client.Reset();
// BeginImplFrame deadline should draw.
scheduler->SetNeedsRedraw();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
+
+ EXPECT_TRUE(client.task_runner().RunTasksWhile(
+ client.ImplFrameDeadlinePending(true)));
+
EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
scheduler_settings.begin_frame_scheduling_enabled =
begin_frame_scheduling_enabled;
scheduler_settings.throttle_frame_production = throttle_frame_production;
- Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
client.Reset();
scheduler->SetNeedsCommit();
EXPECT_FALSE(client.needs_begin_frame());
- EXPECT_EQ(0, client.num_actions_());
+ EXPECT_NO_ACTION(client);
client.Reset();
// When the client-driven BeginFrame are disabled, the scheduler posts it's
// If we don't swap on the deadline, we wait for the next BeginFrame.
client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(0, client.num_actions_());
+ EXPECT_NO_ACTION(client);
EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
EXPECT_FALSE(client.needs_begin_frame());
client.Reset();
client.Reset();
// BeginImplFrame deadline should draw.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
+ client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
EXPECT_FALSE(client.needs_begin_frame());
// Make sure SetNeedsBeginFrame isn't called on the client
// when the BeginFrame is no longer needed.
client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(0, client.num_actions_());
+ EXPECT_NO_ACTION(client);
EXPECT_FALSE(client.needs_begin_frame());
client.Reset();
}
scheduler_settings.begin_frame_scheduling_enabled =
begin_frame_scheduling_enabled;
scheduler_settings.throttle_frame_production = throttle_frame_production;
- Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
client.Reset();
scheduler->SetNeedsCommit();
EXPECT_FALSE(client.needs_begin_frame());
- EXPECT_EQ(0, client.num_actions_());
+ EXPECT_NO_ACTION(client);
client.Reset();
// Trigger the first BeginImplFrame and BeginMainFrame
throttle_frame_production);
}
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterOutputSurfaceIsInitialized) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ client.Reset();
+ scheduler->DidCreateAndInitializeOutputSurface();
+ EXPECT_NO_ACTION(client);
+
+ scheduler->DidLoseOutputSurface();
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStarted) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+ // SetNeedsCommit should begin the frame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+ client.Reset();
+ client.AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->DidLoseOutputSurface();
+ // Do nothing when impl frame is in deadine pending state.
+ EXPECT_NO_ACTION(client);
+
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_ACTION("ScheduledActionCommit", client, 0, 1);
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+}
+
+void DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(
+ bool impl_side_painting) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.impl_side_painting = impl_side_painting;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // SetNeedsCommit should begin the frame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+ client.Reset();
+ client.AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->DidLoseOutputSurface();
+ // Do nothing when impl frame is in deadine pending state.
+ EXPECT_NO_ACTION(client);
+
+ client.Reset();
+ // Run posted deadline.
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
+ // OnBeginImplFrameDeadline didn't schedule any actions because main frame is
+ // not yet completed.
+ EXPECT_NO_ACTION(client);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+
+ // BeginImplFrame is not started.
+ client.task_runner().RunUntilTime(client.now_src()->Now() +
+ base::TimeDelta::FromMilliseconds(10));
+ EXPECT_NO_ACTION(client);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ if (impl_side_painting) {
+ EXPECT_ACTION("ScheduledActionCommit", client, 0, 3);
+ EXPECT_ACTION("ScheduledActionActivateSyncTree", client, 1, 3);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 2, 3);
+ } else {
+ EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
+ }
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency) {
+ bool impl_side_painting = false;
+ DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting);
+}
+
+TEST(SchedulerTest,
+ DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatencyWithImplPaint) {
+ bool impl_side_painting = true;
+ DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting);
+}
+
+void DidLoseOutputSurfaceAfterReadyToCommit(bool impl_side_painting) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.impl_side_painting = impl_side_painting;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // SetNeedsCommit should begin the frame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+ client.Reset();
+ client.AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+
+ client.Reset();
+ scheduler->DidLoseOutputSurface();
+ if (impl_side_painting) {
+ // Sync tree should be forced to activate.
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client);
+ } else {
+ // Do nothing when impl frame is in deadine pending state.
+ EXPECT_NO_ACTION(client);
+ }
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommit) {
+ DidLoseOutputSurfaceAfterReadyToCommit(false);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommitWithImplPainting) {
+ DidLoseOutputSurfaceAfterReadyToCommit(true);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterSetNeedsManageTiles) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ client.Reset();
+ scheduler->SetNeedsManageTiles();
+ scheduler->SetNeedsRedraw();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ client.Reset();
+ client.AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->DidLoseOutputSurface();
+ EXPECT_NO_ACTION(client);
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionManageTiles", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+ // Create a BeginFrame with a long deadline to avoid race conditions.
+ // This is the first BeginFrame, which will be handled immediately.
+ client.Reset();
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+ args.deadline += base::TimeDelta::FromHours(1);
+ scheduler->BeginFrame(args);
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ // Queue BeginFrames while we are still handling the previous BeginFrame.
+ args.frame_time += base::TimeDelta::FromSeconds(1);
+ scheduler->BeginFrame(args);
+ args.frame_time += base::TimeDelta::FromSeconds(1);
+ scheduler->BeginFrame(args);
+
+ // If we don't swap on the deadline, we wait for the next BeginImplFrame.
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ // NotifyReadyToCommit should trigger the commit.
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ client.Reset();
+ EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty());
+ scheduler->DidLoseOutputSurface();
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty());
+
+ // Posted BeginRetroFrame is aborted.
+ client.Reset();
+ client.task_runner().RunPendingTasks();
+ EXPECT_NO_ACTION(client);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+ // Create a BeginFrame with a long deadline to avoid race conditions.
+ // This is the first BeginFrame, which will be handled immediately.
+ client.Reset();
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+ args.deadline += base::TimeDelta::FromHours(1);
+ scheduler->BeginFrame(args);
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ // Queue BeginFrames while we are still handling the previous BeginFrame.
+ args.frame_time += base::TimeDelta::FromSeconds(1);
+ scheduler->BeginFrame(args);
+ args.frame_time += base::TimeDelta::FromSeconds(1);
+ scheduler->BeginFrame(args);
+
+ // If we don't swap on the deadline, we wait for the next BeginImplFrame.
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ // NotifyReadyToCommit should trigger the commit.
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ // BeginImplFrame should prepare the draw.
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ client.Reset();
+ EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty());
+ scheduler->DidLoseOutputSurface();
+ EXPECT_NO_ACTION(client);
+ EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty());
+
+ // BeginImplFrame deadline should abort drawing.
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ // No more BeginRetroFrame because BeginRetroFrame queue is cleared.
+ client.Reset();
+ client.task_runner().RunPendingTasks();
+ EXPECT_NO_ACTION(client);
+}
+
+TEST(SchedulerTest,
+ StopBeginFrameAfterDidLoseOutputSurfaceWithSyntheticBeginFrameSource) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.begin_frame_scheduling_enabled = false;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ client.Reset();
+ EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive());
+ scheduler->SetNeedsCommit();
+ EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive());
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted Tick.
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive());
+
+ // NotifyReadyToCommit should trigger the commit.
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive());
+
+ client.Reset();
+ scheduler->DidLoseOutputSurface();
+ EXPECT_EQ(0, client.num_actions_());
+ EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive());
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive());
+}
+
+TEST(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.impl_side_painting = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // SetNeedsCommit should begin the frame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+ client.Reset();
+ client.AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+
+ client.Reset();
+ scheduler->SetVisible(false);
+ // Sync tree should be forced to activate.
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client);
+}
+
} // namespace
} // namespace cc