summaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authorenne <enne@chromium.org>2016-03-18 11:22:43 -0700
committerCommit bot <commit-bot@chromium.org>2016-03-18 18:24:17 +0000
commit0ec0805af79680611fbfbc5d0e825eb18039cf9d (patch)
tree42ec1ec9be29c82a7a3168813f9fa53c8c8f6dac /cc
parentc987fed5acb7cad3d489ebe7c31fd5a6bd265823 (diff)
downloadchromium_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.cc21
-rw-r--r--cc/scheduler/scheduler.h2
-rw-r--r--cc/scheduler/scheduler_unittest.cc51
-rw-r--r--cc/test/scheduler_test_common.h4
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;