diff options
author | enne <enne@chromium.org> | 2016-03-17 12:50:26 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-17 19:52:56 +0000 |
commit | 061ea9c84412147d772b91e138413cfd2a515eab (patch) | |
tree | a6d6b94c4d1c96baf9a62e3464d2b2204005af00 /cc | |
parent | 4588b6b41a9356338c1c2a2eea3bf11fb8647a35 (diff) | |
download | chromium_src-061ea9c84412147d772b91e138413cfd2a515eab.zip chromium_src-061ea9c84412147d772b91e138413cfd2a515eab.tar.gz chromium_src-061ea9c84412147d772b91e138413cfd2a515eab.tar.bz2 |
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}
Diffstat (limited to 'cc')
-rw-r--r-- | cc/scheduler/scheduler.cc | 16 | ||||
-rw-r--r-- | cc/scheduler/scheduler.h | 5 | ||||
-rw-r--r-- | cc/scheduler/scheduler_unittest.cc | 188 | ||||
-rw-r--r-- | cc/test/scheduler_test_common.h | 3 |
4 files changed, 197 insertions, 15 deletions
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index f5c6d60..7dcf738 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc @@ -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(); diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h index 4828896..21c9d04 100644 --- a/cc/scheduler/scheduler.h +++ b/cc/scheduler/scheduler.h @@ -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, diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index 37ab466..1ca9b69 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc @@ -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; diff --git a/cc/test/scheduler_test_common.h b/cc/test/scheduler_test_common.h index 259e991..414f31f 100644 --- a/cc/test/scheduler_test_common.h +++ b/cc/test/scheduler_test_common.h @@ -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(); |