Commit 061ea9c8 authored by enne's avatar enne Committed by Commit bot

Allow cc::Scheduler begin frame source to be changed

Also, add back throttling tests to check changing the source.

Depends on https://codereview.chromium.org/1765723002
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

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

Cr-Commit-Position: refs/heads/master@{#381779}
parent 4588b6b4
......@@ -49,7 +49,7 @@ Scheduler::Scheduler(
client_(client),
layer_tree_host_id_(layer_tree_host_id),
task_runner_(task_runner),
begin_frame_source_(begin_frame_source),
begin_frame_source_(nullptr),
observing_begin_frame_source_(false),
compositor_timing_history_(std::move(compositor_timing_history)),
begin_impl_frame_deadline_mode_(
......@@ -68,6 +68,7 @@ Scheduler::Scheduler(
begin_impl_frame_deadline_closure_ = base::Bind(
&Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr());
SetBeginFrameSource(begin_frame_source);
ProcessScheduledActions();
}
......@@ -113,6 +114,17 @@ void Scheduler::NotifyReadyToDraw() {
ProcessScheduledActions();
}
void Scheduler::SetBeginFrameSource(BeginFrameSource* source) {
DCHECK(source);
if (source == begin_frame_source_)
return;
if (begin_frame_source_ && observing_begin_frame_source_)
begin_frame_source_->RemoveObserver(this);
begin_frame_source_ = source;
if (observing_begin_frame_source_)
begin_frame_source_->AddObserver(this);
}
void Scheduler::SetNeedsBeginMainFrame() {
state_machine_.SetNeedsBeginMainFrame();
ProcessScheduledActions();
......@@ -744,7 +756,7 @@ void Scheduler::AsValueInto(base::trace_event::TracedValue* state) const {
TRACE_EVENT_CATEGORY_GROUP_ENABLED(
TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
&frame_tracing_enabled);
if (frame_tracing_enabled) {
if (frame_tracing_enabled && begin_frame_source_) {
state->BeginDictionary("begin_frame_source_");
begin_frame_source_->AsValueInto(state);
state->EndDictionary();
......
......@@ -80,6 +80,7 @@ class CC_EXPORT Scheduler : public BeginFrameObserverBase {
void SetCanDraw(bool can_draw);
void NotifyReadyToActivate();
void NotifyReadyToDraw();
void SetBeginFrameSource(BeginFrameSource* source);
void SetNeedsBeginMainFrame();
// Requests a single impl frame (after the current frame if there is one
......@@ -140,6 +141,10 @@ class CC_EXPORT Scheduler : public BeginFrameObserverBase {
void SetChildrenNeedBeginFrames(bool children_need_begin_frames);
void SetVideoNeedsBeginFrames(bool video_needs_begin_frames);
const BeginFrameSource* begin_frame_source() const {
return begin_frame_source_;
}
protected:
Scheduler(SchedulerClient* client,
const SchedulerSettings& scheduler_settings,
......
......@@ -257,18 +257,17 @@ class SchedulerTest : public testing::Test {
protected:
TestScheduler* CreateScheduler() {
BeginFrameSource* frame_source;
unthrottled_frame_source_ = TestBackToBackBeginFrameSource::Create(
now_src_.get(), task_runner_.get());
fake_external_begin_frame_source_.reset(
new FakeExternalBeginFrameSource(client_.get()));
synthetic_frame_source_ = TestSyntheticBeginFrameSource::Create(
now_src_.get(), task_runner_.get(), BeginFrameArgs::DefaultInterval());
if (!scheduler_settings_.throttle_frame_production) {
unthrottled_frame_source_ = TestBackToBackBeginFrameSource::Create(
now_src_.get(), task_runner_.get());
frame_source = unthrottled_frame_source_.get();
} else if (scheduler_settings_.use_external_begin_frame_source) {
fake_external_begin_frame_source_.reset(
new FakeExternalBeginFrameSource(client_.get()));
frame_source = fake_external_begin_frame_source_.get();
} else {
synthetic_frame_source_ = TestSyntheticBeginFrameSource::Create(
now_src_.get(), task_runner_.get(),
BeginFrameArgs::DefaultInterval());
frame_source = synthetic_frame_source_.get();
}
......@@ -396,8 +395,8 @@ class SchedulerTest : public testing::Test {
// Send the next BeginFrame message if using an external source, otherwise
// it will be already in the task queue.
if (scheduler_->settings().use_external_begin_frame_source &&
scheduler_->FrameProductionThrottled()) {
if (scheduler_->begin_frame_source() ==
fake_external_begin_frame_source_.get()) {
EXPECT_TRUE(scheduler_->begin_frames_expected());
SendNextBeginFrame();
}
......@@ -411,7 +410,8 @@ class SchedulerTest : public testing::Test {
}
BeginFrameArgs SendNextBeginFrame() {
DCHECK(scheduler_->settings().use_external_begin_frame_source);
DCHECK_EQ(scheduler_->begin_frame_source(),
fake_external_begin_frame_source_.get());
// Creep the time forward so that any BeginFrameArgs is not equal to the
// last one otherwise we violate the BeginFrameSource contract.
now_src_->Advance(BeginFrameArgs::DefaultInterval());
......@@ -3055,6 +3055,174 @@ TEST_F(SchedulerTest, ScheduledActionActivateAfterBeginFrameSourcePaused) {
EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_);
}
// Tests to ensure frame sources can be successfully changed while drawing.
TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottled) {
scheduler_settings_.use_external_begin_frame_source = true;
SetUpScheduler(true);
// SetNeedsRedraw should begin the frame on the next BeginImplFrame.
scheduler_->SetNeedsRedraw();
EXPECT_SINGLE_ACTION("AddObserver(this)", client_);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
scheduler_->SetNeedsRedraw();
// Switch to an unthrottled frame source.
scheduler_->SetBeginFrameSource(unthrottled_frame_source_.get());
client_->Reset();
// Unthrottled frame source will immediately begin a new frame.
task_runner().RunPendingTasks(); // Run posted BeginFrame.
EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
client_->Reset();
// If we don't swap on the deadline, we wait for the next BeginFrame.
task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
client_->Reset();
}
// Tests to ensure frame sources can be successfully changed while a frame
// deadline is pending.
TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottledBeforeDeadline) {
scheduler_settings_.use_external_begin_frame_source = true;
SetUpScheduler(true);
// SetNeedsRedraw should begin the frame on the next BeginImplFrame.
scheduler_->SetNeedsRedraw();
EXPECT_SINGLE_ACTION("AddObserver(this)", client_);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
// Switch to an unthrottled frame source before the frame deadline is hit.
scheduler_->SetBeginFrameSource(unthrottled_frame_source_.get());
client_->Reset();
EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
client_->Reset();
// Unthrottled frame source will immediately begin a new frame.
task_runner().RunPendingTasks(); // Run BeginFrame.
EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
scheduler_->SetNeedsRedraw();
client_->Reset();
task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
client_->Reset();
}
// Tests to ensure that the active frame source can successfully be changed from
// unthrottled to throttled.
TEST_F(SchedulerTest, SwitchFrameSourceToThrottled) {
scheduler_settings_.throttle_frame_production = false;
scheduler_settings_.use_external_begin_frame_source = true;
SetUpScheduler(true);
scheduler_->SetNeedsRedraw();
EXPECT_NO_ACTION(client_);
client_->Reset();
task_runner().RunPendingTasks(); // Run posted BeginFrame.
EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
client_->Reset();
task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
client_->Reset();
// Switch to a throttled frame source.
scheduler_->SetBeginFrameSource(fake_external_begin_frame_source_.get());
client_->Reset();
// SetNeedsRedraw should begin the frame on the next BeginImplFrame.
scheduler_->SetNeedsRedraw();
task_runner().RunPendingTasks();
EXPECT_NO_ACTION(client_);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
}
// This test maskes sure that switching a frame source when not observing
// such as when not visible also works.
TEST_F(SchedulerTest, SwitchFrameSourceWhenNotObserving) {
scheduler_settings_.use_external_begin_frame_source = true;
SetUpScheduler(true);
// SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame.
scheduler_->SetNeedsBeginMainFrame();
EXPECT_SINGLE_ACTION("AddObserver(this)", client_);
client_->Reset();
// Begin new frame.
EXPECT_SCOPED(AdvanceFrame());
scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
client_->Reset();
scheduler_->NotifyReadyToCommit();
EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
client_->Reset();
scheduler_->NotifyReadyToActivate();
EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_);
// Scheduler loses output surface, and stops waiting for ready to draw signal.
client_->Reset();
scheduler_->DidLoseOutputSurface();
EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
task_runner().RunPendingTasks();
EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
EXPECT_ACTION("RemoveObserver(this)", client_, 1, 3);
EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
// Changing begin frame source doesn't do anything.
// The unthrottled source doesn't print Add/RemoveObserver like the fake one.
client_->Reset();
scheduler_->SetBeginFrameSource(unthrottled_frame_source_.get());
EXPECT_NO_ACTION(client_);
client_->Reset();
scheduler_->DidCreateAndInitializeOutputSurface();
EXPECT_NO_ACTION(client_);
client_->Reset();
scheduler_->SetNeedsBeginMainFrame();
EXPECT_NO_ACTION(client_);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
}
// Tests to ensure that we send a BeginMainFrameNotExpectedSoon when expected.
TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon) {
scheduler_settings_.use_external_begin_frame_source = true;
......
......@@ -233,9 +233,6 @@ class TestScheduler : public Scheduler {
}
BeginFrameSource& frame_source() { return *begin_frame_source_; }
bool FrameProductionThrottled() {
return settings_.throttle_frame_production;
}
bool MainThreadMissedLastDeadline() const {
return state_machine_.main_thread_missed_last_deadline();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment