#include "cc/scheduler/scheduler_state_machine.h"
#include <stddef.h>
#include <array>
#include <tuple>
#include "base/feature_list.h"
#include "base/strings/stringprintf.h"
#include "base/test/gtest_util.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "cc/base/features.h"
#include "cc/metrics/begin_main_frame_metrics.h"
#include "cc/scheduler/scheduler.h"
#include "cc/tiles/tile_priority.h"
#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/test/begin_frame_args_test.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#define EXPECT_ENUM_EQ(enum_tostring, expected, actual) \
EXPECT_THAT(enum_tostring(actual), testing::Eq(enum_tostring(expected)))
#define EXPECT_IMPL_FRAME_STATE(expected) \
EXPECT_ENUM_EQ(BeginImplFrameStateToString, expected, \
state.begin_impl_frame_state())
#define EXPECT_MAIN_FRAME_STATE(expected) \
EXPECT_ENUM_EQ(BeginMainFrameStateToString, expected, \
state.GetBeginMainFrameState())
#define EXPECT_NEXT_MAIN_FRAME_STATE(expected) \
EXPECT_ENUM_EQ(BeginMainFrameStateToString, expected, \
state.GetNextBeginMainFrameState())
#define EXPECT_ACTION(expected) \
EXPECT_ENUM_EQ(ActionToString, expected, state.NextAction())
#define EXPECT_ACTION_UPDATE_STATE(action) \
EXPECT_ACTION(action); \
if (action == SchedulerStateMachine::Action::DRAW_IF_POSSIBLE || \
action == SchedulerStateMachine::Action::DRAW_FORCED) { \
EXPECT_IMPL_FRAME_STATE( \
SchedulerStateMachine::BeginImplFrameState::INSIDE_DEADLINE); \
} \
PerformAction(&state, action); \
if (action == SchedulerStateMachine::Action::NONE) { \
if (state.begin_impl_frame_state() == \
SchedulerStateMachine::BeginImplFrameState::INSIDE_DEADLINE) \
state.OnBeginImplFrameIdle(); \
}
#define SET_UP_STATE(state) \
state.SetVisible(true); \
EXPECT_ACTION_UPDATE_STATE( \
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION); \
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE); \
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit(); \
state.SetCanDraw(true)
namespace cc {
namespace {
const char* BeginImplFrameStateToString(
SchedulerStateMachine::BeginImplFrameState state) {
using BeginImplFrameState = SchedulerStateMachine::BeginImplFrameState;
switch (state) {
case BeginImplFrameState::IDLE:
return "BeginImplFrameState::IDLE";
case BeginImplFrameState::INSIDE_BEGIN_FRAME:
return "BeginImplFrameState::INSIDE_BEGIN_FRAME";
case BeginImplFrameState::INSIDE_DEADLINE:
return "BeginImplFrameState::INSIDE_DEADLINE";
}
NOTREACHED();
}
const char* BeginMainFrameStateToString(
SchedulerStateMachine::BeginMainFrameState state) {
using BeginMainFrameState = SchedulerStateMachine::BeginMainFrameState;
switch (state) {
case BeginMainFrameState::IDLE:
return "BeginMainFrameState::IDLE";
case BeginMainFrameState::SENT:
return "BeginMainFrameState::SENT";
case BeginMainFrameState::READY_TO_COMMIT:
return "BeginMainFrameState::READY_TO_COMMIT";
}
NOTREACHED();
}
const char* ActionToString(SchedulerStateMachine::Action action) {
using Action = SchedulerStateMachine::Action;
switch (action) {
case Action::NONE:
return "Action::NONE";
case Action::SEND_BEGIN_MAIN_FRAME:
return "Action::SEND_BEGIN_MAIN_FRAME";
case Action::COMMIT:
return "Action::COMMIT";
case Action::POST_COMMIT:
return "Action::POST_COMMIT";
case Action::ACTIVATE_SYNC_TREE:
return "Action::ACTIVATE_SYNC_TREE";
case Action::DRAW_IF_POSSIBLE:
return "Action::DRAW_IF_POSSIBLE";
case Action::DRAW_FORCED:
return "Action::DRAW_FORCED";
case Action::DRAW_ABORT:
return "Action::DRAW_ABORT";
case Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION:
return "Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION";
case Action::PREPARE_TILES:
return "Action::PREPARE_TILES";
case Action::INVALIDATE_LAYER_TREE_FRAME_SINK:
return "Action::INVALIDATE_LAYER_TREE_FRAME_SINK";
case Action::PERFORM_IMPL_SIDE_INVALIDATION:
return "Action::PERFORM_IMPL_SIDE_INVALIDATION";
case Action::NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL:
return "Action::NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL";
case Action::NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_SOON:
return "Action::NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_SOON";
}
NOTREACHED();
}
const bool kAnimateOnly = false;
const auto all_begin_impl_frame_states =
std::to_array<SchedulerStateMachine::BeginImplFrameState>({
SchedulerStateMachine::BeginImplFrameState::IDLE,
SchedulerStateMachine::BeginImplFrameState::INSIDE_BEGIN_FRAME,
SchedulerStateMachine::BeginImplFrameState::INSIDE_DEADLINE,
});
const auto begin_main_frame_states =
std::to_array<SchedulerStateMachine::BeginMainFrameState>({
SchedulerStateMachine::BeginMainFrameState::IDLE,
SchedulerStateMachine::BeginMainFrameState::SENT,
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT,
});
class StateMachine : public SchedulerStateMachine {
public:
explicit StateMachine(const SchedulerSettings& scheduler_settings)
: SchedulerStateMachine(scheduler_settings),
draw_result_for_test_(DrawResult::kSuccess) {}
void CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit() {
DidCreateAndInitializeLayerTreeFrameSink();
layer_tree_frame_sink_state_ = LayerTreeFrameSinkState::ACTIVE;
}
void IssueNextBeginImplFrame() {
return IssueBeginImplFrame(next_begin_frame_number_++);
}
void IssueBeginImplFrame(uint64_t sequence_number) {
auto args = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, 0, sequence_number, now_ticks_,
now_ticks_ + base::Hertz(60), base::Hertz(60),
viz::BeginFrameArgs::NORMAL);
args.animate_only = kAnimateOnly;
OnBeginImplFrame(args);
}
void SetBeginMainFrameState(BeginMainFrameState cs) {
begin_main_frame_state_ = cs;
}
BeginMainFrameState GetBeginMainFrameState() const {
return begin_main_frame_state_;
}
BeginMainFrameState GetNextBeginMainFrameState() const {
return next_begin_main_frame_state_;
}
ForcedRedrawOnTimeoutState ForcedRedrawState() const {
return forced_redraw_state_;
}
void SetBeginImplFrameState(BeginImplFrameState bifs) {
begin_impl_frame_state_ = bifs;
}
BeginImplFrameState begin_impl_frame_state() const {
return begin_impl_frame_state_;
}
LayerTreeFrameSinkState layer_tree_frame_sink_state() const {
return layer_tree_frame_sink_state_;
}
void SetNeedsBeginMainFrameForTest(bool needs_begin_main_frame) {
needs_begin_main_frame_ = needs_begin_main_frame;
}
bool NeedsCommit() const { return needs_begin_main_frame_; }
void SetNeedsOneBeginImplFrame(bool needs_frame) {
needs_one_begin_impl_frame_ = needs_frame;
}
void SetNeedsRedraw(bool needs_redraw) { needs_redraw_ = needs_redraw; }
void SetDrawResultForTest(DrawResult draw_result) {
draw_result_for_test_ = draw_result;
}
DrawResult draw_result_for_test() { return draw_result_for_test_; }
void SetNeedsForcedRedrawForTimeout(bool b) {
forced_redraw_state_ = ForcedRedrawOnTimeoutState::WAITING_FOR_COMMIT;
active_tree_needs_first_draw_ = true;
}
bool NeedsForcedRedrawForTimeout() const {
return forced_redraw_state_ != ForcedRedrawOnTimeoutState::IDLE;
}
void SetActiveTreeNeedsFirstDraw(bool needs_first_draw) {
active_tree_needs_first_draw_ = needs_first_draw;
}
void DidReceiveCompositorFrameAck() {
if (!base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
SchedulerStateMachine::DidReceiveCompositorFrameAck();
}
}
bool CanDraw() const { return can_draw_; }
bool Visible() const { return visible_; }
bool ShouldAbortCurrentFrame() const {
return SchedulerStateMachine::ShouldAbortCurrentFrame();
}
bool has_pending_tree() const { return has_pending_tree_; }
void SetHasPendingTree(bool has_pending_tree) {
has_pending_tree_ = has_pending_tree;
}
bool needs_impl_side_invalidation() const {
return needs_impl_side_invalidation_;
}
void AdvanceTimeBy(base::TimeDelta delta) { now_ticks_ += delta; }
base::TimeTicks Now() const override { return now_ticks_; }
using SchedulerStateMachine::ProactiveBeginFrameWanted;
using SchedulerStateMachine::ShouldDraw;
using SchedulerStateMachine::ShouldPrepareTiles;
using SchedulerStateMachine::ShouldSendBeginMainFrame;
using SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately;
using SchedulerStateMachine::ShouldWaitForScrollEvent;
using SchedulerStateMachine::WillCommit;
protected:
DrawResult draw_result_for_test_;
uint64_t next_begin_frame_number_ = viz::BeginFrameArgs::kStartingFrameNumber;
base::TimeTicks now_ticks_;
};
void PerformAction(StateMachine* sm, SchedulerStateMachine::Action action) {
switch (action) {
case SchedulerStateMachine::Action::NONE:
return;
case SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE:
sm->WillActivate();
return;
case SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME:
sm->WillSendBeginMainFrame();
return;
case SchedulerStateMachine::Action::
NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL:
sm->WillNotifyBeginMainFrameNotExpectedUntil();
return;
case SchedulerStateMachine::Action::
NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_SOON:
sm->WillNotifyBeginMainFrameNotExpectedSoon();
return;
case SchedulerStateMachine::Action::COMMIT: {
bool commit_has_no_updates = false;
sm->WillCommit(commit_has_no_updates);
sm->DidCommit();
return;
}
case SchedulerStateMachine::Action::POST_COMMIT:
sm->DidPostCommit();
return;
case SchedulerStateMachine::Action::DRAW_FORCED:
case SchedulerStateMachine::Action::DRAW_IF_POSSIBLE: {
sm->WillDraw();
sm->DidDraw(sm->draw_result_for_test());
return;
}
case SchedulerStateMachine::Action::DRAW_ABORT: {
sm->AbortDraw();
return;
}
case SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION:
sm->WillBeginLayerTreeFrameSinkCreation();
return;
case SchedulerStateMachine::Action::PREPARE_TILES:
sm->WillPrepareTiles();
return;
case SchedulerStateMachine::Action::INVALIDATE_LAYER_TREE_FRAME_SINK:
sm->WillInvalidateLayerTreeFrameSink();
return;
case SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION:
sm->WillPerformImplSideInvalidation();
return;
}
}
TEST(SchedulerStateMachineTest, BeginFrameNeeded) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetBeginMainFrameState(
SchedulerStateMachine::BeginMainFrameState::IDLE);
state.SetNeedsRedraw(false);
state.SetNeedsOneBeginImplFrame(false);
EXPECT_FALSE(state.BeginFrameNeeded());
state.SetNeedsRedraw(false);
state.SetNeedsOneBeginImplFrame(true);
EXPECT_TRUE(state.BeginFrameNeeded());
state.SetVisible(true);
state.SetNeedsRedraw(true);
state.SetNeedsOneBeginImplFrame(false);
EXPECT_TRUE(state.BeginFrameNeeded());
state.SetVisible(false);
state.SetNeedsRedraw(true);
state.SetNeedsOneBeginImplFrame(false);
EXPECT_FALSE(state.BeginFrameNeeded());
state.SetVisible(true);
state.SetNeedsRedraw(false);
state.SetNeedsOneBeginImplFrame(false);
state.SetNeedsBeginMainFrameForTest(true);
EXPECT_TRUE(state.BeginFrameNeeded());
state.SetVisible(true);
state.SetNeedsRedraw(false);
state.SetNeedsOneBeginImplFrame(false);
state.SetNeedsBeginMainFrameForTest(true);
state.SetDeferBeginMainFrame(true);
EXPECT_FALSE(state.BeginFrameNeeded());
}
TEST(SchedulerStateMachineTest, BeginMainFrameIsHighestPriorityAction) {
SchedulerSettings default_scheduler_settings;
default_scheduler_settings.main_frame_before_activation_enabled = true;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION(SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest,
TestNextActionNotifyBeginMainFrameNotExpectedUntil) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetMainThreadWantsBeginMainFrameNotExpectedMessages(true);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
state.IssueNextBeginImplFrame();
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetNeedsOneBeginImplFrame(true);
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::
NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsRedraw(true);
state.SetNeedsBeginMainFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest,
TestNextActionNotifyBeginMainFrameNotExpectedSoon) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetMainThreadWantsBeginMainFrameNotExpectedMessages(true);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
state.IssueNextBeginImplFrame();
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetNeedsOneBeginImplFrame(true);
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::
NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsOneBeginImplFrame(false);
EXPECT_FALSE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetBeginImplFrameState(
SchedulerStateMachine::BeginImplFrameState::IDLE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_SOON);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
SchedulerSettings default_scheduler_settings;
{
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetBeginMainFrameState(
SchedulerStateMachine::BeginMainFrameState::IDLE);
state.SetNeedsRedraw(false);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_FALSE(state.NeedsCommit());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_FALSE(state.NeedsCommit());
}
{
StateMachine state(default_scheduler_settings);
state.SetBeginMainFrameState(
SchedulerStateMachine::BeginMainFrameState::IDLE);
state.SetNeedsRedraw(false);
state.SetNeedsBeginMainFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.NeedsCommit());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.NeedsCommit());
}
{
StateMachine state(default_scheduler_settings);
state.SetBeginMainFrameState(
SchedulerStateMachine::BeginMainFrameState::IDLE);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetNeedsRedraw(false);
state.SetNeedsBeginMainFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BeginImplFrameState::IDLE);
EXPECT_TRUE(state.NeedsCommit());
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
EXPECT_FALSE(state.NeedsCommit());
}
{
StateMachine state(default_scheduler_settings);
state.SetBeginMainFrameState(
SchedulerStateMachine::BeginMainFrameState::IDLE);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetNeedsRedraw(false);
state.SetNeedsBeginMainFrame();
state.SetCanDraw(false);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BeginImplFrameState::IDLE);
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
EXPECT_FALSE(state.NeedsCommit());
}
}
TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) {
SchedulerSettings scheduler_settings;
scheduler_settings.main_frame_before_activation_enabled = true;
StateMachine state(scheduler_settings);
state.SetBeginMainFrameState(
SchedulerStateMachine::BeginMainFrameState::IDLE);
SET_UP_STATE(state);
state.SetNeedsRedraw(false);
state.SetNeedsBeginMainFrame();
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
}
TEST(SchedulerStateMachineTest,
FailedDrawForAnimationCheckerboardSetsNeedsCommitAndRetriesDraw) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_FALSE(state.CommitPending());
state.OnBeginImplFrameDeadline();
state.SetDrawResultForTest(DrawResult::kAbortedCheckerboardAnimations);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameIdle();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.CommitPending());
EXPECT_TRUE(state.RedrawPending());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
state.SetDrawResultForTest(DrawResult::kAbortedCheckerboardAnimations);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameIdle();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest, FailedDrawForMissingHighResNeedsCommit) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_FALSE(state.CommitPending());
state.OnBeginImplFrameDeadline();
state.SetDrawResultForTest(DrawResult::kAbortedMissingHighResContent);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameIdle();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.CommitPending());
EXPECT_FALSE(state.RedrawPending());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameIdle();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.RedrawPending());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
state.SetDrawResultForTest(DrawResult::kSuccess);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameIdle();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest,
TestFailedDrawsEventuallyForceDrawAfterNextCommit) {
SchedulerSettings scheduler_settings;
scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced = 1;
StateMachine state(scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.CommitPending());
state.SetNeedsRedraw(true);
state.OnBeginImplFrameDeadline();
state.SetDrawResultForTest(DrawResult::kAbortedCheckerboardAnimations);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.CommitPending());
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.RedrawPending());
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.RedrawPending());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
state.SetDrawResultForTest(DrawResult::kSuccess);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_FORCED);
state.DidSubmitCompositorFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest, TestFailedDrawsDoNotRestartForcedDraw) {
SchedulerSettings scheduler_settings;
int draw_limit = 2;
scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced =
draw_limit;
StateMachine state(scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.CommitPending());
state.SetNeedsRedraw(true);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
for (int i = 0; i < draw_limit; ++i) {
state.SetNeedsRedraw(true);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
state.SetDrawResultForTest(DrawResult::kAbortedCheckerboardAnimations);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameIdle();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.CommitPending());
EXPECT_TRUE(
state.ForcedRedrawState() ==
SchedulerStateMachine::ForcedRedrawOnTimeoutState::WAITING_FOR_COMMIT);
for (int i = 0; i < draw_limit; ++i) {
state.SetNeedsRedraw(true);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
state.SetDrawResultForTest(DrawResult::kAbortedCheckerboardAnimations);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameIdle();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(
state.ForcedRedrawState() ==
SchedulerStateMachine::ForcedRedrawOnTimeoutState::WAITING_FOR_COMMIT);
}
TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_TRUE(state.RedrawPending());
state.SetDrawResultForTest(DrawResult::kAbortedCheckerboardAnimations);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
state.SetDrawResultForTest(DrawResult::kSuccess);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsRedraw(true);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.BeginFrameNeeded());
}
TEST(SchedulerStateMachineTest, TestNextActionDrawsOnBeginImplFrame) {
SchedulerSettings default_scheduler_settings;
for (size_t i = 0; i < begin_main_frame_states.size(); ++i) {
for (size_t j = 0; j < all_begin_impl_frame_states.size(); ++j) {
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetBeginMainFrameState(begin_main_frame_states[i]);
state.SetBeginImplFrameState(all_begin_impl_frame_states[j]);
bool visible =
(all_begin_impl_frame_states[j] !=
SchedulerStateMachine::BeginImplFrameState::INSIDE_DEADLINE);
state.SetVisible(visible);
EXPECT_NE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE,
state.NextAction());
state.SetNeedsBeginMainFrame();
EXPECT_NE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE,
state.NextAction());
}
}
for (size_t i = 0; i < begin_main_frame_states.size(); ++i) {
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetCanDraw(true);
state.SetBeginMainFrameState(begin_main_frame_states[i]);
state.SetBeginImplFrameState(
SchedulerStateMachine::BeginImplFrameState::INSIDE_DEADLINE);
state.SetNeedsRedraw(true);
SchedulerStateMachine::Action expected_action;
if (begin_main_frame_states[i] ==
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT) {
expected_action = SchedulerStateMachine::Action::COMMIT;
} else {
expected_action = SchedulerStateMachine::Action::DRAW_IF_POSSIBLE;
}
EXPECT_ACTION(expected_action);
state.SetNeedsBeginMainFrame();
EXPECT_ACTION(expected_action);
}
}
TEST(SchedulerStateMachineTest, TestNoBeginMainFrameStatesRedrawWhenInvisible) {
SchedulerSettings default_scheduler_settings;
for (size_t i = 0; i < begin_main_frame_states.size(); ++i) {
for (size_t j = 0; j < 2; ++j) {
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetBeginMainFrameState(begin_main_frame_states[i]);
state.SetVisible(false);
state.SetNeedsRedraw(true);
if (j == 1) {
state.SetBeginImplFrameState(
SchedulerStateMachine::BeginImplFrameState::INSIDE_DEADLINE);
}
EXPECT_NE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE,
state.NextAction());
state.SetNeedsBeginMainFrame();
EXPECT_NE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE,
state.NextAction());
}
}
}
TEST(SchedulerStateMachineTest, TestCanRedraw_StopsDraw) {
SchedulerSettings default_scheduler_settings;
for (size_t i = 0; i < begin_main_frame_states.size(); ++i) {
for (size_t j = 0; j < 2; ++j) {
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetBeginMainFrameState(begin_main_frame_states[i]);
state.SetVisible(false);
state.SetNeedsRedraw(true);
if (j == 1)
state.IssueNextBeginImplFrame();
state.SetCanDraw(false);
EXPECT_NE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE,
state.NextAction());
}
}
}
TEST(SchedulerStateMachineTest,
TestCanRedrawWithWaitingForFirstDrawMakesProgress) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetActiveTreeNeedsFirstDraw(true);
state.SetNeedsBeginMainFrame();
state.SetNeedsRedraw(true);
state.SetCanDraw(false);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_ABORT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_ABORT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest, TestSetNeedsBeginMainFrameIsNotLost) {
SchedulerSettings scheduler_settings;
StateMachine state(scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
state.SetNeedsBeginMainFrame();
EXPECT_TRUE(state.NeedsCommit());
state.NotifyReadyToCommit();
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
EXPECT_IMPL_FRAME_STATE(
SchedulerStateMachine::BeginImplFrameState::INSIDE_BEGIN_FRAME);
EXPECT_ACTION(SchedulerStateMachine::Action::COMMIT);
state.OnBeginImplFrameDeadline();
EXPECT_IMPL_FRAME_STATE(
SchedulerStateMachine::BeginImplFrameState::INSIDE_DEADLINE);
EXPECT_ACTION(SchedulerStateMachine::Action::COMMIT);
state.OnBeginImplFrameIdle();
EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BeginImplFrameState::IDLE);
EXPECT_ACTION(SchedulerStateMachine::Action::COMMIT);
state.IssueNextBeginImplFrame();
EXPECT_IMPL_FRAME_STATE(
SchedulerStateMachine::BeginImplFrameState::INSIDE_BEGIN_FRAME);
EXPECT_ACTION(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest, TestFullCycle) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_TRUE(state.needs_redraw());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
EXPECT_FALSE(state.needs_redraw());
}
namespace {
bool RunOneFrameAndReturnWhetherMainFrameIsIssued(
StateMachine& state,
base::TimeDelta processing_delay = base::TimeDelta()) {
state.IssueNextBeginImplFrame();
state.AdvanceTimeBy(processing_delay);
bool send_begin_main_frame = state.ShouldSendBeginMainFrame();
if (send_begin_main_frame) {
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::LATE,
state.CurrentBeginImplFrameDeadlineMode());
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_TRUE(state.needs_redraw());
} else {
state.SetNeedsRedraw(true);
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::IMMEDIATE,
state.CurrentBeginImplFrameDeadlineMode());
}
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
EXPECT_FALSE(state.needs_redraw());
return send_begin_main_frame;
}
}
TEST(SchedulerStateMachineTest, TestMainFrameThrottling) {
base::test::ScopedFeatureList scoped_feature_list_{
features::kThrottleMainFrameTo60Hz};
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.FrameIntervalUpdated(base::Hertz(120));
state.AdvanceTimeBy(base::Seconds(1280));
int begin_main_frame_count = 0;
for (int i = 0; i < 10; i++) {
state.SetNeedsBeginMainFrame();
begin_main_frame_count +=
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
state.AdvanceTimeBy(base::Hertz(120));
}
EXPECT_EQ(begin_main_frame_count, 5);
}
TEST(SchedulerStateMachineTest,
TestMainFrameThrottlingWithMainThreadScrolling) {
base::test::ScopedFeatureList scoped_feature_list_{
features::kThrottleMainFrameTo60Hz};
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.FrameIntervalUpdated(base::Hertz(120));
state.AdvanceTimeBy(base::Seconds(1280));
state.SetTreePrioritiesAndScrollState(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER, true);
int begin_main_frame_count = 0;
for (int i = 0; i < 10; i++) {
state.SetNeedsBeginMainFrame();
begin_main_frame_count +=
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
state.AdvanceTimeBy(base::Hertz(120));
}
EXPECT_EQ(begin_main_frame_count, 10);
state.SetTreePrioritiesAndScrollState(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER, false);
begin_main_frame_count = 0;
for (int i = 0; i < 10; i++) {
state.SetNeedsBeginMainFrame();
begin_main_frame_count +=
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
state.AdvanceTimeBy(base::Hertz(120));
}
EXPECT_EQ(begin_main_frame_count, 5);
}
TEST(SchedulerStateMachineTest, TestProactiveMainFrameThrottling) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeatureWithParameters(
features::kRenderThrottleFrameRate,
{{"render-throttled-frame-interval-hz", "30"}});
base::TimeDelta throttled_interval =
base::Hertz(features::kRenderThrottledFrameIntervalHz.Get());
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.FrameIntervalUpdated(base::Hertz(120));
state.AdvanceTimeBy(base::Seconds(1280));
auto GetFrameCountFor10Intervals = [&state](int interval_hz) {
int begin_main_frame_count = 0;
for (int i = 0; i < 10; i++) {
state.SetNeedsBeginMainFrame();
begin_main_frame_count +=
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
state.AdvanceTimeBy(base::Hertz(120));
}
return begin_main_frame_count;
};
EXPECT_EQ(GetFrameCountFor10Intervals(120), 10);
EXPECT_EQ(state.MainFrameThrottledInterval(), base::TimeDelta());
state.SetShouldThrottleFrameRate(true);
EXPECT_EQ(GetFrameCountFor10Intervals(120), 2);
EXPECT_EQ(state.MainFrameThrottledInterval(), throttled_interval);
state.SetShouldThrottleFrameRate(false);
EXPECT_EQ(GetFrameCountFor10Intervals(120), 10);
EXPECT_EQ(state.MainFrameThrottledInterval(), base::TimeDelta());
}
TEST(SchedulerStateMachineTest, TestMainFrameThrottlingIsNotSensitiveToDelays) {
base::test::ScopedFeatureList scoped_feature_list_{
features::kThrottleMainFrameTo60Hz};
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.FrameIntervalUpdated(base::Hertz(120));
state.AdvanceTimeBy(base::Seconds(1280));
state.SetNeedsBeginMainFrame();
EXPECT_TRUE(RunOneFrameAndReturnWhetherMainFrameIsIssued(state));
state.AdvanceTimeBy(base::Hertz(120));
state.SetNeedsBeginMainFrame();
EXPECT_FALSE(RunOneFrameAndReturnWhetherMainFrameIsIssued(
state, base::Milliseconds(100)));
state.AdvanceTimeBy(base::Hertz(120));
state.SetNeedsBeginMainFrame();
EXPECT_TRUE(RunOneFrameAndReturnWhetherMainFrameIsIssued(state));
}
TEST(SchedulerStateMachineTest, TestMainFrameThrottlingDifferentRates) {
base::test::ScopedFeatureList scoped_feature_list_{
features::kThrottleMainFrameTo60Hz};
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.FrameIntervalUpdated(base::Hertz(144));
state.AdvanceTimeBy(base::Seconds(1280));
int begin_main_frame_count = 0;
for (int i = 0; i < 10; i++) {
state.SetNeedsBeginMainFrame();
begin_main_frame_count +=
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
state.AdvanceTimeBy(base::Hertz(144));
}
EXPECT_EQ(begin_main_frame_count, 5);
state.FrameIntervalUpdated(base::Hertz(60));
EXPECT_EQ(base::TimeDelta(), state.MainFrameThrottledInterval());
begin_main_frame_count = 0;
for (int i = 0; i < 10; i++) {
state.SetNeedsBeginMainFrame();
begin_main_frame_count +=
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
state.AdvanceTimeBy(base::Hertz(60));
}
EXPECT_EQ(begin_main_frame_count, 10);
constexpr float kSlackFactor = .9;
state.FrameIntervalUpdated(base::Hertz(90));
EXPECT_EQ(base::TimeDelta(), state.MainFrameThrottledInterval());
state.FrameIntervalUpdated(base::Hertz(120));
EXPECT_NEAR(state.MainFrameThrottledInterval().InMillisecondsF(),
(base::Hertz(60) * kSlackFactor).InMillisecondsF(), 1e-2);
state.FrameIntervalUpdated(base::Hertz(144));
EXPECT_NEAR(state.MainFrameThrottledInterval().InMillisecondsF(),
(base::Hertz(72) * kSlackFactor).InMillisecondsF(), 1e-2);
state.FrameIntervalUpdated(base::Hertz(240));
EXPECT_NEAR(state.MainFrameThrottledInterval().InMillisecondsF(),
(base::Hertz(120) * kSlackFactor).InMillisecondsF(), 1e-2);
state.FrameIntervalUpdated(base::Hertz(90));
EXPECT_EQ(base::TimeDelta(), state.MainFrameThrottledInterval());
}
TEST(SchedulerStateMachineTest, TestMainFrameThrottlingWithUrgentUpdates) {
base::test::ScopedFeatureList scoped_feature_list_{
features::kThrottleMainFrameTo60Hz};
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.FrameIntervalUpdated(base::Hertz(120));
state.AdvanceTimeBy(base::Seconds(1280));
int begin_main_frame_count = 0;
for (int i = 0; i < 10; i++) {
state.SetNeedsBeginMainFrame(true);
begin_main_frame_count +=
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
state.AdvanceTimeBy(base::Hertz(120));
}
EXPECT_EQ(begin_main_frame_count, 10);
begin_main_frame_count = 0;
for (int i = 0; i < 10; i++) {
state.SetNeedsBeginMainFrame(false);
state.SetNeedsBeginMainFrame(true);
begin_main_frame_count +=
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
state.AdvanceTimeBy(base::Hertz(120));
}
EXPECT_EQ(begin_main_frame_count, 10);
begin_main_frame_count = 0;
for (int i = 0; i < 10; i++) {
bool urgent = i < 3;
state.SetNeedsBeginMainFrame(urgent);
begin_main_frame_count +=
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
state.AdvanceTimeBy(base::Hertz(120));
}
EXPECT_EQ(begin_main_frame_count, 5 + 1);
}
TEST(SchedulerStateMachineTest, TestMainFrameThrottlingWithUrgentBoost) {
base::test::ScopedFeatureList scoped_feature_list_;
scoped_feature_list_.InitWithFeatures(
{features::kThrottleMainFrameTo60Hz,
features::kBoostFrameRateForUrgentMainFrame},
{});
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.FrameIntervalUpdated(base::Hertz(120));
state.AdvanceTimeBy(base::Seconds(1280));
int begin_main_frame_count = 0;
for (int i = 0; i < 10; i++) {
bool urgent = (i == 0);
state.SetNeedsBeginMainFrame(urgent);
begin_main_frame_count +=
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
state.AdvanceTimeBy(base::Hertz(120));
state.SetNeedsBeginMainFrame(false);
}
EXPECT_EQ(begin_main_frame_count, 10);
state.AdvanceTimeBy(SchedulerStateMachine::kUrgentBoostDuration);
begin_main_frame_count = 0;
for (int i = 0; i < 10; i++) {
state.SetNeedsBeginMainFrame(false);
begin_main_frame_count +=
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
state.AdvanceTimeBy(base::Hertz(120));
state.SetNeedsBeginMainFrame(false);
}
EXPECT_EQ(begin_main_frame_count, 5);
state.AdvanceTimeBy(SchedulerStateMachine::kUrgentBoostDuration);
state.SetNeedsBeginMainFrame(true);
RunOneFrameAndReturnWhetherMainFrameIsIssued(state);
state.AdvanceTimeBy(SchedulerStateMachine::kUrgentBoostDuration / 2);
state.SetNeedsBeginMainFrame(true);
RunOneFrameAndReturnWhetherMainFrameIsIssued(state);
state.AdvanceTimeBy(SchedulerStateMachine::kUrgentBoostDuration / 2);
begin_main_frame_count = 0;
for (int i = 0; i < 10; i++) {
state.SetNeedsBeginMainFrame(false);
begin_main_frame_count +=
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
state.AdvanceTimeBy(base::Hertz(120));
state.SetNeedsBeginMainFrame(false);
}
EXPECT_EQ(begin_main_frame_count, 10);
state.AdvanceTimeBy(SchedulerStateMachine::kUrgentBoostDuration / 2);
begin_main_frame_count = 0;
for (int i = 0; i < 10; i++) {
state.SetNeedsBeginMainFrame(false);
begin_main_frame_count +=
RunOneFrameAndReturnWhetherMainFrameIsIssued(state) ? 1 : 0;
state.AdvanceTimeBy(base::Hertz(120));
state.SetNeedsBeginMainFrame(false);
}
EXPECT_EQ(begin_main_frame_count, 5);
}
TEST(SchedulerStateMachineTest, CommitWithoutDrawWithPendingTree) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
}
TEST(SchedulerStateMachineTest, DontCommitWithoutDrawWithoutPendingTree) {
SchedulerSettings scheduler_settings;
scheduler_settings.commit_to_active_tree = true;
scheduler_settings.main_frame_before_activation_enabled = false;
StateMachine state(scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
uint64_t sequence_number = 10;
state.IssueBeginImplFrame(sequence_number);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
state.SetNeedsBeginMainFrame();
sequence_number++;
state.IssueBeginImplFrame(sequence_number);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest, AbortedMainFrameDoesNotResetPendingTree) {
SchedulerSettings scheduler_settings;
scheduler_settings.main_frame_before_activation_enabled = true;
StateMachine state(scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.has_pending_tree());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.has_pending_tree());
state.BeginMainFrameAborted(CommitEarlyOutReason::kFinishedNoUpdates);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.has_pending_tree());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.has_pending_tree());
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_FALSE(state.has_pending_tree());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.has_pending_tree());
}
class BeginMainFrameSchedulerStateMachineTest
: public testing::Test,
public testing::WithParamInterface<bool> {
public:
BeginMainFrameSchedulerStateMachineTest();
~BeginMainFrameSchedulerStateMachineTest() override = default;
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
BeginMainFrameSchedulerStateMachineTest::
BeginMainFrameSchedulerStateMachineTest() {
if (GetParam()) {
scoped_feature_list_.InitAndEnableFeature(features::kNoCompositorFrameAcks);
} else {
scoped_feature_list_.InitAndDisableFeature(
features::kNoCompositorFrameAcks);
}
}
TEST_P(BeginMainFrameSchedulerStateMachineTest,
TestFullCycleWithCommitToActive) {
SchedulerSettings scheduler_settings;
scheduler_settings.commit_to_active_tree = true;
StateMachine state(scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
uint64_t sequence_number = 10;
state.IssueBeginImplFrame(sequence_number);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_TRUE(state.needs_redraw());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsBeginMainFrame();
sequence_number++;
state.IssueBeginImplFrame(sequence_number);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToDraw();
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
if (!base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
sequence_number++;
state.IssueBeginImplFrame(sequence_number);
if (!base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidReceiveCompositorFrameAck();
}
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToDraw();
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetDeferBeginMainFrame(true);
sequence_number++;
state.IssueBeginImplFrame(sequence_number);
EXPECT_NE(SchedulerStateMachine::BeginImplFrameDeadlineMode::BLOCKED,
state.CurrentBeginImplFrameDeadlineMode());
}
INSTANTIATE_TEST_SUITE_P(,
BeginMainFrameSchedulerStateMachineTest,
testing::Bool(),
[](auto& info) {
return info.param ? "NoCompositorFrameAck"
: "CompositorFrameAck";
});
TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsBeginMainFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_TRUE(state.needs_redraw());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
EXPECT_FALSE(state.needs_redraw());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest, TestNoRequestCommitWhenInvisible) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetVisible(false);
state.SetNeedsBeginMainFrame();
EXPECT_FALSE(state.CouldSendBeginMainFrame());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest, TestNoRequestCommitWhenBeginFrameSourcePaused) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetBeginFrameSourcePaused(true);
state.SetNeedsBeginMainFrame();
EXPECT_FALSE(state.CouldSendBeginMainFrame());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest, TestNoRequestLayerTreeFrameSinkWhenInvisible) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetVisible(false);
state.DidLoseLayerTreeFrameSink();
state.SetNeedsBeginMainFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
}
TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseInvisible) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetVisible(false);
state.BeginMainFrameAborted(CommitEarlyOutReason::kAbortedNotVisible);
EXPECT_TRUE(state.NeedsCommit());
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetVisible(true);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.NeedsCommit());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseCommitNotNeeded) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidCreateAndInitializeLayerTreeFrameSink();
state.SetCanDraw(true);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
state.BeginMainFrameAborted(CommitEarlyOutReason::kFinishedNoUpdates);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsBeginMainFrame();
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
state.IssueNextBeginImplFrame();
EXPECT_ACTION(SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest, TestMainFrameBeforeCommit) {
SchedulerSettings default_scheduler_settings;
default_scheduler_settings.main_frame_before_commit_enabled = true;
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidCreateAndInitializeLayerTreeFrameSink();
state.SetCanDraw(true);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
EXPECT_NEXT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::IDLE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
EXPECT_NEXT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::IDLE);
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
state.IssueNextBeginImplFrame();
state.SetNeedsBeginMainFrame();
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
state.BeginMainFrameAborted(CommitEarlyOutReason::kFinishedNoUpdates);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
EXPECT_NEXT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::IDLE);
state.NotifyReadyToCommit();
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
EXPECT_NEXT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::IDLE);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
EXPECT_NEXT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::SENT);
state.SetNeedsBeginMainFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
EXPECT_NEXT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::IDLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.IssueNextBeginImplFrame();
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
state.NotifyReadyToCommit();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.BeginMainFrameAborted(CommitEarlyOutReason::kFinishedNoUpdates);
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
EXPECT_NEXT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::IDLE);
EXPECT_ACTION(SchedulerStateMachine::Action::COMMIT);
}
TEST(SchedulerStateMachineTest, TestFirstContextCreation) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
state.SetCanDraw(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest, TestContextLostWhenCompletelyIdle) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
EXPECT_NE(SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION,
state.NextAction());
state.DidLoseLayerTreeFrameSink();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest,
TestContextLostWhenIdleAndCommitRequestedWhileRecreating) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
EXPECT_NE(SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION,
state.NextAction());
state.DidLoseLayerTreeFrameSink();
EXPECT_EQ(state.layer_tree_frame_sink_state(),
SchedulerStateMachine::LayerTreeFrameSinkState::NONE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidCreateAndInitializeLayerTreeFrameSink();
EXPECT_EQ(
state.layer_tree_frame_sink_state(),
SchedulerStateMachine::LayerTreeFrameSinkState::WAITING_FOR_FIRST_COMMIT);
EXPECT_FALSE(state.RedrawPending());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_EQ(state.layer_tree_frame_sink_state(),
SchedulerStateMachine::LayerTreeFrameSinkState::
WAITING_FOR_FIRST_ACTIVATION);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_EQ(state.layer_tree_frame_sink_state(),
SchedulerStateMachine::LayerTreeFrameSinkState::ACTIVE);
EXPECT_TRUE(state.RedrawPending());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_FALSE(state.RedrawPending());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsRedraw(true);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.SetCanDraw(false);
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
state.SetCanDraw(true);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsRedraw(true);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_TRUE(state.needs_redraw());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.SetCanDraw(false);
EXPECT_ACTION(SchedulerStateMachine::Action::DRAW_ABORT);
state.SetCanDraw(true);
EXPECT_ACTION(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
}
TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) {
SchedulerSettings scheduler_settings;
StateMachine state(scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.SetNeedsRedraw(true);
uint64_t sequence_number = 10;
state.IssueBeginImplFrame(sequence_number);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidLoseLayerTreeFrameSink();
EXPECT_FALSE(state.BeginFrameNeeded());
state.SetNeedsRedraw(true);
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_ABORT);
EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BeginImplFrameState::IDLE);
EXPECT_ACTION(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
sequence_number++;
state.IssueBeginImplFrame(sequence_number);
EXPECT_IMPL_FRAME_STATE(
SchedulerStateMachine::BeginImplFrameState::INSIDE_BEGIN_FRAME);
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_IMPL_FRAME_STATE(
SchedulerStateMachine::BeginImplFrameState::INSIDE_DEADLINE);
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest,
TestContextLostWhileCommitInProgressAndAnotherCommitRequested) {
SchedulerSettings scheduler_settings;
StateMachine state(scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsRedraw(true);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidLoseLayerTreeFrameSink();
state.SetNeedsRedraw(true);
state.SetNeedsBeginMainFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_ABORT);
EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BeginImplFrameState::IDLE);
EXPECT_ACTION(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
state.IssueNextBeginImplFrame();
EXPECT_IMPL_FRAME_STATE(
SchedulerStateMachine::BeginImplFrameState::INSIDE_BEGIN_FRAME);
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_IMPL_FRAME_STATE(
SchedulerStateMachine::BeginImplFrameState::INSIDE_DEADLINE);
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameIdle();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest,
DontDrawBeforeCommitAfterLostLayerTreeFrameSink) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsRedraw(true);
state.DidLoseLayerTreeFrameSink();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidCreateAndInitializeLayerTreeFrameSink();
EXPECT_FALSE(state.RedrawPending());
state.IssueNextBeginImplFrame();
EXPECT_ACTION(SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest,
TestShouldAbortCurrentFrameAfterLostLayerTreeFrameSink) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetBeginMainFrameState(
SchedulerStateMachine::BeginMainFrameState::SENT);
state.DidLoseLayerTreeFrameSink();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_TRUE(state.ShouldAbortCurrentFrame());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_ABORT);
}
TEST(SchedulerStateMachineTest, TestNoBeginFrameNeededWhenInvisible) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
EXPECT_FALSE(state.BeginFrameNeeded());
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.BeginFrameNeeded());
state.SetVisible(false);
EXPECT_FALSE(state.BeginFrameNeeded());
state.SetVisible(true);
EXPECT_TRUE(state.BeginFrameNeeded());
}
TEST(SchedulerStateMachineTest, TestNoBeginMainFrameWhenInvisible) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetVisible(false);
state.SetNeedsBeginMainFrame();
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
EXPECT_FALSE(state.BeginFrameNeeded());
state.SetVisible(true);
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest, TestFinishCommitWhenCommitInProgress) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetVisible(false);
state.SetBeginMainFrameState(
SchedulerStateMachine::BeginMainFrameState::SENT);
state.SetNeedsBeginMainFrame();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_ABORT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest,
TestFinishCommitWhenCommitInProgressAndBeginFrameSourcePaused) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetVisible(true);
state.SetCanDraw(true);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.CreateAndInitializeLayerTreeFrameSinkWithActivatedCommit();
state.SetBeginFrameSourcePaused(true);
state.SetBeginMainFrameState(
SchedulerStateMachine::BeginMainFrameState::SENT);
state.SetNeedsBeginMainFrame();
state.NotifyReadyToCommit();
EXPECT_TRUE(state.ShouldAbortCurrentFrame());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_TRUE(state.needs_redraw());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_ABORT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_FALSE(state.active_tree_needs_first_draw());
EXPECT_FALSE(state.needs_redraw());
state.SetBeginFrameSourcePaused(false);
EXPECT_TRUE(state.needs_redraw());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidReceiveCompositorFrameAck();
}
TEST(SchedulerStateMachineTest, TestInitialActionsWhenContextLost) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.DidLoseLayerTreeFrameSink();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
state.DidCreateAndInitializeLayerTreeFrameSink();
EXPECT_EQ(
state.layer_tree_frame_sink_state(),
SchedulerStateMachine::LayerTreeFrameSinkState::WAITING_FOR_FIRST_COMMIT);
state.SetVisible(false);
EXPECT_ACTION(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest, ReportIfNotDrawing) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
state.SetCanDraw(false);
state.SetVisible(true);
EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
state.SetCanDraw(true);
state.SetVisible(false);
EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
state.SetCanDraw(false);
state.SetVisible(false);
EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
state.SetCanDraw(true);
state.SetVisible(true);
state.SetBeginFrameSourcePaused(true);
EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
state.SetBeginFrameSourcePaused(false);
EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
}
TEST(SchedulerStateMachineTest, ForceDrawForResourcelessSoftwareDraw) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetResourcelessSoftwareDraw(true);
EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
state.SetVisible(false);
EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
state.SetResourcelessSoftwareDraw(false);
EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
state.SetResourcelessSoftwareDraw(true);
EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
state.SetVisible(true);
state.SetBeginFrameSourcePaused(true);
EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
state.SetResourcelessSoftwareDraw(false);
EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
state.SetResourcelessSoftwareDraw(true);
EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
state.SetBeginFrameSourcePaused(false);
state.SetVisible(false);
state.DidLoseLayerTreeFrameSink();
state.SetCanDraw(false);
state.WillBeginLayerTreeFrameSinkCreation();
state.DidCreateAndInitializeLayerTreeFrameSink();
EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
state.SetCanDraw(true);
state.DidLoseLayerTreeFrameSink();
EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
state.SetCanDraw(true);
state.WillBeginLayerTreeFrameSinkCreation();
state.DidCreateAndInitializeLayerTreeFrameSink();
EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
state.SetCanDraw(false);
state.DidLoseLayerTreeFrameSink();
EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
}
TEST(SchedulerStateMachineTest,
TestTriggerDeadlineImmediatelyAfterAbortedCommit) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.IssueNextBeginImplFrame();
state.SetNeedsRedraw(true);
state.SetNeedsBeginMainFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.BeginMainFrameAborted(CommitEarlyOutReason::kFinishedNoUpdates);
EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
}
void FinishPreviousCommitAndDrawWithoutExitingDeadline(
StateMachine* state_ptr) {
StateMachine& state = *state_ptr;
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
}
TEST(SchedulerStateMachineTest, TestImplLatencyTakesPriorityImplInvalidations) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetTreePrioritiesAndScrollState(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER, false);
bool needs_first_draw_on_activation = true;
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
uint64_t sequence_number = 1;
state.IssueBeginImplFrame(sequence_number);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
state.OnBeginImplFrameIdle();
state.SetNeedsBeginMainFrame();
sequence_number++;
state.IssueBeginImplFrame(sequence_number);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
}
TEST(SchedulerStateMachineTest,
TestTriggerDeadlineImmediatelyOnLostLayerTreeFrameSink) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.DidLoseLayerTreeFrameSink();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
}
TEST(SchedulerStateMachineTest, TestTriggerDeadlineImmediatelyWhenInvisible) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.SetVisible(false);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.ShouldAbortCurrentFrame());
EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
}
TEST(SchedulerStateMachineTest,
TestTriggerDeadlineImmediatelyWhenBeginFrameSourcePaused) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.SetBeginFrameSourcePaused(true);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.ShouldAbortCurrentFrame());
EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
}
TEST(SchedulerStateMachineTest, TestDeferBeginMainFrame) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
state.SetDeferBeginMainFrame(true);
state.SetNeedsBeginMainFrame();
EXPECT_FALSE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetDeferBeginMainFrame(false);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest, EarlyOutCommitWantsProactiveBeginFrame) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
EXPECT_FALSE(state.ProactiveBeginFrameWanted());
bool commit_has_no_updates = true;
state.WillCommit(commit_has_no_updates);
EXPECT_TRUE(state.ProactiveBeginFrameWanted());
state.IssueNextBeginImplFrame();
EXPECT_FALSE(state.ProactiveBeginFrameWanted());
}
TEST(SchedulerStateMachineTest,
NoLayerTreeFrameSinkCreationWhileCommitPending) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
PerformAction(&state, SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.DidLoseLayerTreeFrameSink();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
state.OnBeginImplFrameIdle();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.BeginMainFrameAborted(CommitEarlyOutReason::kAbortedDeferredCommit);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
}
TEST(SchedulerStateMachineTest, NoImplSideInvalidationsWhileInvisible) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
state.SetVisible(false);
bool needs_first_draw_on_activation = true;
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest,
NoImplSideInvalidationsWhenBeginFrameSourcePaused) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
state.SetBeginFrameSourcePaused(true);
bool needs_first_draw_on_activation = true;
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest,
ImplSideInvalidationAndMainFrame_NoMainFrameRequest) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
bool needs_first_draw_on_activation = true;
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION);
}
TEST(SchedulerStateMachineTest,
ImplSideInvalidationAndMainFrame_MainFrameRequest_FastMainThread) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
bool needs_first_draw_on_activation = true;
state.set_should_defer_invalidation_for_fast_main_frame(true);
state.SetNeedsBeginMainFrame();
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest,
ImplSideInvalidationAndMainFrame_LastFrameCommit) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
bool needs_first_draw_on_activation = true;
state.set_should_defer_invalidation_for_fast_main_frame(true);
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest,
ImplSideInvalidationAndMainFrame_LastFrameAborted) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.BeginMainFrameAborted(CommitEarlyOutReason::kFinishedNoUpdates);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
bool needs_first_draw_on_activation = true;
state.set_should_defer_invalidation_for_fast_main_frame(true);
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION);
}
TEST(SchedulerStateMachineTest,
ImplSideInvalidationAndMainFrame_MainFrameRequest_SlowMainThread) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
bool needs_first_draw_on_activation = true;
state.set_should_defer_invalidation_for_fast_main_frame(false);
state.SetNeedsBeginMainFrame();
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION);
}
TEST(SchedulerStateMachineTest, NoImplSideInvalidationUntilFrameSinkActive) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
state.set_should_defer_invalidation_for_fast_main_frame(false);
state.DidLoseLayerTreeFrameSink();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
state.DidCreateAndInitializeLayerTreeFrameSink();
state.SetNeedsBeginMainFrame();
bool needs_first_draw_on_activation = true;
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.OnBeginImplFrameDeadline();
state.OnBeginImplFrameIdle();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.OnBeginImplFrameIdle();
state.SetNeedsBeginMainFrame();
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION);
}
TEST(SchedulerStateMachineTest, ImplSideInvalidationWhenPendingTreeExists) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
bool needs_first_draw_on_activation = true;
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.set_should_defer_invalidation_for_fast_main_frame(false);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION);
}
TEST(SchedulerStateMachineTest, ImplSideInvalidationWhileReadyToCommit) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
state.set_should_defer_invalidation_for_fast_main_frame(false);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToCommit();
bool needs_first_draw_on_activation = true;
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
EXPECT_TRUE(state.needs_impl_side_invalidation());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_FALSE(state.needs_impl_side_invalidation());
}
TEST(SchedulerStateMachineTest,
ConsecutiveImplSideInvalidationsWaitForBeginFrame) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
bool needs_first_draw_on_activation = true;
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.IssueNextBeginImplFrame();
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.IssueNextBeginImplFrame();
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION);
}
TEST(SchedulerStateMachineTest, ImplSideInvalidationsThrottledOnDraw) {
SchedulerSettings settings;
settings.commit_to_active_tree = true;
StateMachine state(settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
state.NotifyReadyToDraw();
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
bool needs_first_draw_on_activation = true;
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.IssueNextBeginImplFrame();
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidReceiveCompositorFrameAck();
state.IssueNextBeginImplFrame();
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION);
}
TEST(SchedulerStateMachineTest, PrepareTilesWaitForImplSideInvalidation) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
bool needs_first_draw_on_activation = true;
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.SetNeedsPrepareTiles();
state.IssueNextBeginImplFrame();
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION);
state.DidPrepareTiles();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
TEST(SchedulerStateMachineTest, TestFullPipelineMode) {
SchedulerSettings scheduler_settings;
scheduler_settings.wait_for_all_pipeline_stages_before_draw = true;
StateMachine state(scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.SetCanDraw(false);
uint64_t sequence_number = 10;
state.IssueBeginImplFrame(sequence_number);
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::BLOCKED,
state.CurrentBeginImplFrameDeadlineMode());
state.SetDeferBeginMainFrame(true);
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::IMMEDIATE,
state.CurrentBeginImplFrameDeadlineMode());
state.SetDeferBeginMainFrame(false);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::SENT);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::BLOCKED,
state.CurrentBeginImplFrameDeadlineMode());
state.NotifyReadyToCommit();
EXPECT_MAIN_FRAME_STATE(
SchedulerStateMachine::BeginMainFrameState::READY_TO_COMMIT);
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::BLOCKED,
state.CurrentBeginImplFrameDeadlineMode());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::BLOCKED,
state.CurrentBeginImplFrameDeadlineMode());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_FALSE(state.ShouldPrepareTiles());
state.SetNeedsPrepareTiles();
EXPECT_TRUE(state.ShouldPrepareTiles());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::PREPARE_TILES);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::IMMEDIATE,
state.CurrentBeginImplFrameDeadlineMode());
state.SetCanDraw(true);
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::BLOCKED,
state.CurrentBeginImplFrameDeadlineMode());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToDraw();
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::IMMEDIATE,
state.CurrentBeginImplFrameDeadlineMode());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsRedraw(true);
sequence_number++;
state.IssueBeginImplFrame(sequence_number);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::IMMEDIATE,
state.CurrentBeginImplFrameDeadlineMode());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidSubmitCompositorFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsRedraw(true);
state.SetNeedsBeginMainFrame();
sequence_number++;
state.IssueBeginImplFrame(sequence_number);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::BLOCKED,
state.CurrentBeginImplFrameDeadlineMode());
state.SetTreePrioritiesAndScrollState(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER, false);
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::BLOCKED,
state.CurrentBeginImplFrameDeadlineMode());
state.BeginMainFrameAborted(CommitEarlyOutReason::kFinishedNoUpdates);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BeginMainFrameState::IDLE);
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::IMMEDIATE,
state.CurrentBeginImplFrameDeadlineMode());
}
TEST(SchedulerStateMachineTest, AllowSkippingActiveTreeFirstDraws) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
bool needs_first_draw_on_activation = false;
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
uint64_t sequence_number = 1;
state.IssueBeginImplFrame(sequence_number);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
state.OnBeginImplFrameIdle();
state.SetNeedsBeginMainFrame();
sequence_number++;
state.IssueBeginImplFrame(sequence_number);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
}
TEST(SchedulerStateMachineTest, DelayDrawIfAnimationWorkletsPending) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
uint64_t sequence_number = 10;
state.IssueBeginImplFrame(sequence_number);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::IMMEDIATE,
state.CurrentBeginImplFrameDeadlineMode());
state.NotifyAnimationWorkletStateChange(
SchedulerStateMachine::AnimationWorkletState::PROCESSING,
SchedulerStateMachine::TreeType::ACTIVE);
EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::REGULAR,
state.CurrentBeginImplFrameDeadlineMode());
state.NotifyAnimationWorkletStateChange(
SchedulerStateMachine::AnimationWorkletState::PROCESSING,
SchedulerStateMachine::TreeType::ACTIVE);
EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::REGULAR,
state.CurrentBeginImplFrameDeadlineMode());
state.NotifyAnimationWorkletStateChange(
SchedulerStateMachine::AnimationWorkletState::IDLE,
SchedulerStateMachine::TreeType::ACTIVE);
EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::REGULAR,
state.CurrentBeginImplFrameDeadlineMode());
state.NotifyAnimationWorkletStateChange(
SchedulerStateMachine::AnimationWorkletState::IDLE,
SchedulerStateMachine::TreeType::ACTIVE);
EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::IMMEDIATE,
state.CurrentBeginImplFrameDeadlineMode());
state.SetNeedsRedraw(true);
state.OnBeginImplFrameDeadline();
EXPECT_IMPL_FRAME_STATE(
SchedulerStateMachine::BeginImplFrameState::INSIDE_DEADLINE);
EXPECT_TRUE(state.ShouldDraw());
state.NotifyAnimationWorkletStateChange(
SchedulerStateMachine::AnimationWorkletState::PROCESSING,
SchedulerStateMachine::TreeType::ACTIVE);
EXPECT_TRUE(state.ShouldDraw());
state.NotifyAnimationWorkletStateChange(
SchedulerStateMachine::AnimationWorkletState::IDLE,
SchedulerStateMachine::TreeType::ACTIVE);
EXPECT_TRUE(state.ShouldDraw());
}
TEST(SchedulerStateMachineTest, BlockActivationIfAnimationWorkletsPending) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.NotifyAnimationWorkletStateChange(
SchedulerStateMachine::AnimationWorkletState::PROCESSING,
SchedulerStateMachine::TreeType::PENDING);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyAnimationWorkletStateChange(
SchedulerStateMachine::AnimationWorkletState::IDLE,
SchedulerStateMachine::TreeType::PENDING);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
}
TEST(SchedulerStateMachineTest, BlockActivationIfPaintWorkletsPending) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyPaintWorkletStateChange(
SchedulerStateMachine::PaintWorkletState::PROCESSING);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyPaintWorkletStateChange(
SchedulerStateMachine::PaintWorkletState::IDLE);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
}
TEST(SchedulerStateMachineTest,
BlockActivationIfPaintWorkletsPendingEvenWhenAbortingFrame) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyPaintWorkletStateChange(
SchedulerStateMachine::PaintWorkletState::PROCESSING);
state.SetVisible(false);
ASSERT_TRUE(state.ShouldAbortCurrentFrame());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyPaintWorkletStateChange(
SchedulerStateMachine::PaintWorkletState::IDLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
}
TEST(SchedulerStateMachineTest, TestFullPipelineModeDoesntBlockAfterCommit) {
SchedulerSettings settings;
settings.wait_for_all_pipeline_stages_before_draw = true;
StateMachine state(settings);
SET_UP_STATE(state);
const bool needs_first_draw_on_activation = true;
state.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
state.SetNeedsBeginMainFrame();
state.SetNeedsRedraw(true);
uint64_t sequence_number = 10;
state.IssueBeginImplFrame(sequence_number);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
state.NotifyReadyToDraw();
EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_IMPL_FRAME_STATE(
SchedulerStateMachine::BeginImplFrameState::INSIDE_BEGIN_FRAME);
EXPECT_FALSE(state.ShouldDraw());
state.SetNeedsBeginMainFrame();
sequence_number++;
state.IssueBeginImplFrame(sequence_number);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.OnBeginImplFrameDeadline();
EXPECT_TRUE(state.ShouldDraw());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
}
TEST(SchedulerStateMachineTest,
PauseRenderingSuppressesCommitsAndInvalidations) {
SchedulerSettings settings;
StateMachine state(settings);
SET_UP_STATE(state);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
state.SetPauseRendering(true);
state.OnBeginImplFrameDeadline();
EXPECT_TRUE(state.ShouldSubscribeToBeginFrames());
EXPECT_TRUE(state.BeginFrameNeeded());
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::POST_COMMIT);
state.OnBeginImplFrameDeadline();
EXPECT_TRUE(state.ShouldSubscribeToBeginFrames());
EXPECT_TRUE(state.BeginFrameNeeded());
state.NotifyReadyToActivate();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE);
EXPECT_TRUE(state.ShouldSubscribeToBeginFrames());
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.OnBeginImplFrameDeadline();
state.SetNeedsImplSideInvalidation(true);
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_TRUE(state.ShouldSubscribeToBeginFrames());
EXPECT_FALSE(state.BeginFrameNeeded());
state.SetPauseRendering(false);
EXPECT_TRUE(state.ShouldSubscribeToBeginFrames());
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
state.set_should_defer_invalidation_for_fast_main_frame(false);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION);
}
class DisableFrameRateLimitSchedulerStateMachineTests
: public testing::Test,
public testing::WithParamInterface<std::tuple<bool, bool>> {
public:
DisableFrameRateLimitSchedulerStateMachineTests();
~DisableFrameRateLimitSchedulerStateMachineTests() override = default;
SchedulerSettings GetSchedulerSettings() {
SchedulerSettings settings;
settings.disable_frame_rate_limit = std::get<0>(GetParam());
return settings;
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
DisableFrameRateLimitSchedulerStateMachineTests::
DisableFrameRateLimitSchedulerStateMachineTests() {
if (std::get<1>(GetParam())) {
scoped_feature_list_.InitAndEnableFeature(features::kNoCompositorFrameAcks);
} else {
scoped_feature_list_.InitAndDisableFeature(
features::kNoCompositorFrameAcks);
}
}
TEST_P(DisableFrameRateLimitSchedulerStateMachineTests,
TestImplLatencyTakesPriority) {
SchedulerSettings default_scheduler_settings = GetSchedulerSettings();
StateMachine state(default_scheduler_settings);
SET_UP_STATE(state);
state.SetNeedsRedraw(true);
state.SetNeedsBeginMainFrame();
state.IssueNextBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.SetTreePrioritiesAndScrollState(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER, false);
EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE);
state.DidSubmitCompositorFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
if (!base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
state.DidReceiveCompositorFrameAck();
}
state.SetNeedsBeginMainFrame();
FinishPreviousCommitAndDrawWithoutExitingDeadline(&state);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
if (!base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
state.DidReceiveCompositorFrameAck();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
FinishPreviousCommitAndDrawWithoutExitingDeadline(&state);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.SetNeedsBeginMainFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.IssueNextBeginImplFrame();
if (default_scheduler_settings.disable_frame_rate_limit ||
base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME);
} else {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
INSTANTIATE_TEST_SUITE_P(DisableFrameRateLimitSchedulerStateMachineTests,
DisableFrameRateLimitSchedulerStateMachineTests,
testing::Combine(testing::Bool(), testing::Bool()),
[](auto& info) {
return base::StringPrintf(
"%s_%s",
std::get<0>(info.param) ? "DisableFrameRateLimit"
: "FrameRateLimit",
std::get<1>(info.param) ? "NoCompositorFrameAck"
: "CompositorFrameAck");
});
class ScrollingSchedulerStateMachineTest
: public DisableFrameRateLimitSchedulerStateMachineTests {
public:
ScrollingSchedulerStateMachineTest();
~ScrollingSchedulerStateMachineTest() override = default;
void BeginImplFrameWaitingForScrollEvent();
void SetUp() override;
protected:
SchedulerSettings InitScrollDeadlineMode();
SchedulerSettings scheduler_settings_;
public:
StateMachine state;
};
ScrollingSchedulerStateMachineTest::ScrollingSchedulerStateMachineTest()
: state(InitScrollDeadlineMode()) {}
void ScrollingSchedulerStateMachineTest::BeginImplFrameWaitingForScrollEvent() {
state.IssueNextBeginImplFrame();
state.set_waiting_for_scroll_event(true);
}
SchedulerSettings ScrollingSchedulerStateMachineTest::InitScrollDeadlineMode() {
scheduler_settings_ =
DisableFrameRateLimitSchedulerStateMachineTests::GetSchedulerSettings();
scheduler_settings_.scroll_deadline_mode_enabled = true;
return scheduler_settings_;
}
void ScrollingSchedulerStateMachineTest::SetUp() {
DisableFrameRateLimitSchedulerStateMachineTests::SetUp();
SET_UP_STATE(state);
state.set_is_scrolling(true);
state.SetTreePrioritiesAndScrollState(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER, false);
}
TEST_P(ScrollingSchedulerStateMachineTest, ScrollModeBlocksBeginMainFrame) {
state.SetNeedsBeginMainFrame();
BeginImplFrameWaitingForScrollEvent();
EXPECT_TRUE(state.ShouldWaitForScrollEvent());
EXPECT_FALSE(state.ShouldSendBeginMainFrame());
state.set_waiting_for_scroll_event(false);
EXPECT_FALSE(state.ShouldWaitForScrollEvent());
EXPECT_TRUE(state.ShouldSendBeginMainFrame());
BeginImplFrameWaitingForScrollEvent();
EXPECT_TRUE(state.ShouldWaitForScrollEvent());
EXPECT_FALSE(state.ShouldSendBeginMainFrame());
state.OnBeginImplFrameDeadline();
EXPECT_FALSE(state.ShouldWaitForScrollEvent());
EXPECT_TRUE(state.ShouldSendBeginMainFrame());
}
TEST_P(ScrollingSchedulerStateMachineTest, ScrollModeBlockedByNoImmediateMode) {
state.DidSubmitCompositorFrame();
state.SetNeedsRedraw(true);
BeginImplFrameWaitingForScrollEvent();
if (scheduler_settings_.disable_frame_rate_limit ||
base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
} else {
EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
}
EXPECT_TRUE(state.ShouldWaitForScrollEvent());
if (scheduler_settings_.disable_frame_rate_limit ||
base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
EXPECT_EQ(
SchedulerStateMachine::BeginImplFrameDeadlineMode::WAIT_FOR_SCROLL,
state.CurrentBeginImplFrameDeadlineMode());
} else {
EXPECT_NE(
SchedulerStateMachine::BeginImplFrameDeadlineMode::WAIT_FOR_SCROLL,
state.CurrentBeginImplFrameDeadlineMode());
}
if (!base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
state.DidReceiveCompositorFrameAck();
}
EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
EXPECT_TRUE(state.ShouldWaitForScrollEvent());
EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::WAIT_FOR_SCROLL,
state.CurrentBeginImplFrameDeadlineMode());
}
INSTANTIATE_TEST_SUITE_P(ScrollingSchedulerStateMachineTest,
ScrollingSchedulerStateMachineTest,
testing::Combine(testing::Bool(), testing::Bool()),
[](auto& info) {
return base::StringPrintf(
"%s_%s",
std::get<0>(info.param) ? "DisableFrameRateLimit"
: "FrameRateLimit",
std::get<1>(info.param) ? "NoCompositorFrameAck"
: "CompositorFrameAck");
});
TEST(SchedulerStateMachineTest,
SetShouldWarmUpWillStartLayerTreeFrameSinkCreation) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetVisible(false);
state.SetShouldWarmUp();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
state.DidCreateAndInitializeLayerTreeFrameSink();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::NONE);
}
}
}