Index: cc/scheduler/begin_frame_source.cc |
diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc |
index 5c20a86caf2c4b11fd1fd54d48b74ca78a893cc7..2f56c890eb6aa7db8a29ee2a60ff9c95bd61ae4b 100644 |
--- a/cc/scheduler/begin_frame_source.cc |
+++ b/cc/scheduler/begin_frame_source.cc |
@@ -9,6 +9,7 @@ |
#include "base/auto_reset.h" |
#include "base/location.h" |
#include "base/logging.h" |
+#include "base/memory/ptr_util.h" |
#include "base/strings/string_number_conversions.h" |
#include "base/strings/stringprintf.h" |
#include "base/trace_event/trace_event.h" |
@@ -97,92 +98,37 @@ void BeginFrameSourceBase::SetBeginFrameSourcePaused(bool paused) { |
// BackToBackBeginFrameSource -------------------------------------------- |
BackToBackBeginFrameSource::BackToBackBeginFrameSource( |
base::SingleThreadTaskRunner* task_runner) |
- : BeginFrameSourceBase(), task_runner_(task_runner), weak_factory_(this) { |
- DCHECK(task_runner); |
+ : SyntheticBeginFrameSource( |
+ base::MakeUnique<DelayBasedTimeSource>(task_runner)) { |
+ SetUnthrottled(true); |
} |
-BackToBackBeginFrameSource::~BackToBackBeginFrameSource() { |
-} |
- |
-base::TimeTicks BackToBackBeginFrameSource::Now() { |
- return base::TimeTicks::Now(); |
-} |
- |
-// BeginFrameSourceBase support |
-void BackToBackBeginFrameSource::AddObserver(BeginFrameObserver* obs) { |
- BeginFrameSourceBase::AddObserver(obs); |
- pending_begin_frame_observers_.insert(obs); |
- PostPendingBeginFramesTask(); |
-} |
- |
-void BackToBackBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) { |
- BeginFrameSourceBase::RemoveObserver(obs); |
- pending_begin_frame_observers_.erase(obs); |
- if (pending_begin_frame_observers_.empty()) |
- begin_frame_task_.Cancel(); |
-} |
- |
-void BackToBackBeginFrameSource::DidFinishFrame(BeginFrameObserver* obs, |
- size_t remaining_frames) { |
- BeginFrameSourceBase::DidFinishFrame(obs, remaining_frames); |
- if (remaining_frames == 0 && observers_.find(obs) != observers_.end()) { |
- pending_begin_frame_observers_.insert(obs); |
- PostPendingBeginFramesTask(); |
- } |
-} |
- |
-void BackToBackBeginFrameSource::PostPendingBeginFramesTask() { |
- DCHECK(needs_begin_frames()); |
- DCHECK(!pending_begin_frame_observers_.empty()); |
- if (begin_frame_task_.IsCancelled()) { |
- begin_frame_task_.Reset( |
- base::Bind(&BackToBackBeginFrameSource::SendPendingBeginFrames, |
- weak_factory_.GetWeakPtr())); |
- task_runner_->PostTask(FROM_HERE, begin_frame_task_.callback()); |
- } |
-} |
- |
-void BackToBackBeginFrameSource::SendPendingBeginFrames() { |
- DCHECK(needs_begin_frames()); |
- DCHECK(!begin_frame_task_.IsCancelled()); |
- begin_frame_task_.Cancel(); |
- |
- base::TimeTicks now = Now(); |
- BeginFrameArgs args = BeginFrameArgs::Create( |
- BEGINFRAME_FROM_HERE, now, now + BeginFrameArgs::DefaultInterval(), |
- BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL); |
- |
- std::set<BeginFrameObserver*> pending_observers; |
- pending_observers.swap(pending_begin_frame_observers_); |
- for (BeginFrameObserver* obs : pending_observers) |
- obs->OnBeginFrame(args); |
-} |
+BackToBackBeginFrameSource::~BackToBackBeginFrameSource() = default; |
// SyntheticBeginFrameSource --------------------------------------------- |
SyntheticBeginFrameSource::SyntheticBeginFrameSource( |
- base::SingleThreadTaskRunner* task_runner, |
- base::TimeDelta initial_vsync_interval) |
- : time_source_( |
- DelayBasedTimeSource::Create(initial_vsync_interval, task_runner)) { |
- time_source_->SetClient(this); |
-} |
- |
-SyntheticBeginFrameSource::SyntheticBeginFrameSource( |
std::unique_ptr<DelayBasedTimeSource> time_source) |
- : time_source_(std::move(time_source)) { |
+ : time_source_(std::move(time_source)), |
+ last_interval_(time_source_->Interval()) { |
time_source_->SetClient(this); |
} |
-SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {} |
+SyntheticBeginFrameSource::~SyntheticBeginFrameSource() = default; |
void SyntheticBeginFrameSource::OnUpdateVSyncParameters( |
base::TimeTicks timebase, |
base::TimeDelta interval) { |
- if (!authoritative_interval_.is_zero()) |
+ if (!authoritative_interval_.is_zero()) { |
interval = authoritative_interval_; |
+ } else if (interval.is_zero()) { |
+ // TODO(brianderson): We should not be receiving 0 intervals. |
enne (OOO)
2016/06/14 21:25:17
I love how this comment has proliferated.
brianderson
2016/06/14 21:59:48
I have so many fewer TODO's now! =)
|
+ interval = BeginFrameArgs::DefaultInterval(); |
+ } |
last_timebase_ = timebase; |
- time_source_->SetTimebaseAndInterval(timebase, interval); |
+ last_interval_ = interval; |
+ if (!unthrottled_) |
+ time_source_->SetTimebaseAndInterval(timebase, interval); |
} |
void SyntheticBeginFrameSource::SetAuthoritativeVSyncInterval( |
@@ -191,20 +137,44 @@ void SyntheticBeginFrameSource::SetAuthoritativeVSyncInterval( |
OnUpdateVSyncParameters(last_timebase_, interval); |
} |
+void SyntheticBeginFrameSource::SetUnthrottled(bool unthrottled) { |
+ if (unthrottled) |
+ time_source_->SetTimebaseAndInterval(base::TimeTicks(), base::TimeDelta()); |
+ else |
+ time_source_->SetTimebaseAndInterval(last_timebase_, last_interval_); |
+ unthrottled_ = unthrottled; |
+} |
+ |
BeginFrameArgs SyntheticBeginFrameSource::CreateBeginFrameArgs( |
base::TimeTicks frame_time, |
BeginFrameArgs::BeginFrameArgsType type) { |
+ if (unthrottled_) { |
+ // When unthrottled, the NextTickTime is not meaningful, so just use the |
+ // current interval as the deadline. |
+ return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, |
+ frame_time + last_interval_, last_interval_, |
+ type); |
+ } |
return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, |
- time_source_->NextTickTime(), |
- time_source_->Interval(), type); |
+ time_source_->NextTickTime(), last_interval_, |
+ type); |
} |
// BeginFrameSource support |
void SyntheticBeginFrameSource::AddObserver(BeginFrameObserver* obs) { |
BeginFrameSourceBase::AddObserver(obs); |
+ |
+ if (unthrottled_) { |
+ // When unthrottled, ensure the time source is ticking for the first frame |
+ // this observer sees (since it only ticks when an observer is ready), and |
+ // don't post a MISSED frame since unthrottled just goes as fast as it can. |
+ time_source_->SetActive(true); |
+ frame_finished_observers_.insert(obs); |
+ return; |
+ } |
+ |
BeginFrameArgs args = CreateBeginFrameArgs( |
- time_source_->NextTickTime() - time_source_->Interval(), |
- BeginFrameArgs::MISSED); |
+ time_source_->NextTickTime() - last_interval_, BeginFrameArgs::MISSED); |
BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs(); |
if (!last_args.IsValid() || |
(args.frame_time > |
@@ -213,23 +183,55 @@ void SyntheticBeginFrameSource::AddObserver(BeginFrameObserver* obs) { |
} |
} |
+void SyntheticBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) { |
+ BeginFrameSourceBase::RemoveObserver(obs); |
+ frame_finished_observers_.erase(obs); |
+} |
+ |
void SyntheticBeginFrameSource::OnNeedsBeginFramesChanged( |
bool needs_begin_frames) { |
time_source_->SetActive(needs_begin_frames); |
} |
+void SyntheticBeginFrameSource::DidFinishFrame(BeginFrameObserver* obs, |
+ size_t remaining_frames) { |
+ if (remaining_frames == 0 && observers_.find(obs) != observers_.end()) { |
+ frame_finished_observers_.insert(obs); |
+ time_source_->SetActive(true); |
+ } |
+} |
+ |
// DelayBasedTimeSourceClient support |
void SyntheticBeginFrameSource::OnTimerTick() { |
- BeginFrameArgs args = CreateBeginFrameArgs(time_source_->LastTickTime(), |
- BeginFrameArgs::NORMAL); |
+ // This must be captured before calling SetActive(false) on the time_source_. |
+ base::TimeTicks now = time_source_->LastTickTime(); |
+ |
+ if (unthrottled_) { |
+ // When unthrottled, we only want to tick when an observer finishes a frame, |
+ // so stop and wait for that. |
+ time_source_->SetActive(false); |
+ } |
+ |
+ BeginFrameArgs args = CreateBeginFrameArgs(now, BeginFrameArgs::NORMAL); |
std::set<BeginFrameObserver*> observers(observers_); |
- for (auto& it : observers) { |
- BeginFrameArgs last_args = it->LastUsedBeginFrameArgs(); |
- if (!last_args.IsValid() || |
- (args.frame_time > |
- last_args.frame_time + args.interval / kDoubleTickDivisor)) { |
- it->OnBeginFrame(args); |
+ for (auto& obs : observers) { |
+ bool on_begin_frame = false; |
+ if (unthrottled_) { |
+ // When unthrottled, we only want to generate a new begin frame for each |
+ // observer when its previous one finished. |
+ on_begin_frame = frame_finished_observers_.count(obs) > 0; |
+ } else { |
+ // When ticking at a throttled rate we want to generate a new begin frame |
+ // regularly, but not too often. |
+ BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs(); |
+ on_begin_frame = |
+ !last_args.IsValid() || |
+ (args.frame_time > |
+ last_args.frame_time + args.interval / kDoubleTickDivisor); |
} |
+ frame_finished_observers_.erase(obs); |
+ if (on_begin_frame) |
+ obs->OnBeginFrame(args); |
} |
} |