#include "cc/scheduler/scheduler.h"
#include <stddef.h>
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>
#include "base/auto_reset.h"
#include "base/check_op.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/time/time.h"
#include "base/time/time_override.h"
#include "base/trace_event/trace_event.h"
#include "cc/base/features.h"
#include "cc/metrics/begin_main_frame_metrics.h"
#include "cc/metrics/event_metrics.h"
#include "cc/metrics/frame_sequence_tracker_collection.h"
#include "cc/scheduler/scheduler_state_machine.h"
#include "cc/test/fake_compositor_frame_reporting_controller.h"
#include "cc/test/scheduler_test_common.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 "components/viz/test/fake_delay_based_time_source.h"
#include "components/viz/test/fake_external_begin_frame_source.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#define EXPECT_ACTIONS(...) \
EXPECT_THAT(client_->Actions(), ::testing::ElementsAre(__VA_ARGS__))
#define EXPECT_NO_ACTION() EXPECT_THAT(client_->Actions(), ::testing::IsEmpty())
#define EXPECT_SCOPED(statements) \
{ \
SCOPED_TRACE(""); \
statements; \
}
namespace cc {
namespace {
using testing::Bool;
using testing::Combine;
base::TimeDelta kSlowDuration = base::Seconds(1);
base::TimeDelta kFastDuration = base::Milliseconds(1);
class FakeSchedulerClient : public SchedulerClient,
public viz::FakeExternalBeginFrameSource::Client {
public:
FakeSchedulerClient() { Reset(); }
void Reset() {
actions_.clear();
will_begin_impl_frame_causes_redraw_ = false;
will_begin_impl_frame_requests_one_begin_impl_frame_ = false;
invalidate_needs_redraw_ = true;
draw_will_happen_ = true;
swap_will_happen_if_draw_happens_ = true;
num_draws_ = 0;
last_begin_main_frame_args_ = viz::BeginFrameArgs();
last_begin_frame_ack_ = viz::BeginFrameAck();
last_frame_skipped_reason_.reset();
}
void set_scheduler(TestScheduler* scheduler) { scheduler_ = scheduler; }
bool needs_begin_frames() { return scheduler_->begin_frames_expected(); }
int num_draws() const { return num_draws_; }
bool invalidate_needs_redraw() const { return invalidate_needs_redraw_; }
const std::vector<std::string>& Actions() const { return actions_; }
base::TimeTicks posted_begin_impl_frame_deadline() const {
return posted_begin_impl_frame_deadline_;
}
base::TimeDelta frame_interval() const { return frame_interval_; }
int ActionIndex(std::string_view action) const {
for (size_t i = 0; i < actions_.size(); i++)
if (actions_[i] == action) {
return base::checked_cast<int>(i);
}
return -1;
}
bool HasAction(std::string_view action) const {
return ActionIndex(action) >= 0;
}
void SetWillBeginImplFrameRequestsOneBeginImplFrame(bool request) {
will_begin_impl_frame_requests_one_begin_impl_frame_ = request;
}
void SetWillBeginImplFrameCausesRedraw(bool causes_redraw) {
will_begin_impl_frame_causes_redraw_ = causes_redraw;
}
void SetInvalidateNeedsRedraw(bool needs_redraw) {
invalidate_needs_redraw_ = needs_redraw;
}
void SetDrawWillHappen(bool draw_will_happen) {
draw_will_happen_ = draw_will_happen;
}
void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens) {
swap_will_happen_if_draw_happens_ = swap_will_happen_if_draw_happens;
}
void SetAutomaticSubmitCompositorFrameAck(bool automatic_ack) {
automatic_ack_ = automatic_ack;
}
void SetWillBeginImplFrameMightHaveDamage(bool might_have_damage) {
will_begin_impl_frame_might_have_damage_ = might_have_damage;
}
bool WillBeginImplFrame(const viz::BeginFrameArgs& args) override {
EXPECT_FALSE(inside_begin_impl_frame_);
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
inside_begin_impl_frame_ = true;
PushAction("WillBeginImplFrame");
if (will_begin_impl_frame_requests_one_begin_impl_frame_)
scheduler_->SetNeedsOneBeginImplFrame();
if (will_begin_impl_frame_causes_redraw_)
scheduler_->SetNeedsRedraw();
return will_begin_impl_frame_might_have_damage_;
}
void DidFinishImplFrame(
const viz::BeginFrameArgs& last_activated_args) override {
EXPECT_TRUE(inside_begin_impl_frame_);
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
inside_begin_impl_frame_ = false;
}
void DidNotProduceFrame(const viz::BeginFrameAck& ack,
FrameSkippedReason reason) override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
last_begin_frame_ack_ = ack;
last_frame_skipped_reason_ = reason;
}
void WillNotReceiveBeginFrame() override {}
void ScheduledActionSendBeginMainFrame(
const viz::BeginFrameArgs& args) override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
PushAction("ScheduledActionSendBeginMainFrame");
last_begin_main_frame_args_ = args;
}
void FrameIntervalUpdated(base::TimeDelta interval) override {
frame_interval_ = interval;
}
void OnBeginImplFrameDeadline() override {}
void DidChangeBeginFrameSourcePaused(bool paused) override {}
const viz::BeginFrameArgs& last_begin_main_frame_args() {
return last_begin_main_frame_args_;
}
const viz::BeginFrameAck& last_begin_frame_ack() {
return last_begin_frame_ack_;
}
FrameSkippedReason last_frame_skipped_reason() const {
return last_frame_skipped_reason_.value();
}
DrawResult ScheduledActionDrawIfPossible() override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
PushAction("ScheduledActionDrawIfPossible");
num_draws_++;
if (!draw_will_happen_)
return DrawResult::kAbortedCheckerboardAnimations;
if (swap_will_happen_if_draw_happens_) {
last_begin_frame_ack_ = scheduler_->CurrentBeginFrameAckForActiveTree();
SubmitInfo submit_info;
scheduler_->DidSubmitCompositorFrame(submit_info);
if (automatic_ack_ &&
!base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
scheduler_->DidReceiveCompositorFrameAck();
}
}
return DrawResult::kSuccess;
}
DrawResult ScheduledActionDrawForced() override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
PushAction("ScheduledActionDrawForced");
last_begin_frame_ack_ = scheduler_->CurrentBeginFrameAckForActiveTree();
return DrawResult::kSuccess;
}
void ScheduledActionCommit() override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
PushAction("ScheduledActionCommit");
}
void ScheduledActionPostCommit() override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
PushAction("ScheduledActionPostCommit");
}
void ScheduledActionActivateSyncTree() override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
PushAction("ScheduledActionActivateSyncTree");
}
void ScheduledActionBeginLayerTreeFrameSinkCreation() override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
PushAction("ScheduledActionBeginLayerTreeFrameSinkCreation");
}
void ScheduledActionPrepareTiles() override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
PushAction("ScheduledActionPrepareTiles");
scheduler_->DidPrepareTiles();
}
void ScheduledActionInvalidateLayerTreeFrameSink(bool needs_redraw) override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
invalidate_needs_redraw_ = needs_redraw;
actions_.push_back("ScheduledActionInvalidateLayerTreeFrameSink");
}
void ScheduledActionPerformImplSideInvalidation() override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
PushAction("ScheduledActionPerformImplSideInvalidation");
}
void SendBeginMainFrameNotExpectedSoon() override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
PushAction("SendBeginMainFrameNotExpectedSoon");
}
void ScheduledActionBeginMainFrameNotExpectedUntil(
base::TimeTicks time) override {
EXPECT_FALSE(inside_action_);
base::AutoReset<bool> mark_inside(&inside_action_, true);
PushAction("ScheduledActionBeginMainFrameNotExpectedUntil");
}
bool IsInsideBeginImplFrame() const { return inside_begin_impl_frame_; }
base::RepeatingCallback<bool(void)> InsideBeginImplFrame(bool state) {
return base::BindRepeating(
&FakeSchedulerClient::InsideBeginImplFrameCallback,
base::Unretained(this), state);
}
bool IsCurrentFrame(int last_frame_number) const {
return scheduler_->current_frame_number() == last_frame_number;
}
base::RepeatingCallback<bool(void)> FrameHasNotAdvancedCallback() {
return base::BindRepeating(&FakeSchedulerClient::IsCurrentFrame,
base::Unretained(this),
scheduler_->current_frame_number());
}
void PushAction(std::string_view description) {
actions_.emplace_back(description);
}
void OnAddObserver(viz::BeginFrameObserver* obs) override {
PushAction("AddObserver(this)");
}
void OnRemoveObserver(viz::BeginFrameObserver* obs) override {
PushAction("RemoveObserver(this)");
}
protected:
bool InsideBeginImplFrameCallback(bool state) {
return inside_begin_impl_frame_ == state;
}
bool inside_action_ = false;
bool inside_begin_impl_frame_ = false;
bool will_begin_impl_frame_causes_redraw_;
bool will_begin_impl_frame_requests_one_begin_impl_frame_;
bool invalidate_needs_redraw_ = true;
bool draw_will_happen_;
bool swap_will_happen_if_draw_happens_;
bool automatic_ack_ = true;
bool will_begin_impl_frame_might_have_damage_ = true;
int num_draws_;
viz::BeginFrameArgs last_begin_main_frame_args_;
viz::BeginFrameAck last_begin_frame_ack_;
base::TimeTicks posted_begin_impl_frame_deadline_;
std::vector<std::string> actions_;
raw_ptr<TestScheduler> scheduler_ = nullptr;
base::TimeDelta frame_interval_;
std::optional<FrameSkippedReason> last_frame_skipped_reason_;
};
enum BeginFrameSourceType {
EXTERNAL_BFS,
UNTHROTTLED_BFS,
THROTTLED_BFS,
};
class SchedulerTestTaskRunner : public base::TestMockTimeTaskRunner {
public:
SchedulerTestTaskRunner()
: base::TestMockTimeTaskRunner(
base::TestMockTimeTaskRunner::Type::kStandalone) {
AdvanceMockTickClock(base::Microseconds(110000));
}
void RunUntilTime(base::TimeTicks end_time) {
FastForwardBy(end_time - NowTicks());
}
void RunPendingTasks() {
base::circular_deque<base::TestPendingTask> tasks = TakePendingTasks();
while (!tasks.empty()) {
base::TestPendingTask task = std::move(tasks.front());
tasks.pop_front();
AdvanceMockTickClock(task.GetTimeToRun() - NowTicks());
std::move(task.task).Run();
}
}
void RunTasksWhile(base::RepeatingCallback<bool()> condition) {
run_condition_ = condition;
FastForwardUntilNoTasksRemain();
run_condition_ = std::nullopt;
while (!tasks_to_requeue_.empty()) {
base::TestPendingTask task = std::move(tasks_to_requeue_.front());
tasks_to_requeue_.pop_front();
PostDelayedTask(task.location, std::move(task.task),
task.GetTimeToRun() - NowTicks());
}
}
protected:
void OnBeforeSelectingTask() override {
ASSERT_LT(++task_count_, 100u);
if (run_condition_ && HasPendingTask() && !run_condition_->Run()) {
tasks_to_requeue_ = TakePendingTasks();
}
}
private:
~SchedulerTestTaskRunner() override = default;
size_t task_count_ = 0u;
std::optional<base::RepeatingCallback<bool()>> run_condition_;
base::circular_deque<base::TestPendingTask> tasks_to_requeue_;
};
class SchedulerTest
: public testing::Test,
public testing::WithParamInterface<std::tuple<bool, bool>> {
public:
SchedulerTest()
: task_runner_(base::MakeRefCounted<SchedulerTestTaskRunner>()),
fake_external_begin_frame_source_(nullptr),
tracker_collection_(false) {
std::vector<base::test::FeatureRef> enabled;
std::vector<base::test::FeatureRef> disabled;
if (std::get<0>(GetParam())) {
enabled.push_back(features::kNoCompositorFrameAcks);
} else {
disabled.push_back(features::kNoCompositorFrameAcks);
}
if (std::get<1>(GetParam())) {
enabled.push_back(features::kThrottleMainFrameTo60Hz);
} else {
disabled.push_back(features::kThrottleMainFrameTo60Hz);
}
scoped_feature_list_.InitWithFeatures(enabled, disabled);
}
static std::string GetTestName(
testing::TestParamInfo<std::tuple<bool, bool>> info) {
std::string first =
std::get<0>(info.param) ? "NoCompositorFrameAck" : "CompositorFrameAck";
std::string second = std::get<1>(info.param) ? "Throttled" : "NotThrottled";
return first + "_" + second;
}
~SchedulerTest() override { client_->set_scheduler(nullptr); }
protected:
TestScheduler* CreateScheduler(BeginFrameSourceType bfs_type) {
viz::BeginFrameSource* frame_source = nullptr;
unthrottled_frame_source_ =
std::make_unique<viz::BackToBackBeginFrameSource>(
std::make_unique<viz::FakeDelayBasedTimeSource>(
task_runner_->GetMockTickClock(), task_runner_.get()));
fake_external_begin_frame_source_ =
std::make_unique<viz::FakeExternalBeginFrameSource>(1.0, false);
fake_external_begin_frame_source_->SetClient(client_.get());
synthetic_frame_source_ = std::make_unique<viz::DelayBasedBeginFrameSource>(
std::make_unique<viz::FakeDelayBasedTimeSource>(
task_runner_->GetMockTickClock(), task_runner_.get()),
viz::BeginFrameSource::kNotRestartableId);
switch (bfs_type) {
case EXTERNAL_BFS:
frame_source = fake_external_begin_frame_source_.get();
break;
case UNTHROTTLED_BFS:
frame_source = unthrottled_frame_source_.get();
break;
case THROTTLED_BFS:
frame_source = synthetic_frame_source_.get();
break;
}
DCHECK(frame_source);
std::unique_ptr<FakeCompositorTimingHistory>
fake_compositor_timing_history = FakeCompositorTimingHistory::Create(
scheduler_settings_.using_synchronous_renderer_compositor);
fake_compositor_timing_history_ = fake_compositor_timing_history.get();
reporting_controller =
std::make_unique<FakeCompositorFrameReportingController>();
reporting_controller->SetFrameSorter(&frame_sorter);
reporting_controller->SetFrameSequenceTrackerCollection(
&tracker_collection_);
scheduler_ = std::make_unique<TestScheduler>(
task_runner_->GetMockTickClock(), client_.get(), scheduler_settings_, 0,
task_runner_.get(), std::move(fake_compositor_timing_history),
reporting_controller.get());
client_->set_scheduler(scheduler_.get());
scheduler_->SetBeginFrameSource(frame_source);
return scheduler_.get();
}
void SetUpScheduler(BeginFrameSourceType bfs_type,
std::unique_ptr<FakeSchedulerClient> client) {
client_ = std::move(client);
CreateScheduler(bfs_type);
EXPECT_SCOPED(InitializeLayerTreeFrameSinkAndFirstCommit());
}
void SetUpScheduler(BeginFrameSourceType bfs_type) {
SetUpScheduler(bfs_type, std::make_unique<FakeSchedulerClient>());
}
void SetUpSchedulerWithNoLayerTreeFrameSink(BeginFrameSourceType bfs_type) {
client_ = std::make_unique<FakeSchedulerClient>();
CreateScheduler(bfs_type);
}
void InitializeLayerTreeFrameSinkAndFirstCommit() {
TRACE_EVENT0(
"cc", "SchedulerUnitTest::InitializeLayerTreeFrameSinkAndFirstCommit");
DCHECK(scheduler_);
EXPECT_NO_ACTION();
EXPECT_FALSE(scheduler_->begin_frames_expected());
scheduler_->SetVisible(true);
scheduler_->SetCanDraw(true);
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
client_->Reset();
scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_TRUE(scheduler_->begin_frames_expected());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
{
SCOPED_TRACE("Do first frame to commit after initialize.");
AdvanceFrame();
task_runner_->AdvanceMockTickClock(base::Milliseconds(1));
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
scheduler_->NotifyReadyToActivate();
scheduler_->NotifyReadyToDraw();
EXPECT_FALSE(scheduler_->CommitPending());
if (scheduler_settings_.using_synchronous_renderer_compositor) {
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = false;
bool skip_draw = false;
scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
skip_draw);
} else {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
}
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
}
client_->Reset();
{
SCOPED_TRACE(
"Run second frame so Scheduler calls SetNeedsBeginFrame(false).");
AdvanceFrame();
if (!scheduler_settings_.using_synchronous_renderer_compositor) {
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
}
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
}
EXPECT_FALSE(scheduler_->begin_frames_expected());
if (scheduler_->begin_frame_source() ==
fake_external_begin_frame_source_.get()) {
uint64_t last_begin_frame_number =
fake_external_begin_frame_source_->next_begin_frame_number() - 1;
bool has_damage = false;
EXPECT_EQ(
viz::BeginFrameAck(fake_external_begin_frame_source_->source_id(),
last_begin_frame_number, has_damage),
client_->last_begin_frame_ack());
}
client_->Reset();
}
void AdvanceFrame(bool animate_only = false) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
"FakeSchedulerClient::AdvanceFrame");
if (scheduler_->begin_frame_source() ==
fake_external_begin_frame_source_.get()) {
EXPECT_TRUE(scheduler_->begin_frames_expected());
if (client_->IsInsideBeginImplFrame())
task_runner_->RunPendingTasks();
SendNextBeginFrame(animate_only);
} else {
task_runner_->RunTasksWhile(client_->FrameHasNotAdvancedCallback());
}
}
viz::BeginFrameArgs SendNextBeginFrame(bool animate_only = false) {
DCHECK_EQ(scheduler_->begin_frame_source(),
fake_external_begin_frame_source_.get());
task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
viz::BeginFrameArgs args =
fake_external_begin_frame_source_->CreateBeginFrameArgs(
BEGINFRAME_FROM_HERE, task_runner_->GetMockTickClock());
args.animate_only = animate_only;
fake_external_begin_frame_source_->TestOnBeginFrame(args);
return args;
}
viz::FakeExternalBeginFrameSource* fake_external_begin_frame_source() const {
return fake_external_begin_frame_source_.get();
}
void SetShouldDeferInvalidationForMainFrame(bool defer) {
base::TimeDelta delta;
if (!defer)
delta = base::Seconds(1);
fake_compositor_timing_history_
->SetBeginMainFrameStartToReadyToCommitDurationEstimate(delta);
fake_compositor_timing_history_
->SetBeginMainFrameQueueDurationCriticalEstimate(delta);
fake_compositor_timing_history_
->SetBeginMainFrameQueueDurationNotCriticalEstimate(delta);
fake_compositor_timing_history_->SetDrawDurationEstimate(base::TimeDelta());
}
void SendTestBeginFrameAfterInterval(base::TimeDelta interval,
uint64_t source_id,
uint64_t sequence_number) {
scheduler_->SetNeedsRedraw();
task_runner_->AdvanceMockTickClock(interval);
viz::BeginFrameArgs args = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, source_id, sequence_number,
task_runner_->NowTicks(), task_runner_->NowTicks() + interval, interval,
viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_EQ(client_->frame_interval(), interval);
}
void AdvanceAndMissOneFrame();
void CheckMainFrameNotSkippedAfterLateCommit();
void ImplFrameNotSkippedAfterLateAck();
void BeginFramesNotFromClient(BeginFrameSourceType bfs_type);
void BeginFramesNotFromClient_IsDrawThrottled(BeginFrameSourceType bfs_type);
bool BeginMainFrameOnCriticalPath(TreePriority tree_priority,
ScrollHandlerState scroll_handler_state,
base::TimeDelta durations);
scoped_refptr<SchedulerTestTaskRunner> task_runner_;
std::unique_ptr<viz::FakeExternalBeginFrameSource>
fake_external_begin_frame_source_;
std::unique_ptr<viz::SyntheticBeginFrameSource> synthetic_frame_source_;
std::unique_ptr<viz::SyntheticBeginFrameSource> unthrottled_frame_source_;
SchedulerSettings scheduler_settings_;
std::unique_ptr<FakeSchedulerClient> client_;
FrameSequenceTrackerCollection tracker_collection_;
FrameSorter frame_sorter;
std::unique_ptr<CompositorFrameReportingController> reporting_controller;
std::unique_ptr<TestScheduler> scheduler_;
raw_ptr<FakeCompositorTimingHistory> fake_compositor_timing_history_;
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_P(SchedulerTest, InitializeLayerTreeFrameSinkDoesNotBeginImplFrame) {
SetUpSchedulerWithNoLayerTreeFrameSink(EXTERNAL_BFS);
scheduler_->SetVisible(true);
scheduler_->SetCanDraw(true);
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
client_->Reset();
scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
EXPECT_NO_ACTION();
}
TEST_P(SchedulerTest, Stop) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
scheduler_->Stop();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
client_->Reset();
}
TEST_P(SchedulerTest, VideoNeedsBeginFrames) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetVideoNeedsBeginFrames(true);
EXPECT_ACTIONS("AddObserver(this)");
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
client_->Reset();
scheduler_->SetVideoNeedsBeginFrames(false);
EXPECT_NO_ACTION();
client_->Reset();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_ACTIONS("RemoveObserver(this)");
EXPECT_FALSE(scheduler_->begin_frames_expected());
}
TEST_P(SchedulerTest, RequestCommit) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_NO_ACTION();
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("RemoveObserver(this)");
client_->Reset();
}
TEST_P(SchedulerTest, RequestCommitAfterSetDeferBeginMainFrame) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetDeferBeginMainFrame(true);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_NO_ACTION();
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_NO_ACTION();
EXPECT_FALSE(scheduler_->begin_frames_expected());
client_->Reset();
scheduler_->SetDeferBeginMainFrame(false);
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
}
TEST_P(SchedulerTest, DeferBeginMainFrameWithRedraw) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetDeferBeginMainFrame(true);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_NO_ACTION();
client_->Reset();
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
AdvanceFrame();
EXPECT_ACTIONS("WillBeginImplFrame");
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
AdvanceFrame();
EXPECT_ACTIONS("WillBeginImplFrame");
}
TEST_P(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_NO_ACTION();
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_FALSE(scheduler_->begin_frames_expected());
client_->Reset();
}
class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
public:
SchedulerClientThatsetNeedsDrawInsideDraw()
: FakeSchedulerClient(), request_redraws_(false) {}
void SetRequestRedrawsInsideDraw(bool enable) { request_redraws_ = enable; }
DrawResult ScheduledActionDrawIfPossible() override {
if (request_redraws_) {
scheduler_->SetNeedsRedraw();
}
return FakeSchedulerClient::ScheduledActionDrawIfPossible();
}
DrawResult ScheduledActionDrawForced() override { NOTREACHED(); }
private:
bool request_redraws_;
};
TEST_P(SchedulerTest, RequestRedrawInsideDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw* client =
new SchedulerClientThatsetNeedsDrawInsideDraw;
SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
client->SetRequestRedrawsInsideDraw(true);
scheduler_->SetNeedsRedraw();
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
EXPECT_EQ(0, client->num_draws());
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(1, client->num_draws());
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
client->SetRequestRedrawsInsideDraw(false);
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(2, client_->num_draws());
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(2, client->num_draws());
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_FALSE(client->needs_begin_frames());
}
TEST_P(SchedulerTest, RequestRedrawInsideFailedDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw* client =
new SchedulerClientThatsetNeedsDrawInsideDraw;
SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
client->SetRequestRedrawsInsideDraw(true);
client->SetDrawWillHappen(false);
scheduler_->SetNeedsRedraw();
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
EXPECT_EQ(0, client->num_draws());
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(1, client->num_draws());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
client->SetRequestRedrawsInsideDraw(false);
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(2, client->num_draws());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
client->SetDrawWillHappen(true);
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(3, client->num_draws());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
}
class SchedulerClientThatSetNeedsBeginMainFrameInsideDraw
: public FakeSchedulerClient {
public:
SchedulerClientThatSetNeedsBeginMainFrameInsideDraw()
: set_needs_commit_on_next_draw_(false) {}
DrawResult ScheduledActionDrawIfPossible() override {
if (set_needs_commit_on_next_draw_) {
scheduler_->SetNeedsBeginMainFrame();
set_needs_commit_on_next_draw_ = false;
}
return FakeSchedulerClient::ScheduledActionDrawIfPossible();
}
DrawResult ScheduledActionDrawForced() override { NOTREACHED(); }
void SetNeedsBeginMainFrameOnNextDraw() {
set_needs_commit_on_next_draw_ = true;
}
private:
bool set_needs_commit_on_next_draw_;
};
TEST_P(SchedulerTest, RequestCommitInsideDraw) {
SchedulerClientThatSetNeedsBeginMainFrameInsideDraw* client =
new SchedulerClientThatSetNeedsBeginMainFrameInsideDraw;
SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
EXPECT_FALSE(client->needs_begin_frames());
scheduler_->SetNeedsRedraw();
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_EQ(0, client->num_draws());
EXPECT_TRUE(client->needs_begin_frames());
client->SetNeedsBeginMainFrameOnNextDraw();
EXPECT_SCOPED(AdvanceFrame());
client->SetNeedsBeginMainFrameOnNextDraw();
task_runner_->RunPendingTasks();
EXPECT_EQ(1, client->num_draws());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_TRUE(client->needs_begin_frames());
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
scheduler_->NotifyReadyToActivate();
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(2, client->num_draws());
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_FALSE(scheduler_->CommitPending());
EXPECT_TRUE(client->needs_begin_frames());
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(2, client->num_draws());
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_FALSE(scheduler_->CommitPending());
EXPECT_FALSE(client->needs_begin_frames());
}
TEST_P(SchedulerTest, RequestCommitInsideFailedDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw* client =
new SchedulerClientThatsetNeedsDrawInsideDraw;
SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
client->SetDrawWillHappen(false);
scheduler_->SetNeedsRedraw();
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
EXPECT_EQ(0, client->num_draws());
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(1, client->num_draws());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(2, client->num_draws());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
client->SetDrawWillHappen(true);
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(3, client->num_draws());
EXPECT_TRUE(scheduler_->CommitPending());
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
}
TEST_P(SchedulerTest, NoSwapWhenDrawFails) {
SchedulerClientThatSetNeedsBeginMainFrameInsideDraw* client =
new SchedulerClientThatSetNeedsBeginMainFrameInsideDraw;
SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
scheduler_->SetNeedsRedraw();
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
EXPECT_EQ(0, client->num_draws());
client->SetNeedsBeginMainFrameOnNextDraw();
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(1, client->num_draws());
scheduler_->SetNeedsRedraw();
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_TRUE(client->needs_begin_frames());
client->SetDrawWillHappen(false);
client->SetNeedsBeginMainFrameOnNextDraw();
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(2, client->num_draws());
}
class SchedulerClientNeedsPrepareTilesInDraw : public FakeSchedulerClient {
public:
DrawResult ScheduledActionDrawIfPossible() override {
scheduler_->SetNeedsPrepareTiles();
return FakeSchedulerClient::ScheduledActionDrawIfPossible();
}
};
TEST_P(SchedulerTest, PrepareTiles) {
SchedulerClientNeedsPrepareTilesInDraw* client =
new SchedulerClientNeedsPrepareTilesInDraw;
SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
client->Reset();
scheduler_->SetNeedsPrepareTiles();
scheduler_->SetNeedsRedraw();
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_TRUE(scheduler_->PrepareTilesPending());
EXPECT_TRUE(client->needs_begin_frames());
EXPECT_EQ(0, client->num_draws());
EXPECT_FALSE(client->HasAction("ScheduledActionPrepareTiles"));
EXPECT_FALSE(client->HasAction("ScheduledActionDrawIfPossible"));
client->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client->Reset();
task_runner_->RunPendingTasks();
EXPECT_EQ(1, client->num_draws());
EXPECT_TRUE(client->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
EXPECT_LT(client->ActionIndex("ScheduledActionDrawIfPossible"),
client->ActionIndex("ScheduledActionPrepareTiles"));
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client->Reset();
scheduler_->SetNeedsRedraw();
EXPECT_TRUE(scheduler_->RedrawPending());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
EXPECT_TRUE(client->needs_begin_frames());
EXPECT_EQ(0, client->num_draws());
client->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client->Reset();
task_runner_->RunPendingTasks();
EXPECT_EQ(1, client->num_draws());
EXPECT_TRUE(client->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
EXPECT_LT(client->ActionIndex("ScheduledActionDrawIfPossible"),
client->ActionIndex("ScheduledActionPrepareTiles"));
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("RemoveObserver(this)");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_EQ(0, client->num_draws());
client->Reset();
EXPECT_FALSE(client->needs_begin_frames());
scheduler_->SetNeedsPrepareTiles();
EXPECT_TRUE(client->needs_begin_frames());
EXPECT_TRUE(scheduler_->PrepareTilesPending());
EXPECT_FALSE(scheduler_->RedrawPending());
client->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client->Reset();
task_runner_->RunPendingTasks();
EXPECT_EQ(0, client->num_draws());
EXPECT_FALSE(client->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
}
TEST_P(SchedulerTest, PrepareTilesOncePerFrame) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsPrepareTiles();
scheduler_->SetNeedsRedraw();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->PrepareTilesPending());
scheduler_->DidPrepareTiles();
EXPECT_FALSE(scheduler_->PrepareTilesPending());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_EQ(1, client_->num_draws());
EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
scheduler_->SetNeedsPrepareTiles();
scheduler_->SetNeedsRedraw();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_EQ(1, client_->num_draws());
EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_TRUE(client_->HasAction("ScheduledActionPrepareTiles"));
EXPECT_LT(client_->ActionIndex("ScheduledActionDrawIfPossible"),
client_->ActionIndex("ScheduledActionPrepareTiles"));
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
scheduler_->DidPrepareTiles();
scheduler_->SetNeedsPrepareTiles();
scheduler_->SetNeedsRedraw();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->PrepareTilesPending());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_EQ(1, client_->num_draws());
EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->PrepareTilesPending());
scheduler_->DidPrepareTiles();
EXPECT_FALSE(scheduler_->PrepareTilesPending());
scheduler_->SetNeedsPrepareTiles();
scheduler_->SetNeedsRedraw();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->PrepareTilesPending());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_EQ(1, client_->num_draws());
EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
scheduler_->SetNeedsPrepareTiles();
scheduler_->SetNeedsRedraw();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_EQ(1, client_->num_draws());
EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
EXPECT_TRUE(client_->HasAction("ScheduledActionPrepareTiles"));
EXPECT_LT(client_->ActionIndex("ScheduledActionDrawIfPossible"),
client_->ActionIndex("ScheduledActionPrepareTiles"));
EXPECT_FALSE(scheduler_->RedrawPending());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
}
TEST_P(SchedulerTest, DidPrepareTilesPreventsPrepareTilesForOneFrame) {
std::unique_ptr<SchedulerClientNeedsPrepareTilesInDraw> client =
base::WrapUnique(new SchedulerClientNeedsPrepareTilesInDraw);
SetUpScheduler(EXTERNAL_BFS, std::move(client));
client_->Reset();
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
"ScheduledActionPrepareTiles");
for (int i = 0; i < 10; i++) {
scheduler_->DidPrepareTiles();
}
client_->Reset();
scheduler_->SetNeedsRedraw();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
client_->Reset();
scheduler_->SetNeedsRedraw();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
"ScheduledActionPrepareTiles");
}
TEST_P(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
SchedulerClientNeedsPrepareTilesInDraw* client =
new SchedulerClientNeedsPrepareTilesInDraw;
SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
scheduler_->SetNeedsRedraw();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_EQ(base::TimeTicks(), client->posted_begin_impl_frame_deadline());
}
TEST_P(SchedulerTest, WaitForReadyToDrawDoNotPostDeadline) {
SchedulerClientNeedsPrepareTilesInDraw* client =
new SchedulerClientNeedsPrepareTilesInDraw;
scheduler_settings_.commit_to_active_tree = true;
SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
client_->Reset();
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_NO_ACTION();
scheduler_->NotifyReadyToDraw();
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_EQ(1, client_->num_draws());
EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
}
TEST_P(SchedulerTest, WaitForReadyToDrawCancelledWhenLostLayerTreeFrameSink) {
SchedulerClientNeedsPrepareTilesInDraw* client =
new SchedulerClientNeedsPrepareTilesInDraw;
scheduler_settings_.commit_to_active_tree = true;
SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
client_->Reset();
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_NO_ACTION();
client_->Reset();
scheduler_->DidLoseLayerTreeFrameSink();
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
"RemoveObserver(this)");
}
void SchedulerTest::AdvanceAndMissOneFrame() {
scheduler_->SetNeedsBeginMainFrame();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_SCOPED(AdvanceFrame());
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
"ScheduledActionSendBeginMainFrame", "ScheduledActionCommit",
"ScheduledActionPostCommit",
"ScheduledActionActivateSyncTree");
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
client_->Reset();
}
void SchedulerTest::CheckMainFrameNotSkippedAfterLateCommit() {
AdvanceAndMissOneFrame();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_TRUE(client_->HasAction("WillBeginImplFrame"));
EXPECT_TRUE(client_->HasAction("ScheduledActionSendBeginMainFrame"));
}
TEST_P(SchedulerTest, MainFrameNotSkippedAfterLateBeginFrame) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
AdvanceAndMissOneFrame();
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
scheduler_->SetNeedsBeginMainFrame();
task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
viz::BeginFrameArgs args =
fake_external_begin_frame_source_->CreateBeginFrameArgs(
BEGINFRAME_FROM_HERE, task_runner_->GetMockTickClock());
task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval() *
100);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_EQ(true, scheduler_->MainThreadMissedLastDeadline());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
"ScheduledActionDrawIfPossible");
}
TEST_P(SchedulerTest, FrameIntervalUpdated) {
SetUpScheduler(EXTERNAL_BFS);
constexpr uint64_t kSourceId = viz::BeginFrameArgs::kStartingSourceId;
uint64_t sequence_number = viz::BeginFrameArgs::kStartingFrameNumber;
base::TimeDelta interval =
base::Microseconds(base::Time::kMicrosecondsPerSecond / 120.0);
scheduler_->SetNeedsRedraw();
task_runner_->AdvanceMockTickClock(interval);
viz::BeginFrameArgs args1 = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, kSourceId, sequence_number++,
task_runner_->NowTicks(), task_runner_->NowTicks() + interval, interval,
viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args1);
EXPECT_EQ(client_->frame_interval(), interval);
scheduler_->SetNeedsRedraw();
const base::TimeDelta late_delta = base::Milliseconds(4);
task_runner_->AdvanceMockTickClock(interval + late_delta);
viz::BeginFrameArgs args2 = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, kSourceId, sequence_number++, args1.deadline,
args1.deadline + interval, interval, viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args2);
EXPECT_EQ(client_->frame_interval(), interval);
interval = base::Microseconds(base::Time::kMicrosecondsPerSecond / 90.0);
scheduler_->SetNeedsRedraw();
task_runner_->AdvanceMockTickClock(args2.deadline - task_runner_->NowTicks());
viz::BeginFrameArgs args3 = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, kSourceId, sequence_number++, args2.deadline,
args2.deadline + interval, interval, viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args3);
EXPECT_EQ(client_->frame_interval(), interval);
scheduler_->SetNeedsRedraw();
task_runner_->AdvanceMockTickClock(interval);
viz::BeginFrameArgs args4 = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, kSourceId, sequence_number++, args3.deadline,
args3.deadline + interval, base::TimeDelta(),
viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args4);
EXPECT_EQ(client_->frame_interval(), interval);
}
TEST_P(SchedulerTest, BeginMainFrameThrottling) {
SetUpScheduler(EXTERNAL_BFS);
constexpr uint64_t kSourceId = viz::BeginFrameArgs::kStartingSourceId;
uint64_t sequence_number = viz::BeginFrameArgs::kStartingFrameNumber;
base::TimeDelta interval = base::Hertz(60);
scheduler_->SetNeedsRedraw();
task_runner_->AdvanceMockTickClock(interval);
viz::BeginFrameArgs args = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, kSourceId, sequence_number++,
task_runner_->NowTicks(), task_runner_->NowTicks() + interval, interval,
viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_EQ(client_->frame_interval(), interval);
EXPECT_TRUE(
scheduler_->state_machine().MainFrameThrottledInterval().is_zero());
{
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(features::kThrottleMainFrameTo60Hz);
interval = base::Hertz(240);
scheduler_->SetNeedsRedraw();
task_runner_->AdvanceMockTickClock(interval);
args = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, kSourceId, sequence_number++,
task_runner_->NowTicks(), task_runner_->NowTicks() + interval, interval,
viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_EQ(client_->frame_interval(), interval);
EXPECT_TRUE(
scheduler_->state_machine().MainFrameThrottledInterval().is_zero());
}
base::test::ScopedFeatureList feature_list{
features::kThrottleMainFrameTo60Hz};
interval = base::Hertz(120);
scheduler_->SetNeedsRedraw();
task_runner_->AdvanceMockTickClock(interval);
args = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, kSourceId, sequence_number++,
task_runner_->NowTicks(), task_runner_->NowTicks() + interval, interval,
viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_EQ(client_->frame_interval(), interval);
constexpr float kSlackFactor = .9;
EXPECT_NEAR(scheduler_->state_machine()
.MainFrameThrottledInterval()
.InMillisecondsF(),
(base::Hertz(60) * kSlackFactor).InMillisecondsF(), 1e-2);
interval = base::Hertz(90);
scheduler_->SetNeedsRedraw();
task_runner_->AdvanceMockTickClock(interval);
args = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, kSourceId, sequence_number++,
task_runner_->NowTicks(), task_runner_->NowTicks() + interval, interval,
viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_EQ(client_->frame_interval(), interval);
EXPECT_TRUE(
scheduler_->state_machine().MainFrameThrottledInterval().is_zero());
}
TEST_P(SchedulerTest, MainFrameNotSkippedAfterLateCommit) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
}
TEST_P(
SchedulerTest,
MainFrameNotSkippedAfterLateCommit_LongMainFrameQueueDurationNotCritical) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_
->SetBeginMainFrameQueueDurationNotCriticalEstimate(kSlowDuration);
EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
}
TEST_P(SchedulerTest,
MainFrameNotSkippedAfterLateCommit_LongMainFrameQueueDurationCritical) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_
->SetBeginMainFrameQueueDurationCriticalEstimate(kSlowDuration);
fake_compositor_timing_history_
->SetBeginMainFrameQueueDurationNotCriticalEstimate(kSlowDuration);
EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
}
TEST_P(SchedulerTest,
MainFrameNotSkippedAfterLateCommitInPreferImplLatencyMode) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetTreePrioritiesAndScrollState(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER, false);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
}
TEST_P(SchedulerTest,
MainFrameNotSkippedAfterLateCommit_CommitEstimateTooLong) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_
->SetBeginMainFrameStartToReadyToCommitDurationEstimate(kSlowDuration);
EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
}
TEST_P(SchedulerTest,
MainFrameNotSkippedAfterLateCommit_ReadyToActivateEstimateTooLong) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_->SetCommitToReadyToActivateDurationEstimate(
kSlowDuration);
EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
}
TEST_P(SchedulerTest,
MainFrameNotSkippedAfterLateCommit_ActivateEstimateTooLong) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_->SetActivateDurationEstimate(kSlowDuration);
EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
}
TEST_P(SchedulerTest, MainFrameNotSkippedAfterLateCommit_DrawEstimateTooLong) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_->SetDrawDurationEstimate(kSlowDuration);
EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
}
TEST_P(SchedulerTest, MainFrameNotSkippedAfterLateBeginMainFrameAbort) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
"ScheduledActionSendBeginMainFrame");
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
client_->Reset();
scheduler_->BeginMainFrameAborted(CommitEarlyOutReason::kFinishedNoUpdates);
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
scheduler_->SetNeedsBeginMainFrame();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(client_->HasAction("WillBeginImplFrame"));
EXPECT_TRUE(client_->HasAction("ScheduledActionSendBeginMainFrame"));
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
}
TEST_P(SchedulerTest, MainFrameNotSkippedAfterCanDrawChanges) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
"ScheduledActionSendBeginMainFrame");
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
client_->Reset();
scheduler_->NotifyReadyToCommit(nullptr);
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit",
"ScheduledActionActivateSyncTree");
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
scheduler_->SetCanDraw(false);
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
client_->Reset();
scheduler_->SetCanDraw(true);
EXPECT_NO_ACTION();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(client_->HasAction("WillBeginImplFrame"));
EXPECT_TRUE(client_->HasAction("ScheduledActionSendBeginMainFrame"));
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
}
TEST_P(SchedulerTest, MainFrameNotSkippedWhenNoTimingHistory) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
"ScheduledActionSendBeginMainFrame");
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
client_->Reset();
scheduler_->NotifyReadyToCommit(nullptr);
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit",
"ScheduledActionActivateSyncTree");
EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
scheduler_->ClearHistory();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
}
void SchedulerTest::ImplFrameNotSkippedAfterLateAck() {
client_->SetAutomaticSubmitCompositorFrameAck(false);
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
SendNextBeginFrame();
EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
"ScheduledActionSendBeginMainFrame");
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
scheduler_->NotifyReadyToActivate();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit",
"ScheduledActionActivateSyncTree",
"ScheduledActionDrawIfPossible");
for (int i = 0; i < 10; i++) {
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
SendNextBeginFrame();
if (base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
} else {
EXPECT_ACTIONS("WillBeginImplFrame");
}
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
client_->Reset();
if (!base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
scheduler_->DidReceiveCompositorFrameAck();
}
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
scheduler_->NotifyReadyToActivate();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
if (base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit",
"ScheduledActionActivateSyncTree",
"ScheduledActionDrawIfPossible");
} else {
EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame",
"ScheduledActionCommit", "ScheduledActionPostCommit",
"ScheduledActionActivateSyncTree",
"ScheduledActionDrawIfPossible");
}
}
}
TEST_P(SchedulerTest,
ImplFrameNotSkippedAfterLateAck_MainFrameQueueDurationCriticalTooLong) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_
->SetBeginMainFrameQueueDurationCriticalEstimate(kSlowDuration);
fake_compositor_timing_history_
->SetBeginMainFrameQueueDurationNotCriticalEstimate(kSlowDuration);
EXPECT_SCOPED(ImplFrameNotSkippedAfterLateAck());
}
TEST_P(SchedulerTest, ImplFrameNotSkippedAfterLateAck_CommitEstimateTooLong) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_
->SetBeginMainFrameStartToReadyToCommitDurationEstimate(kSlowDuration);
EXPECT_SCOPED(ImplFrameNotSkippedAfterLateAck());
}
TEST_P(SchedulerTest,
ImplFrameNotSkippedAfterLateAck_ReadyToActivateEstimateTooLong) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_->SetCommitToReadyToActivateDurationEstimate(
kSlowDuration);
EXPECT_SCOPED(ImplFrameNotSkippedAfterLateAck());
}
TEST_P(SchedulerTest, ImplFrameNotSkippedAfterLateAck_ActivateEstimateTooLong) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_->SetActivateDurationEstimate(kSlowDuration);
EXPECT_SCOPED(ImplFrameNotSkippedAfterLateAck());
}
TEST_P(SchedulerTest, ImplFrameNotSkippedAfterLateAck_DrawEstimateTooLong) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_->SetDrawDurationEstimate(kSlowDuration);
EXPECT_SCOPED(ImplFrameNotSkippedAfterLateAck());
}
void SchedulerTest::BeginFramesNotFromClient(BeginFrameSourceType bfs_type) {
SetUpScheduler(bfs_type);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_NO_ACTION();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("ScheduledActionDrawIfPossible", "WillBeginImplFrame");
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_NO_ACTION();
client_->Reset();
}
TEST_P(SchedulerTest, SyntheticBeginFrames) {
BeginFramesNotFromClient(THROTTLED_BFS);
}
TEST_P(SchedulerTest, UnthrottledBeginFrames) {
BeginFramesNotFromClient(UNTHROTTLED_BFS);
}
void SchedulerTest::BeginFramesNotFromClient_IsDrawThrottled(
BeginFrameSourceType bfs_type) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature(features::kNoCompositorFrameAcks);
SetUpScheduler(bfs_type);
fake_compositor_timing_history_->SetDrawDurationEstimate(base::TimeDelta());
client_->SetAutomaticSubmitCompositorFrameAck(false);
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_NO_ACTION();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
client_->Reset();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
scheduler_->SetNeedsRedraw();
EXPECT_SCOPED(AdvanceFrame());
if (base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
} else {
EXPECT_ACTIONS("WillBeginImplFrame");
}
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
base::TimeTicks before_deadline, after_deadline;
before_deadline = task_runner_->NowTicks();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
after_deadline = task_runner_->NowTicks();
EXPECT_GT(after_deadline, before_deadline);
EXPECT_LT(after_deadline,
before_deadline + viz::BeginFrameArgs::DefaultInterval());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
if (base::FeatureList::IsEnabled(features::kNoCompositorFrameAcks)) {
EXPECT_NO_ACTION();
} else {
scheduler_->DidReceiveCompositorFrameAck();
EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame");
}
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
before_deadline = task_runner_->NowTicks();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
after_deadline = task_runner_->NowTicks();
EXPECT_GT(after_deadline, before_deadline);
EXPECT_LT(after_deadline,
before_deadline + viz::BeginFrameArgs::DefaultInterval());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
}
TEST_P(SchedulerTest, SyntheticBeginFrames_IsDrawThrottled) {
BeginFramesNotFromClient_IsDrawThrottled(THROTTLED_BFS);
}
TEST_P(SchedulerTest, UnthrottledBeginFrames_IsDrawThrottled) {
BeginFramesNotFromClient_IsDrawThrottled(UNTHROTTLED_BFS);
}
TEST_P(SchedulerTest,
DidLoseLayerTreeFrameSinkAfterLayerTreeFrameSinkIsInitialized) {
SetUpSchedulerWithNoLayerTreeFrameSink(EXTERNAL_BFS);
scheduler_->SetVisible(true);
scheduler_->SetCanDraw(true);
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
client_->Reset();
scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
EXPECT_NO_ACTION();
scheduler_->DidLoseLayerTreeFrameSink();
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
}
TEST_P(SchedulerTest, DidLoseLayerTreeFrameSinkAfterBeginFrameStarted) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->DidLoseLayerTreeFrameSink();
EXPECT_NO_ACTION();
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit",
"ScheduledActionActivateSyncTree");
client_->Reset();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
"RemoveObserver(this)");
}
TEST_P(SchedulerTest,
DidLoseLayerTreeFrameSinkAfterBeginFrameStartedWithHighLatency) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->DidLoseLayerTreeFrameSink();
EXPECT_NO_ACTION();
client_->Reset();
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("RemoveObserver(this)");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunUntilTime(task_runner_->NowTicks() + base::Milliseconds(10));
EXPECT_NO_ACTION();
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit",
"ScheduledActionActivateSyncTree",
"ScheduledActionBeginLayerTreeFrameSinkCreation");
}
TEST_P(SchedulerTest, DidLoseLayerTreeFrameSinkAfterReadyToCommit) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
client_->Reset();
scheduler_->DidLoseLayerTreeFrameSink();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
client_->Reset();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
"RemoveObserver(this)");
}
TEST_P(SchedulerTest, DidLoseLayerTreeFrameSinkAfterSetNeedsPrepareTiles) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsPrepareTiles();
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->DidLoseLayerTreeFrameSink();
EXPECT_NO_ACTION();
client_->Reset();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionPrepareTiles",
"ScheduledActionBeginLayerTreeFrameSinkCreation",
"RemoveObserver(this)");
}
TEST_P(SchedulerTest, DidLoseLayerTreeFrameSinkWithDelayBasedBeginFrameSource) {
SetUpScheduler(THROTTLED_BFS);
EXPECT_FALSE(scheduler_->begin_frames_expected());
scheduler_->SetNeedsBeginMainFrame();
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
AdvanceFrame();
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
scheduler_->DidLoseLayerTreeFrameSink();
EXPECT_NO_ACTION();
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
EXPECT_FALSE(scheduler_->begin_frames_expected());
}
TEST_P(SchedulerTest, DidLoseLayerTreeFrameSinkWhenIdle) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
client_->Reset();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
client_->Reset();
scheduler_->DidLoseLayerTreeFrameSink();
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
"RemoveObserver(this)");
}
TEST_P(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->SetVisible(false);
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree", "RemoveObserver(this)");
}
TEST_P(SchedulerTest, ScheduledActionActivateAfterBeginFrameSourcePaused) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
fake_external_begin_frame_source_->SetPaused(true);
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree", "RemoveObserver(this)");
}
TEST_P(SchedulerTest, SwitchFrameSourceToUnthrottled) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
scheduler_->SetNeedsRedraw();
scheduler_->SetBeginFrameSource(unthrottled_frame_source_.get());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
}
TEST_P(SchedulerTest, SwitchFrameSourceToUnthrottledBeforeDeadline) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
scheduler_->SetBeginFrameSource(unthrottled_frame_source_.get());
client_->Reset();
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
"WillBeginImplFrame");
scheduler_->SetNeedsRedraw();
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
}
TEST_P(SchedulerTest, SwitchFrameSourceToThrottled) {
SetUpScheduler(UNTHROTTLED_BFS);
scheduler_->SetNeedsRedraw();
EXPECT_NO_ACTION();
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->SetBeginFrameSource(fake_external_begin_frame_source_.get());
client_->Reset();
scheduler_->SetNeedsRedraw();
task_runner_->RunPendingTasks();
EXPECT_NO_ACTION();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
}
TEST_P(SchedulerTest, SwitchFrameSourceToNullInsideDeadline) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
client_->Reset();
scheduler_->SetBeginFrameSource(nullptr);
EXPECT_ACTIONS("RemoveObserver(this)");
client_->Reset();
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(scheduler_->begin_frames_expected());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->SetNeedsRedraw();
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_NO_ACTION();
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_NO_ACTION();
client_->Reset();
scheduler_->SetBeginFrameSource(fake_external_begin_frame_source_.get());
EXPECT_ACTIONS("AddObserver(this)");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
}
TEST_P(SchedulerTest, SwitchFrameSourceWhenNotObserving) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
client_->Reset();
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
client_->Reset();
scheduler_->DidLoseLayerTreeFrameSink();
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
"RemoveObserver(this)");
client_->Reset();
scheduler_->SetBeginFrameSource(unthrottled_frame_source_.get());
EXPECT_NO_ACTION();
client_->Reset();
scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
EXPECT_NO_ACTION();
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_NO_ACTION();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
}
TEST_P(SchedulerTest, ScheduledActionBeginMainFrameNotExpectedUntil) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionBeginMainFrameNotExpectedUntil",
"ScheduledActionDrawIfPossible");
}
TEST_P(SchedulerTest,
ScheduledActionBeginMainFrameNotExpectedUntilSentOnlyOncePerFrame) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionBeginMainFrameNotExpectedUntil",
"ScheduledActionDrawIfPossible");
client_->Reset();
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(false);
task_runner_->RunPendingTasks();
EXPECT_NO_ACTION();
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
task_runner_->RunPendingTasks();
EXPECT_NO_ACTION();
}
TEST_P(SchedulerTest, SendBeginMainFrameNotExpectedSoon_Requested) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
scheduler_->NotifyReadyToActivate();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
"ScheduledActionCommit", "ScheduledActionPostCommit",
"ScheduledActionActivateSyncTree",
"ScheduledActionDrawIfPossible");
client_->Reset();
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionBeginMainFrameNotExpectedUntil");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("SendBeginMainFrameNotExpectedSoon", "RemoveObserver(this)");
client_->Reset();
}
TEST_P(SchedulerTest, SendBeginMainFrameNotExpectedSoon_Unrequested) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
scheduler_->NotifyReadyToActivate();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
"ScheduledActionCommit", "ScheduledActionPostCommit",
"ScheduledActionActivateSyncTree",
"ScheduledActionDrawIfPossible");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("RemoveObserver(this)");
client_->Reset();
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
EXPECT_ACTIONS("SendBeginMainFrameNotExpectedSoon");
}
TEST_P(SchedulerTest, SendBeginMainFrameNotExpectedSoonOnlyOncePerFrame) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
scheduler_->NotifyReadyToActivate();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
"ScheduledActionCommit", "ScheduledActionPostCommit",
"ScheduledActionActivateSyncTree",
"ScheduledActionDrawIfPossible");
client_->Reset();
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionBeginMainFrameNotExpectedUntil");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("SendBeginMainFrameNotExpectedSoon", "RemoveObserver(this)");
client_->Reset();
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(false);
EXPECT_NO_ACTION();
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
EXPECT_NO_ACTION();
}
TEST_P(SchedulerTest, SendBeginMainFrameNotExpectedSoon_AlreadyIdle) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
scheduler_->NotifyReadyToActivate();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
"ScheduledActionCommit", "ScheduledActionPostCommit",
"ScheduledActionActivateSyncTree",
"ScheduledActionDrawIfPossible");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame", "RemoveObserver(this)");
client_->Reset();
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
EXPECT_ACTIONS("SendBeginMainFrameNotExpectedSoon");
}
TEST_P(SchedulerTest, SendBeginMainFrameNotExpectedSoonDuringIdleIfNeeded) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionDrawIfPossible");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
EXPECT_ACTIONS("ScheduledActionBeginMainFrameNotExpectedUntil");
client_->Reset();
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(false);
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("RemoveObserver(this)");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
EXPECT_ACTIONS("SendBeginMainFrameNotExpectedSoon");
}
TEST_P(SchedulerTest,
ScheduledActionBeginMainFrameNotSoonSentDuringIdleIfNeededNotVisible) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionDrawIfPossible");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->SetVisible(false);
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("RemoveObserver(this)");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
EXPECT_ACTIONS("SendBeginMainFrameNotExpectedSoon");
}
TEST_P(SchedulerTest, SynchronousCompositorAnimation) {
scheduler_settings_.using_synchronous_renderer_compositor = true;
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsOneBeginImplFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
client_->SetWillBeginImplFrameCausesRedraw(true);
client_->SetWillBeginImplFrameRequestsOneBeginImplFrame(true);
AdvanceFrame();
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionInvalidateLayerTreeFrameSink");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = false;
bool skip_draw = false;
scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
client_->SetWillBeginImplFrameCausesRedraw(true);
AdvanceFrame();
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionInvalidateLayerTreeFrameSink");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->SetNeedsRedraw();
scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
AdvanceFrame();
EXPECT_ACTIONS("WillBeginImplFrame", "RemoveObserver(this)");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
}
TEST_P(SchedulerTest, SynchronousCompositorOnDrawDuringIdle) {
scheduler_settings_.using_synchronous_renderer_compositor = true;
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = false;
bool skip_draw = false;
scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
skip_draw);
EXPECT_ACTIONS("AddObserver(this)", "ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
AdvanceFrame();
EXPECT_ACTIONS("WillBeginImplFrame", "RemoveObserver(this)");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
}
TEST_P(SchedulerTest, InvalidateLayerTreeFrameSinkWhenCannotDraw) {
scheduler_settings_.using_synchronous_renderer_compositor = true;
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetCanDraw(false);
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(scheduler_->RedrawPending());
scheduler_->SetCanDraw(true);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionInvalidateLayerTreeFrameSink");
client_->Reset();
bool resourceless_software_draw = false;
bool skip_draw = false;
scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(scheduler_->RedrawPending());
}
TEST_P(SchedulerTest, NeedsPrepareTilesInvalidates) {
scheduler_settings_.using_synchronous_renderer_compositor = true;
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetCanDraw(false);
scheduler_->SetNeedsPrepareTiles();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionInvalidateLayerTreeFrameSink");
client_->Reset();
}
TEST_P(SchedulerTest, SetNeedsOneBeginImplFrame) {
SetUpScheduler(EXTERNAL_BFS);
EXPECT_FALSE(scheduler_->begin_frames_expected());
scheduler_->SetNeedsOneBeginImplFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
client_->SetWillBeginImplFrameRequestsOneBeginImplFrame(true);
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_ACTIONS("RemoveObserver(this)");
}
TEST_P(SchedulerTest, AbortEarlyIfNoDamage) {
SetUpScheduler(EXTERNAL_BFS);
client_->SetWillBeginImplFrameMightHaveDamage(false);
scheduler_->SetNeedsRedraw();
EXPECT_EQ(0, client_->num_draws());
EXPECT_ACTIONS("AddObserver(this)");
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
"RemoveObserver(this)");
EXPECT_EQ(0, client_->num_draws());
scheduler_->SetNeedsRedraw();
EXPECT_SCOPED(AdvanceFrame());
task_runner_->RunPendingTasks();
EXPECT_EQ(0, client_->num_draws());
}
TEST_P(SchedulerTest, SkipDraw) {
scheduler_settings_.using_synchronous_renderer_compositor = true;
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsOneBeginImplFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
client_->SetWillBeginImplFrameCausesRedraw(true);
AdvanceFrame();
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionInvalidateLayerTreeFrameSink");
EXPECT_TRUE(client_->invalidate_needs_redraw());
client_->Reset();
scheduler_->SetNeedsPrepareTiles();
bool resourceless_software_draw = false;
bool skip_draw = false;
scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
"ScheduledActionPrepareTiles");
client_->Reset();
scheduler_->SetNeedsPrepareTiles();
AdvanceFrame();
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionInvalidateLayerTreeFrameSink");
EXPECT_FALSE(client_->invalidate_needs_redraw());
client_->Reset();
scheduler_->SetNeedsRedraw();
scheduler_->SetNeedsPrepareTiles();
client_->SetInvalidateNeedsRedraw(false);
skip_draw = true;
scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
skip_draw);
EXPECT_ACTIONS("ScheduledActionPrepareTiles");
client_->Reset();
}
TEST_P(SchedulerTest, SynchronousCompositorCommitAndVerifyBeginFrameAcks) {
scheduler_settings_.using_synchronous_renderer_compositor = true;
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
viz::BeginFrameArgs args = SendNextBeginFrame();
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
bool has_damage = false;
EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
client_->last_begin_frame_ack());
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
EXPECT_NO_ACTION();
args = SendNextBeginFrame();
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
has_damage = false;
EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
client_->last_begin_frame_ack());
client_->Reset();
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
client_->Reset();
args = SendNextBeginFrame();
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionInvalidateLayerTreeFrameSink");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = false;
bool skip_draw = false;
scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
args = SendNextBeginFrame();
EXPECT_ACTIONS("WillBeginImplFrame", "RemoveObserver(this)");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
has_damage = false;
EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
client_->last_begin_frame_ack());
client_->Reset();
}
class SchedulerClientSetNeedsPrepareTilesOnDraw : public FakeSchedulerClient {
public:
SchedulerClientSetNeedsPrepareTilesOnDraw() : FakeSchedulerClient() {}
protected:
DrawResult ScheduledActionDrawIfPossible() override {
scheduler_->SetNeedsPrepareTiles();
return FakeSchedulerClient::ScheduledActionDrawIfPossible();
}
};
TEST_P(SchedulerTest, SynchronousCompositorPrepareTilesOnDraw) {
scheduler_settings_.using_synchronous_renderer_compositor = true;
std::unique_ptr<FakeSchedulerClient> client =
base::WrapUnique(new SchedulerClientSetNeedsPrepareTilesOnDraw);
SetUpScheduler(EXTERNAL_BFS, std::move(client));
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionInvalidateLayerTreeFrameSink");
client_->Reset();
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = false;
bool skip_draw = false;
scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
"ScheduledActionPrepareTiles");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
client_->Reset();
scheduler_->SetNeedsRedraw();
scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
"ScheduledActionPrepareTiles");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
EXPECT_ACTIONS("WillBeginImplFrame", "RemoveObserver(this)");
EXPECT_FALSE(scheduler_->begin_frames_expected());
client_->Reset();
}
TEST_P(SchedulerTest, SynchronousCompositorAllowsActivateBeforeDraw) {
scheduler_settings_.using_synchronous_renderer_compositor = true;
std::unique_ptr<FakeSchedulerClient> client =
base::WrapUnique(new SchedulerClientSetNeedsPrepareTilesOnDraw);
SetUpScheduler(EXTERNAL_BFS, std::move(client));
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
"ScheduledActionInvalidateLayerTreeFrameSink");
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
"ScheduledActionInvalidateLayerTreeFrameSink");
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
client_->Reset();
}
TEST_P(SchedulerTest, SetNeedsRedrawFromWillBeginImplFrame) {
client_ = std::make_unique<FakeSchedulerClient>();
CreateScheduler(EXTERNAL_BFS);
scheduler_->SetVisible(true);
scheduler_->SetCanDraw(true);
client_->SetWillBeginImplFrameCausesRedraw(true);
scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
scheduler_->SetNeedsBeginMainFrame();
AdvanceFrame();
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
"AddObserver(this)", "WillBeginImplFrame",
"ScheduledActionSendBeginMainFrame");
EXPECT_TRUE(scheduler_->RedrawPending());
}
TEST_P(SchedulerTest, SynchronousCompositorSendBeginMainFrameWhileIdle) {
scheduler_settings_.using_synchronous_renderer_compositor = true;
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsRedraw();
EXPECT_ACTIONS("AddObserver(this)");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionInvalidateLayerTreeFrameSink");
client_->Reset();
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = false;
bool skip_draw = false;
scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame");
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionInvalidateLayerTreeFrameSink");
client_->Reset();
scheduler_->SetNeedsRedraw();
scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame");
client_->Reset();
}
TEST_P(SchedulerTest, SynchronousCompositorResourcelessOnDrawWhenInvisible) {
scheduler_settings_.using_synchronous_renderer_compositor = true;
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetVisible(false);
scheduler_->SetNeedsRedraw();
bool resourceless_software_draw = true;
bool skip_draw = false;
scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
skip_draw);
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
}
TEST_P(SchedulerTest, AuthoritativeVSyncInterval) {
SetUpScheduler(THROTTLED_BFS);
base::TimeDelta initial_interval = scheduler_->BeginImplFrameInterval();
base::TimeDelta authoritative_interval = base::Milliseconds(33);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_EQ(initial_interval, scheduler_->BeginImplFrameInterval());
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
scheduler_->NotifyReadyToActivate();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
synthetic_frame_source_->OnUpdateVSyncParameters(task_runner_->NowTicks(),
authoritative_interval);
EXPECT_SCOPED(AdvanceFrame());
EXPECT_NE(initial_interval, scheduler_->BeginImplFrameInterval());
EXPECT_EQ(authoritative_interval, scheduler_->BeginImplFrameInterval());
}
TEST_P(SchedulerTest, ImplLatencyTakesPriority) {
SetUpScheduler(THROTTLED_BFS);
scheduler_->SetTreePrioritiesAndScrollState(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER, false);
scheduler_->SetCriticalBeginMainFrameToActivateIsFast(true);
EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
scheduler_->SetCriticalBeginMainFrameToActivateIsFast(false);
EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
scheduler_->SetTreePrioritiesAndScrollState(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER, true);
scheduler_->SetCriticalBeginMainFrameToActivateIsFast(true);
EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
scheduler_->SetCriticalBeginMainFrameToActivateIsFast(false);
EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
scheduler_->SetTreePrioritiesAndScrollState(
SAME_PRIORITY_FOR_BOTH_TREES,
ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER, false);
scheduler_->SetCriticalBeginMainFrameToActivateIsFast(true);
EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
scheduler_->SetCriticalBeginMainFrameToActivateIsFast(false);
EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
scheduler_->SetTreePrioritiesAndScrollState(
SAME_PRIORITY_FOR_BOTH_TREES,
ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER, true);
scheduler_->SetCriticalBeginMainFrameToActivateIsFast(true);
EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
scheduler_->SetCriticalBeginMainFrameToActivateIsFast(false);
EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
}
TEST_P(SchedulerTest, NoLayerTreeFrameSinkCreationWhileCommitPending) {
SetUpScheduler(THROTTLED_BFS);
scheduler_->SetNeedsBeginMainFrame();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
client_->Reset();
scheduler_->DidLoseLayerTreeFrameSink();
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_NO_ACTION();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_NO_ACTION();
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->BeginMainFrameAborted(
CommitEarlyOutReason::kAbortedDeferredCommit);
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
}
TEST_P(SchedulerTest, ImplSideInvalidationInsideImplFrame) {
SetUpScheduler(EXTERNAL_BFS);
bool needs_first_draw_on_activation = true;
scheduler_->SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionPerformImplSideInvalidation");
}
TEST_P(SchedulerTest, ImplSideInvalidationsMergedWithCommit) {
SetUpScheduler(EXTERNAL_BFS);
SetShouldDeferInvalidationForMainFrame(true);
scheduler_->SetNeedsBeginMainFrame();
bool needs_first_draw_on_activation = true;
scheduler_->SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
EXPECT_FALSE(scheduler_->needs_impl_side_invalidation());
}
TEST_P(SchedulerTest, AbortedCommitsTriggerImplSideInvalidations) {
SetUpScheduler(EXTERNAL_BFS);
SetShouldDeferInvalidationForMainFrame(true);
scheduler_->SetNeedsBeginMainFrame();
bool needs_first_draw_on_activation = true;
scheduler_->SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->BeginMainFrameAborted(CommitEarlyOutReason::kFinishedNoUpdates);
EXPECT_ACTIONS("ScheduledActionPerformImplSideInvalidation");
}
TEST_P(SchedulerTest, InvalidationNotBlockedOnMainFrame) {
SetUpScheduler(EXTERNAL_BFS);
SetShouldDeferInvalidationForMainFrame(false);
scheduler_->SetNeedsBeginMainFrame();
bool needs_first_draw_on_activation = true;
scheduler_->SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
"ScheduledActionPerformImplSideInvalidation");
}
bool SchedulerTest::BeginMainFrameOnCriticalPath(
TreePriority tree_priority,
ScrollHandlerState scroll_handler_state,
base::TimeDelta durations) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(durations);
client_->Reset();
scheduler_->SetTreePrioritiesAndScrollState(
tree_priority, scroll_handler_state,
scroll_handler_state ==
ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_FALSE(client_->last_begin_main_frame_args().IsValid());
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(client_->last_begin_main_frame_args().IsValid());
return client_->last_begin_main_frame_args().on_critical_path;
}
TEST_P(SchedulerTest, BeginMainFrameOnCriticalPath_BNF) {
EXPECT_TRUE(BeginMainFrameOnCriticalPath(
SAME_PRIORITY_FOR_BOTH_TREES,
ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER,
kFastDuration));
}
TEST_P(SchedulerTest, BeginMainFrameOnCriticalPath_BNS) {
EXPECT_TRUE(BeginMainFrameOnCriticalPath(
SAME_PRIORITY_FOR_BOTH_TREES,
ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER,
kSlowDuration));
}
TEST_P(SchedulerTest, BeginMainFrameOnCriticalPath_BHF) {
EXPECT_TRUE(BeginMainFrameOnCriticalPath(
SAME_PRIORITY_FOR_BOTH_TREES,
ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER, kFastDuration));
}
TEST_P(SchedulerTest, BeginMainFrameOnCriticalPath_BHS) {
EXPECT_TRUE(BeginMainFrameOnCriticalPath(
SAME_PRIORITY_FOR_BOTH_TREES,
ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER, kSlowDuration));
}
TEST_P(SchedulerTest, BeginMainFrameOnCriticalPath_ANF) {
EXPECT_FALSE(BeginMainFrameOnCriticalPath(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER,
kFastDuration));
}
TEST_P(SchedulerTest, BeginMainFrameOnCriticalPath_ANS) {
EXPECT_FALSE(BeginMainFrameOnCriticalPath(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER,
kSlowDuration));
}
TEST_P(SchedulerTest, BeginMainFrameOnCriticalPath_AHF) {
EXPECT_TRUE(BeginMainFrameOnCriticalPath(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER, kFastDuration));
}
TEST_P(SchedulerTest, BeginMainFrameOnCriticalPath_AHS) {
EXPECT_FALSE(BeginMainFrameOnCriticalPath(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER, kSlowDuration));
}
TEST_P(SchedulerTest, BeginFrameAckForFinishedImplFrame) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsRedraw();
client_->Reset();
viz::BeginFrameArgs args = SendNextBeginFrame();
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
bool has_damage = true;
EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
client_->last_begin_frame_ack());
client_->Reset();
scheduler_->SetNeedsRedraw();
client_->Reset();
args = SendNextBeginFrame();
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
client_->SetDrawWillHappen(false);
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
"ScheduledActionSendBeginMainFrame");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
has_damage = false;
EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
client_->last_begin_frame_ack());
EXPECT_EQ(FrameSkippedReason::kWaitingOnMain,
client_->last_frame_skipped_reason());
client_->Reset();
args = SendNextBeginFrame();
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
client_->SetDrawWillHappen(false);
client_->SetSwapWillHappenIfDrawHappens(false);
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
has_damage = false;
EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
client_->last_begin_frame_ack());
EXPECT_EQ(FrameSkippedReason::kWaitingOnMain,
client_->last_frame_skipped_reason());
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
args = SendNextBeginFrame();
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
client_->SetDrawWillHappen(true);
client_->SetSwapWillHappenIfDrawHappens(false);
task_runner_->RunPendingTasks();
has_damage = false;
EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
client_->last_begin_frame_ack());
EXPECT_EQ(FrameSkippedReason::kWaitingOnMain,
client_->last_frame_skipped_reason());
}
TEST_P(SchedulerTest, BeginFrameAckForBeginFrameBeforeLastDeadline) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsPrepareTiles();
client_->Reset();
SendNextBeginFrame();
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
viz::BeginFrameArgs args = SendNextBeginFrame();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("ScheduledActionPrepareTiles", "RemoveObserver(this)");
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_FALSE(scheduler_->begin_frames_expected());
bool has_damage = false;
EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
client_->last_begin_frame_ack());
client_->Reset();
}
TEST_P(SchedulerTest, BeginFrameAckForDroppedBeginFrame) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsOneBeginImplFrame();
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
viz::BeginFrameArgs first_args = SendNextBeginFrame();
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
EXPECT_FALSE(scheduler_->BeginFrameNeeded());
client_->Reset();
viz::BeginFrameArgs second_args = SendNextBeginFrame();
EXPECT_NO_ACTION();
bool has_damage = false;
EXPECT_EQ(viz::BeginFrameAck(second_args, has_damage),
client_->last_begin_frame_ack());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS("RemoveObserver(this)");
has_damage = false;
EXPECT_EQ(viz::BeginFrameAck(first_args, has_damage),
client_->last_begin_frame_ack());
client_->Reset();
}
TEST_P(SchedulerTest, BeginFrameAckForLateMissedBeginFrame) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsRedraw();
client_->Reset();
task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
viz::BeginFrameArgs args =
fake_external_begin_frame_source_->CreateBeginFrameArgs(
BEGINFRAME_FROM_HERE, task_runner_->GetMockTickClock());
args.type = viz::BeginFrameArgs::MISSED;
task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
EXPECT_GT(task_runner_->NowTicks(), args.deadline);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
task_runner_->RunPendingTasks();
EXPECT_NO_ACTION();
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
bool has_damage = false;
EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
client_->last_begin_frame_ack());
client_->Reset();
}
TEST_P(SchedulerTest, CriticalBeginMainFrameToActivateIsFast) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsRedraw();
base::TimeDelta estimate_duration = base::Milliseconds(1);
fake_compositor_timing_history_->SetAllEstimatesTo(estimate_duration);
scheduler_->SetTreePrioritiesAndScrollState(
SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER, true);
scheduler_->SetNeedsRedraw();
base::TimeDelta interval = base::Milliseconds(2);
task_runner_->AdvanceMockTickClock(interval);
viz::BeginFrameArgs args = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, 0u, 1u, task_runner_->NowTicks(),
task_runner_->NowTicks() + interval, interval,
viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
task_runner_->RunPendingTasks();
ASSERT_FALSE(client_->IsInsideBeginImplFrame());
scheduler_->SetNeedsRedraw();
interval = base::Milliseconds(10);
task_runner_->AdvanceMockTickClock(interval);
args = viz::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, 0u, 2u,
task_runner_->NowTicks(),
task_runner_->NowTicks() + interval,
interval, viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
task_runner_->RunPendingTasks();
ASSERT_FALSE(client_->IsInsideBeginImplFrame());
scheduler_->SetNeedsRedraw();
fake_compositor_timing_history_->SetDrawDurationEstimate(
base::Milliseconds(7));
task_runner_->AdvanceMockTickClock(interval);
args = viz::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, 0u, 3u,
task_runner_->NowTicks(),
task_runner_->NowTicks() + interval,
interval, viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
}
TEST_P(SchedulerTest, WaitForAllPipelineStagesUsesMissedBeginFrames) {
scheduler_settings_.wait_for_all_pipeline_stages_before_draw = true;
client_ = std::make_unique<FakeSchedulerClient>();
CreateScheduler(EXTERNAL_BFS);
scheduler_->SetVisible(true);
scheduler_->SetCanDraw(true);
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
client_->Reset();
scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_TRUE(scheduler_->begin_frames_expected());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
base::TimeDelta interval = base::Milliseconds(16);
task_runner_->AdvanceMockTickClock(interval);
base::TimeTicks timestamp = task_runner_->NowTicks();
task_runner_->AdvanceMockTickClock(interval * 2);
viz::BeginFrameArgs args = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, 0u, 1u, timestamp, timestamp + interval, interval,
viz::BeginFrameArgs::MISSED);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
}
TEST_P(SchedulerTest, WaitForAllPipelineStagesAlwaysObservesBeginFrames) {
scheduler_settings_.wait_for_all_pipeline_stages_before_draw = true;
client_ = std::make_unique<FakeSchedulerClient>();
CreateScheduler(EXTERNAL_BFS);
scheduler_->SetVisible(true);
scheduler_->SetCanDraw(true);
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
client_->Reset();
scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
scheduler_->SetDeferBeginMainFrame(true);
scheduler_->SetNeedsBeginMainFrame();
EXPECT_TRUE(scheduler_->begin_frames_expected());
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
EXPECT_TRUE(scheduler_->begin_frames_expected());
EXPECT_TRUE(scheduler_->BeginFrameNeeded());
base::TimeDelta interval = base::Milliseconds(16);
task_runner_->AdvanceMockTickClock(interval);
base::TimeTicks timestamp = task_runner_->NowTicks();
viz::BeginFrameArgs args = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, 0u, 1u, timestamp, timestamp + interval, interval,
viz::BeginFrameArgs::NORMAL);
fake_external_begin_frame_source_->TestOnBeginFrame(args);
EXPECT_ACTIONS("WillBeginImplFrame");
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS();
EXPECT_TRUE(!client_->IsInsideBeginImplFrame());
client_->Reset();
}
TEST_P(SchedulerTest, CriticalBeginMainFrameIsFast_CommitEstimateSlow) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_->SetCommitDurationEstimate(kSlowDuration);
EXPECT_SCOPED(AdvanceFrame());
EXPECT_FALSE(scheduler_->state_machine()
.critical_begin_main_frame_to_activate_is_fast());
}
TEST_P(SchedulerTest, CriticalBeginMainFrameIsFast_CommitEstimateFast) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(scheduler_->state_machine()
.critical_begin_main_frame_to_activate_is_fast());
}
TEST_P(SchedulerTest, ShouldDeferInvalidation_AllEstimatesFast) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(scheduler_->state_machine()
.should_defer_invalidation_for_fast_main_frame());
}
TEST_P(SchedulerTest, ShouldDeferInvalidation_BMFStartToReadyToCommitSlow) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_
->SetBeginMainFrameStartToReadyToCommitDurationEstimate(kSlowDuration);
EXPECT_SCOPED(AdvanceFrame());
EXPECT_FALSE(scheduler_->state_machine()
.should_defer_invalidation_for_fast_main_frame());
}
TEST_P(SchedulerTest, ShouldDeferInvalidation_BMFQueueDurationCriticalSlow) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_
->SetBeginMainFrameQueueDurationCriticalEstimate(kSlowDuration);
EXPECT_SCOPED(AdvanceFrame());
EXPECT_FALSE(scheduler_->state_machine()
.should_defer_invalidation_for_fast_main_frame());
}
TEST_P(SchedulerTest, ShouldDeferInvalidation_BMFQueueDurationNotCriticalSlow) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
scheduler_->SetTreePrioritiesAndScrollState(
TreePriority::SMOOTHNESS_TAKES_PRIORITY,
ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER, false);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
fake_compositor_timing_history_
->SetBeginMainFrameQueueDurationNotCriticalEstimate(kSlowDuration);
EXPECT_SCOPED(AdvanceFrame());
EXPECT_FALSE(scheduler_->state_machine()
.should_defer_invalidation_for_fast_main_frame());
}
TEST_P(SchedulerTest, SlowMainThreadButEstimatedFastTriggersInvalidations) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
scheduler_->SetNeedsImplSideInvalidation(true);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionPerformImplSideInvalidation");
}
TEST_P(SchedulerTest,
SlowMainThreadRasterButEstimatedFastDoesNotTriggersInvalidations) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
scheduler_->SetNeedsImplSideInvalidation(true);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->NotifyReadyToCommit(nullptr);
EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
client_->Reset();
task_runner_->RunPendingTasks();
EXPECT_ACTIONS();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
}
TEST_P(SchedulerTest, SynchronousCompositorImplSideInvalidation) {
scheduler_settings_.using_synchronous_renderer_compositor = true;
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kSlowDuration);
scheduler_->SetNeedsBeginMainFrame();
const bool needs_first_draw_on_activation = true;
scheduler_->SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
}
TEST_P(SchedulerTest, NoInvalidationForAnimateOnlyFrames) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
client_->Reset();
scheduler_->SetNeedsImplSideInvalidation(true);
bool animate_only = true;
EXPECT_SCOPED(AdvanceFrame(animate_only));
EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame");
client_->Reset();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS();
animate_only = false;
EXPECT_SCOPED(AdvanceFrame(animate_only));
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionPerformImplSideInvalidation");
client_->Reset();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS();
}
TEST_P(SchedulerTest, SendEarlyDidNotProduceFrameIfIdle) {
SetUpScheduler(EXTERNAL_BFS);
scheduler_->SetNeedsBeginMainFrame();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
auto begin_main_frame_args = client_->last_begin_main_frame_args();
EXPECT_NE(client_->last_begin_frame_ack().frame_id.sequence_number,
begin_main_frame_args.frame_id.sequence_number);
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
scheduler_->SetNeedsBeginMainFrame();
scheduler_->BeginMainFrameAborted(CommitEarlyOutReason::kFinishedNoUpdates);
EXPECT_EQ(client_->last_begin_frame_ack().frame_id.sequence_number,
begin_main_frame_args.frame_id.sequence_number);
}
TEST_P(SchedulerTest,
HighImplLatencyModePrioritizesMainFramesOverImplInvalidation) {
SetUpScheduler(EXTERNAL_BFS);
fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
scheduler_->SetNeedsImplSideInvalidation(true);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame",
"ScheduledActionPerformImplSideInvalidation");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTIONS("WillBeginImplFrame");
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame");
fake_compositor_timing_history_->SetBeginMainFrameSentTime(
task_runner_->NowTicks() + base::Milliseconds(8));
client_->Reset();
scheduler_->NotifyReadyToActivate();
task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
EXPECT_ACTIONS("ScheduledActionActivateSyncTree",
"ScheduledActionDrawIfPossible");
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
scheduler_->SetNeedsImplSideInvalidation(true);
EXPECT_ACTIONS("WillBeginImplFrame");
}
TEST_P(SchedulerTest, ProactiveThrottling) {
SetUpScheduler(EXTERNAL_BFS);
constexpr uint64_t kSourceId = viz::BeginFrameArgs::kStartingSourceId;
uint64_t sequence_number = viz::BeginFrameArgs::kStartingFrameNumber;
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeatureWithParameters(
features::kRenderThrottleFrameRate,
{{"render-throttled-frame-interval-hz", "30"}});
base::TimeDelta throttled_interval =
base::Hertz(features::kRenderThrottledFrameIntervalHz.Get());
base::TimeDelta interval = base::Hertz(120);
SendTestBeginFrameAfterInterval(interval, kSourceId, sequence_number++);
if (base::FeatureList::IsEnabled(features::kThrottleMainFrameTo60Hz)) {
EXPECT_GT(scheduler_->state_machine().MainFrameThrottledInterval(),
base::Hertz(120));
} else {
EXPECT_TRUE(
scheduler_->state_machine().MainFrameThrottledInterval().is_zero());
}
scheduler_->SetShouldThrottleFrameRate(true);
interval = base::Hertz(60);
SendTestBeginFrameAfterInterval(interval, kSourceId, sequence_number++);
EXPECT_EQ(scheduler_->state_machine().MainFrameThrottledInterval(),
throttled_interval);
interval = base::Hertz(10);
SendTestBeginFrameAfterInterval(interval, kSourceId, sequence_number++);
EXPECT_TRUE(
scheduler_->state_machine().MainFrameThrottledInterval().is_zero());
scheduler_->SetShouldThrottleFrameRate(false);
interval = base::Hertz(60);
SendTestBeginFrameAfterInterval(interval, kSourceId, sequence_number++);
EXPECT_TRUE(
scheduler_->state_machine().MainFrameThrottledInterval().is_zero());
}
TEST_P(SchedulerTest, SetShouldWarmUpWillStartLayerTreeFrameSinkCreation) {
SetUpSchedulerWithNoLayerTreeFrameSink(EXTERNAL_BFS);
scheduler_->SetVisible(false);
scheduler_->SetShouldWarmUp();
EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
client_->Reset();
scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
EXPECT_NO_ACTION();
}
class SchedulerClientTracksBeginFramePaused : public FakeSchedulerClient {
public:
void DidChangeBeginFrameSourcePaused(bool paused) override {
num_time_changed_++;
is_paused_ = paused;
}
bool is_paused() { return is_paused_; }
int num_time_changed() { return num_time_changed_; }
protected:
int num_time_changed_ = 0;
bool is_paused_ = false;
};
TEST_P(SchedulerTest, SchedulerClientShouldSendBeginMainFrameSourcePaused) {
SchedulerClientTracksBeginFramePaused* client =
new SchedulerClientTracksBeginFramePaused;
SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
scheduler_->OnBeginFrameSourcePausedChanged(true);
EXPECT_TRUE(client->is_paused());
scheduler_->OnBeginFrameSourcePausedChanged(false);
EXPECT_FALSE(client->is_paused());
EXPECT_EQ(client->num_time_changed(), 2);
}
INSTANTIATE_TEST_SUITE_P(,
SchedulerTest,
Combine(Bool(), Bool()),
&SchedulerTest::GetTestName);
}
}