Index: cc/scheduler/begin_frame_source.cc |
diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc |
index d05e2dfeb2fab0a12eb3dc1891356d2d97857608..37f70b248be5abfce4b9033e52a954aa08a0b609 100644 |
--- a/cc/scheduler/begin_frame_source.cc |
+++ b/cc/scheduler/begin_frame_source.cc |
@@ -233,6 +233,111 @@ void DelayBasedBeginFrameSource::OnTimerTick() { |
} |
} |
+// BeginFrameObserverAckTracker ------------------------------------------- |
+BeginFrameObserverAckTracker::BeginFrameObserverAckTracker() |
+ : current_source_id_(0), |
+ current_sequence_number_(BeginFrameArgs::kStartingFrameNumber), |
+ observers_had_damage_(false) {} |
+ |
+BeginFrameObserverAckTracker::~BeginFrameObserverAckTracker() {} |
+ |
+void BeginFrameObserverAckTracker::OnBeginFrame(const BeginFrameArgs& args) { |
+ if (current_source_id_ != args.source_id) |
+ SourceChanged(args); |
+ |
+ DCHECK_GE(args.sequence_number, current_sequence_number_); |
+ // Reset for new BeginFrame. |
+ current_sequence_number_ = args.sequence_number; |
+ finished_observers_.clear(); |
+ observers_had_damage_ = false; |
+} |
+ |
+void BeginFrameObserverAckTracker::OnObserverBeginFrame( |
+ BeginFrameObserver* obs, |
+ const BeginFrameArgs& args) { |
+ if (current_source_id_ != args.source_id) |
+ SourceChanged(args); |
+ |
+ DCHECK_EQ(args.sequence_number, current_sequence_number_); |
+ // Observer may choose to drop the BeginFrame. In this case, it has finished, |
+ // but is not considered up-to-date. |
+ if (obs->LastUsedBeginFrameArgs().sequence_number != current_sequence_number_) |
brianderson
2017/02/15 20:50:47
Why is this != instead of ==?
Eric Seckler
2017/02/17 19:10:01
This checks if the observer actually uses the Begi
brianderson
2017/02/17 20:49:54
Ah, I see. Instead of doing this, can we require O
Eric Seckler
2017/02/17 22:49:35
I think I'll make those changes and send out anoth
Eric Seckler
2017/02/21 12:10:57
Turns out it doesn't require much changes at this
|
+ finished_observers_.insert(obs); |
+} |
+ |
+void BeginFrameObserverAckTracker::SourceChanged(const BeginFrameArgs& args) { |
+ current_source_id_ = args.source_id; |
+ current_sequence_number_ = args.sequence_number; |
+ |
+ // Mark all observers invalid: We report an invalid frame until every observer |
+ // has confirmed the frame. |
+ for (auto& entry : latest_confirmed_sequence_numbers_) |
+ entry.second = BeginFrameArgs::kInvalidFrameNumber; |
+} |
+ |
+void BeginFrameObserverAckTracker::OnObserverFinishedFrame( |
+ BeginFrameObserver* obs, |
+ const BeginFrameAck& ack) { |
+ if (ack.source_id != current_source_id_) |
+ return; |
+ |
+ DCHECK_LE(ack.sequence_number, current_sequence_number_); |
+ if (ack.sequence_number != current_sequence_number_) |
+ return; |
+ |
+ finished_observers_.insert(obs); |
+ observers_had_damage_ |= ack.has_damage; |
+ |
+ // We max() with the current value in |latest_confirmed_sequence_numbers_| to |
+ // handle situations where an observer just started observing (again) and may |
+ // acknowledge with an ancient latest_confirmed_sequence_number. |
+ latest_confirmed_sequence_numbers_[obs] = |
+ std::max(ack.latest_confirmed_sequence_number, |
+ latest_confirmed_sequence_numbers_[obs]); |
+} |
+ |
+void BeginFrameObserverAckTracker::OnObserverAdded(BeginFrameObserver* obs) { |
+ observers_.insert(obs); |
+ |
+ // Since the observer didn't want BeginFrames before, we consider it |
+ // up-to-date up to the last BeginFrame, except if it already handled the |
+ // current BeginFrame. In which case, we consider it up-to-date up to the |
+ // current one. |
+ DCHECK_LT(BeginFrameArgs::kInvalidFrameNumber, current_sequence_number_); |
+ const BeginFrameArgs& last_args = obs->LastUsedBeginFrameArgs(); |
+ if (last_args.IsValid() && |
+ last_args.sequence_number == current_sequence_number_ && |
+ last_args.source_id == current_source_id_) { |
+ latest_confirmed_sequence_numbers_[obs] = current_sequence_number_; |
+ finished_observers_.insert(obs); |
+ } else { |
+ latest_confirmed_sequence_numbers_[obs] = current_sequence_number_ - 1; |
+ } |
+} |
+ |
+void BeginFrameObserverAckTracker::OnObserverRemoved(BeginFrameObserver* obs) { |
+ observers_.erase(obs); |
+ finished_observers_.erase(obs); |
+ latest_confirmed_sequence_numbers_.erase(obs); |
+} |
+ |
+bool BeginFrameObserverAckTracker::AllObserversFinishedFrame() const { |
+ return base::STLIncludes(finished_observers_, observers_); |
brianderson
2017/02/15 20:50:48
It looks like STLIncludes depends on std::includes
Eric Seckler
2017/02/17 19:10:01
Added the early out. I don't think we can guarante
|
+} |
+ |
+bool BeginFrameObserverAckTracker::AnyObserversHadDamage() const { |
+ return observers_had_damage_; |
+} |
+ |
+uint64_t BeginFrameObserverAckTracker::LatestConfirmedSequenceNumber() const { |
+ uint64_t latest_confirmed_sequence_number = current_sequence_number_; |
+ for (const auto& entry : latest_confirmed_sequence_numbers_) { |
+ latest_confirmed_sequence_number = |
+ std::min(latest_confirmed_sequence_number, entry.second); |
+ } |
+ return latest_confirmed_sequence_number; |
+} |
+ |
// ExternalBeginFrameSource ----------------------------------------------- |
ExternalBeginFrameSource::ExternalBeginFrameSource( |
ExternalBeginFrameSourceClient* client) |
@@ -248,6 +353,7 @@ void ExternalBeginFrameSource::AddObserver(BeginFrameObserver* obs) { |
bool observers_was_empty = observers_.empty(); |
observers_.insert(obs); |
+ ack_tracker_.OnObserverAdded(obs); |
obs->OnBeginFrameSourcePausedChanged(paused_); |
if (observers_was_empty) |
client_->OnNeedsBeginFrames(true); |
@@ -261,6 +367,7 @@ void ExternalBeginFrameSource::AddObserver(BeginFrameObserver* obs) { |
(missed_begin_frame_args_.sequence_number > |
last_args.sequence_number)); |
obs->OnBeginFrame(missed_begin_frame_args_); |
+ ack_tracker_.OnObserverBeginFrame(obs, missed_begin_frame_args_); |
} |
} |
} |
@@ -270,12 +377,20 @@ void ExternalBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) { |
DCHECK(observers_.find(obs) != observers_.end()); |
observers_.erase(obs); |
+ ack_tracker_.OnObserverRemoved(obs); |
+ MaybeFinishFrame(); |
if (observers_.empty()) { |
missed_begin_frame_args_ = BeginFrameArgs(); |
client_->OnNeedsBeginFrames(false); |
} |
} |
+void ExternalBeginFrameSource::DidFinishFrame(BeginFrameObserver* obs, |
+ const BeginFrameAck& ack) { |
+ ack_tracker_.OnObserverFinishedFrame(obs, ack); |
+ MaybeFinishFrame(); |
+} |
+ |
bool ExternalBeginFrameSource::IsThrottled() const { |
return true; |
} |
@@ -290,11 +405,35 @@ void ExternalBeginFrameSource::OnSetBeginFrameSourcePaused(bool paused) { |
} |
void ExternalBeginFrameSource::OnBeginFrame(const BeginFrameArgs& args) { |
+ if (frame_active_) |
+ FinishFrame(); |
+ |
+ frame_active_ = true; |
missed_begin_frame_args_ = args; |
missed_begin_frame_args_.type = BeginFrameArgs::MISSED; |
+ ack_tracker_.OnBeginFrame(args); |
std::unordered_set<BeginFrameObserver*> observers(observers_); |
- for (auto* obs : observers) |
+ for (auto* obs : observers) { |
obs->OnBeginFrame(args); |
+ ack_tracker_.OnObserverBeginFrame(obs, args); |
+ } |
+ MaybeFinishFrame(); |
+} |
+ |
+void ExternalBeginFrameSource::MaybeFinishFrame() { |
+ if (!frame_active_ || !ack_tracker_.AllObserversFinishedFrame()) |
+ return; |
+ FinishFrame(); |
+} |
+ |
+void ExternalBeginFrameSource::FinishFrame() { |
+ frame_active_ = false; |
+ |
+ BeginFrameAck ack(missed_begin_frame_args_.source_id, |
+ missed_begin_frame_args_.sequence_number, |
+ ack_tracker_.LatestConfirmedSequenceNumber(), 0, |
+ ack_tracker_.AnyObserversHadDamage()); |
+ client_->OnDidFinishFrame(ack); |
} |
} // namespace cc |