diff options
author | enne <enne@chromium.org> | 2016-03-18 11:22:43 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-18 18:24:17 +0000 |
commit | 0ec0805af79680611fbfbc5d0e825eb18039cf9d (patch) | |
tree | 42ec1ec9be29c82a7a3168813f9fa53c8c8f6dac /cc | |
parent | c987fed5acb7cad3d489ebe7c31fd5a6bd265823 (diff) | |
download | chromium_src-0ec0805af79680611fbfbc5d0e825eb18039cf9d.zip chromium_src-0ec0805af79680611fbfbc5d0e825eb18039cf9d.tar.gz chromium_src-0ec0805af79680611fbfbc5d0e825eb18039cf9d.tar.bz2 |
Allow null begin frame sources in cc::Scheduler
This adds support to make it possible to set the begin frame source in
Scheduler back to null before setting it to something else again.
This is primarily to support the use case of losing an output surface
(which will provide the begin frame source) before asynchronously later
initializing another output surface (with potentially another source).
In this case, there will be some period of time where there is no valid
begin frame source. The scheduler owner could provide a fake one, but
I think that's more confusing than helpful.
Depends on https://codereview.chromium.org/1774323003
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel
Review URL: https://codereview.chromium.org/1781663004
Cr-Commit-Position: refs/heads/master@{#382016}
Diffstat (limited to 'cc')
-rw-r--r-- | cc/scheduler/scheduler.cc | 21 | ||||
-rw-r--r-- | cc/scheduler/scheduler.h | 2 | ||||
-rw-r--r-- | cc/scheduler/scheduler_unittest.cc | 51 | ||||
-rw-r--r-- | cc/test/scheduler_test_common.h | 4 |
4 files changed, 68 insertions, 10 deletions
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index 7dcf738..3fb8b3b 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc @@ -73,8 +73,7 @@ Scheduler::Scheduler( } Scheduler::~Scheduler() { - if (observing_begin_frame_source_) - begin_frame_source_->RemoveObserver(this); + SetBeginFrameSource(nullptr); } base::TimeTicks Scheduler::Now() const { @@ -115,12 +114,13 @@ void Scheduler::NotifyReadyToDraw() { } 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 (!begin_frame_source_) + return; if (observing_begin_frame_source_) begin_frame_source_->AddObserver(this); } @@ -245,14 +245,16 @@ void Scheduler::SetupNextBeginFrameIfNeeded() { if (state_machine_.BeginFrameNeeded()) { // Call AddObserver as soon as possible. observing_begin_frame_source_ = true; - begin_frame_source_->AddObserver(this); + if (begin_frame_source_) + begin_frame_source_->AddObserver(this); devtools_instrumentation::NeedsBeginFrameChanged(layer_tree_host_id_, true); } else if (state_machine_.begin_impl_frame_state() == SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) { // Call RemoveObserver in between frames only. observing_begin_frame_source_ = false; - begin_frame_source_->RemoveObserver(this); + if (begin_frame_source_) + begin_frame_source_->RemoveObserver(this); BeginImplFrameNotExpectedSoon(); devtools_instrumentation::NeedsBeginFrameChanged(layer_tree_host_id_, false); @@ -381,7 +383,8 @@ void Scheduler::BeginRetroFrame() { "expiration_time - now", (expiration_time - now).InMillisecondsF(), "BeginFrameArgs", begin_retro_frame_args_.front().AsValue()); begin_retro_frame_args_.pop_front(); - begin_frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); + if (begin_frame_source_) + begin_frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); } if (begin_retro_frame_args_.empty()) { @@ -474,7 +477,8 @@ void Scheduler::BeginImplFrameWithDeadline(const BeginFrameArgs& args) { can_activate_before_deadline)) { TRACE_EVENT_INSTANT0("cc", "SkipBeginImplFrameToReduceLatency", TRACE_EVENT_SCOPE_THREAD); - begin_frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); + if (begin_frame_source_) + begin_frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); return; } @@ -506,7 +510,8 @@ void Scheduler::FinishImplFrame() { ProcessScheduledActions(); client_->DidFinishImplFrame(); - begin_frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); + if (begin_frame_source_) + begin_frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); begin_impl_frame_tracker_.Finish(); } diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h index 21c9d04..6672de4 100644 --- a/cc/scheduler/scheduler.h +++ b/cc/scheduler/scheduler.h @@ -162,7 +162,7 @@ class CC_EXPORT Scheduler : public BeginFrameObserverBase { int layer_tree_host_id_; base::SingleThreadTaskRunner* task_runner_; - // Not owned. + // Not owned. May be null. BeginFrameSource* begin_frame_source_; bool observing_begin_frame_source_; diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index 1ca9b69..e0450c6 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc @@ -3169,6 +3169,57 @@ TEST_F(SchedulerTest, SwitchFrameSourceToThrottled) { EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1); } +TEST_F(SchedulerTest, SwitchFrameSourceToNullInsideDeadline) { + scheduler_settings_.use_external_begin_frame_source = true; + SetUpScheduler(true); + + scheduler_->SetNeedsRedraw(); + EXPECT_SINGLE_ACTION("AddObserver(this)", client_); + client_->Reset(); + + EXPECT_SCOPED(AdvanceFrame()); + EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); + client_->Reset(); + + // Switch to a null frame source. + scheduler_->SetBeginFrameSource(nullptr); + EXPECT_SINGLE_ACTION("RemoveObserver(this)", client_); + client_->Reset(); + + EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); + task_runner().RunPendingTasks(); // Run posted deadline. + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1); + EXPECT_FALSE(scheduler_->begin_frames_expected()); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + // AdvanceFrame helper can't be used here because there's no deadline posted. + scheduler_->SetNeedsRedraw(); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + EXPECT_NO_ACTION(client_); + client_->Reset(); + + scheduler_->SetNeedsBeginMainFrame(); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + EXPECT_NO_ACTION(client_); + client_->Reset(); + + // Switch back to the same source, make sure frames continue to be produced. + scheduler_->SetBeginFrameSource(fake_external_begin_frame_source_.get()); + EXPECT_SINGLE_ACTION("AddObserver(this)", client_); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + EXPECT_SCOPED(AdvanceFrame()); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2); + EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); + + task_runner().RunPendingTasks(); + 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) { diff --git a/cc/test/scheduler_test_common.h b/cc/test/scheduler_test_common.h index 414f31f..eac4983 100644 --- a/cc/test/scheduler_test_common.h +++ b/cc/test/scheduler_test_common.h @@ -238,7 +238,9 @@ class TestScheduler : public Scheduler { return state_machine_.main_thread_missed_last_deadline(); } - bool begin_frames_expected() const { return observing_begin_frame_source_; } + bool begin_frames_expected() const { + return begin_frame_source_ && observing_begin_frame_source_; + } ~TestScheduler() override; |